Evaluator.java
package visitor;
import calculator.Expression;
import calculator.operations.Operation;
import calculator.atoms.*;
import calculator.atoms.visitor.AtomCaster;
import calculator.atoms.visitor.AtomComparator;
import calculator.functions.BinaryFunction;
import calculator.functions.UnaryFunction;
import java.util.ArrayList;
/**
* Evaluation is a concrete visitor that serves to
* compute and evaluate the results of arithmetic expressions.
*/
public class Evaluator extends Visitor {
/**
* Default constructor of the class. Does not initialise anything.
*/
public Evaluator() {
}
/** The result of the evaluation will be stored in this private variable */
private Atom computedValue;
/**
* getter method to obtain the result of the evaluation
*
* @return an Integer object containing the result of the evaluation
*/
public Atom getResult() {
return computedValue;
}
/**
* Use the visitor design pattern to visit a Real.
*
* @param r The Real being visited
*/
public void visit(Real r) {
computedValue = r;
}
public void visit(IntegerAtom i) {
computedValue = i;
}
@Override
public void visit(Complex c) {
computedValue = c;
}
@Override
public void visit(Rationnal q) {
computedValue = q;
}
/**
* Use the visitor design pattern to visit an operation
*
* @param o The operation being visited
*/
public void visit(Operation o) {
ArrayList<Atom> evaluatedArgs = new ArrayList<>();
// first loop to recursively evaluate each subexpression
for (Expression a : o.args) {
a.accept(this);
evaluatedArgs.add(computedValue);
}
// second loop to accumulate all the evaluated subresults
Atom result = evaluatedArgs.get(0);
int max = evaluatedArgs.size();
for (int counter = 1; counter < max; counter++) {
Atom other = evaluatedArgs.get(counter);
// here compare the atoms to get the type to cast to
AtomComparator atomComp = new AtomComparator();
result.accept(atomComp);
other.accept(atomComp);
// cast both the operand to the Atom Type to cast to
AtomCaster atomCaster = new AtomCaster(atomComp.getResult());
result.accept(atomCaster);
result = atomCaster.getResult();
other.accept(atomCaster);
other = atomCaster.getResult();
// apply the operation between the now casted Atoms
result = result.apply(o, other);
}
// store the accumulated result
computedValue = result;
}
@Override
public void visit(UnaryFunction o) {
o.getArg().accept(this);
computedValue = computedValue.apply(o);
}
@Override
public void visit(BinaryFunction f) {
f.getFirstArg().accept(this);
Atom firstValue = computedValue;
f.getSecondArg().accept(this);
Atom secondValue = computedValue;
// Cast both operands to a compatible atom type before applying the function.
AtomComparator atomComp = new AtomComparator();
firstValue.accept(atomComp);
secondValue.accept(atomComp);
AtomCaster atomCaster = new AtomCaster(atomComp.getResult());
firstValue.accept(atomCaster);
firstValue = atomCaster.getResult();
secondValue.accept(atomCaster);
secondValue = atomCaster.getResult();
computedValue = firstValue.apply(f, secondValue);
}
}