1 package calculator.operations;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import calculator.Expression;
7 import calculator.IllegalConstruction;
8 import calculator.Notation;
9 import calculator.atoms.Atom;
10 import calculator.atoms.Complex;
11 import calculator.atoms.IntegerAtom;
12 import calculator.atoms.Rationnal;
13 import calculator.atoms.Real;
14 import visitor.Printer;
15 import visitor.Visitor;
16
17 /**
18 * Operation is an abstract class that represents arithmetic operations,
19 * which are a special kind of Expressions, just like numbers are.
20 *
21 * @see Expression
22 * @see Atom
23 */
24 public abstract class Operation implements Expression {
25 /**
26 * The list of expressions passed as an argument to the arithmetic operation
27 */
28 public List<Expression> args;
29
30 /**
31 * The character used to represent the arithmetic operation (e.g. "+", "*")
32 */
33 protected String symbol;
34
35 /**
36 * The neutral element of the operation (e.g. 1 for *, 0 for +)
37 */
38 protected int neutral;
39
40 /**
41 * To construct an operation with a list of expressions as arguments,
42 * as well as the Notation used to represent the operation.
43 *
44 * @param elist The list of expressions passed as argument to the arithmetic
45 * operation
46 * @throws IllegalConstruction Exception thrown if a null list of expressions is
47 * passed as argument
48 */
49 protected /* constructor */ Operation(List<Expression> elist)
50 throws IllegalConstruction {
51 if (elist == null) {
52 throw new IllegalConstruction();
53 } else {
54 args = new ArrayList<>(elist);
55 }
56 }
57
58 /**
59 * getter method to return the number of arguments of an arithmetic operation.
60 *
61 * @return The number of arguments of the arithmetic operation.
62 */
63 public List<Expression> getArgs() {
64 return args;
65 }
66
67 /**
68 * getter method to return the symbol of the arithmetic operation.
69 *
70 * @return The symbol of the arithmetic operation (e.g. "+", "-", "*", "/").
71 */
72 public String getSymbol() {
73 return symbol;
74 }
75
76 /**
77 * Abstract method representing the actual binary arithmetic operation to
78 * compute on Reals
79 *
80 * @param r1 first Real of the binary operation
81 * @param r2 second Real of the binary operation
82 * @return result of computing the binary operation
83 */
84 public abstract Real op(Real r1, Real r2);
85
86 /**
87 * Abstract method representing the actual binary arithmetic operation to
88 * compute on Complexes
89 *
90 * @param c1 first Complex of the binary operation
91 * @param c2 second Complex of the binary operation
92 * @return result of computing the binary operation
93 */
94 public abstract Complex op(Complex c1, Complex c2);
95
96 /**
97 * Abstract method representing the actual binary arithmetic operation to
98 * compute on Integer
99 *
100 * @param i1 first Integer of the binary operation
101 * @param i2 second Integer of the binary operation
102 * @return result of computing the binary operation
103 */
104 public abstract Atom op(IntegerAtom i1, IntegerAtom i2);
105
106 /**
107 * Abstract method representing the actual binary arithmetic operation to
108 * compute on Rationnals
109 *
110 * @param q1 first Rationnal of the binary operation
111 * @param q2 second Rationnal of the binary operation
112 * @return result of computing the binary operation
113 */
114 public abstract Atom op(Rationnal q1, Rationnal q2);
115
116 /**
117 * Add more parameters to the existing list of parameters
118 *
119 * @param params The list of parameters to be added
120 */
121 public void addMoreParams(List<Expression> params) {
122 args.addAll(params);
123 }
124
125 /**
126 * Accept method to implement the visitor design pattern to traverse arithmetic
127 * expressions.
128 * Each operation will delegate the visitor to each of its arguments
129 * expressions,
130 * and will then pass itself to the visitor object to get processed by the
131 * visitor object.
132 *
133 * @param v The visitor object
134 */
135 public void accept(Visitor v) {
136 v.visit(this);
137 }
138
139 /**
140 * Convert the arithmetic operation into a String to allow it to be printed,
141 * using the default printer
142 *
143 * @return The String that is the result of the conversion.
144 */
145 @Override
146 public final String toString() {
147 Printer p = new Printer();
148 this.accept(p);
149 return p.getResult();
150 }
151
152 /**
153 * Appeal to the visitor to convert the arithmetic operation into a String to
154 * allow it to be printed,
155 * using the notation n (prefix, infix or postfix) that is specified as a
156 * parameter.
157 *
158 * @param n The notation to be used for representing the operation (prefix,
159 * infix or postfix)
160 * @return The String that is the result of the conversion.
161 */
162 public final String toString(Notation n) {
163 Printer p = new Printer(n);
164 this.accept(p);
165 return p.getResult();
166 }
167
168 /**
169 * Two operation objects are equal if their list of arguments is equal and they
170 * correspond to the same operation.
171 *
172 * @param o The object to compare with
173 * @return The result of the equality comparison
174 */
175 @Override
176 public boolean equals(Object o) {
177 if (o == null)
178 return false; // No object should be equal to null
179
180 if (this == o)
181 return true; // If it's the same object, they're obviously equal
182
183 if (getClass() != o.getClass())
184 return false; // getClass() instead of instanceof() because an addition is not the same as a
185 // multiplication
186
187 Operation other = (Operation) o;
188 return this.args.equals(other.getArgs());
189 }
190
191 /**
192 * The method hashCode needs to be overridden it the equals method is
193 * overridden;
194 * otherwise there may be problems when you use your object in hashed
195 * collections
196 * such as HashMap, HashSet, LinkedHashSet.
197 *
198 * @return The result of computing the hash.
199 */
200 @Override
201 public int hashCode() {
202 int result = 5;
203 int prime = 31;
204 result = prime * result + neutral;
205 result = prime * result + symbol.hashCode();
206 result = prime * result + args.hashCode();
207 return result;
208 }
209
210 }