Calculator.java

package calculator;

import calculator.atoms.Atom;
import visitor.Counter;
import visitor.Evaluator;
import visitor.Printer;

/**
 * This class represents the core logic of a Calculator.
 * It can be used to print and evaluate artihmetic expressions.
 *
 * @author tommens
 */
public class Calculator {

	/**
	 * Default constructor of the class.
	 * Does nothing since the class does not have any variables that need to be
	 * initialised.
	 */
	public Calculator() {
	}

	/*
	 * For the moment the calculator only contains a print method and an eval method
	 * It would be useful to complete this with a read method, so that we would be
	 * able
	 * to implement a full REPL cycle (Read-Eval-Print loop) such as in Scheme,
	 * Python, R and other languages.
	 * To do so would require to implement a method with the following signature,
	 * converting an input string
	 * into an arithmetic expression:
	 * public Expression read(String s)
	 */

	/**
	 * Prints an arithmetic expression provided as input parameter.
	 * 
	 * @param e the arithmetic Expression to be printed
	 * @see #printExpressionDetails(Expression)
	 */
	public void print(Expression e) {
		System.out.println("The result of evaluating expression " + format(e, Notation.INFIX));
		System.out.println("is: " + format(eval(e), Notation.INFIX) + ".");
		System.out.println();
	}

	/**
	 * Prints verbose details of an arithmetic expression provided as input
	 * parameter.
	 * 
	 * @param e the arithmetic Expression to be printed
	 * @see #print(Expression)
	 */
	public void printExpressionDetails(Expression e) {
		print(e);
		Counter c = new Counter();
		e.accept(c);
		System.out.print("It contains " + c.getDepth() + " levels of nested expressions, ");
		System.out.print(c.getNbOps() + " operations");
		System.out.println(" and " + c.getNbNbs() + " numbers.");
		System.out.println();
	}

	/**
	 * Evaluates an arithmetic expression and returns its result
	 * 
	 * @param e the arithmetic Expression to be evaluated
	 * @return The result of the evaluation
	 */
	public Atom eval(Expression e) {
		// create a new visitor to evaluate expressions
		Evaluator v = new Evaluator();
		// and ask the expression to accept this visitor to start the evaluation process
		e.accept(v);
		// and return the result of the evaluation at the end of the process
		return v.getResult();
	}

	/**
	 * Formats an arithmetic expression in a given notation
	 * 
	 * @param e        the arithmetic Expression to be formatted
	 * @param notation the notation to be used for formatting
	 * @return The formatted expression as a String
	 */
	public String format(Expression e, Notation notation) {
		Printer p = new Printer(notation);
		e.accept(p);
		return p.getResult();
	}

	/*
	 * We could also have other methods, e.g. to verify whether an expression is
	 * syntactically correct
	 * public Boolean validate(Expression e)
	 * or to simplify some expression
	 * public Expression simplify(Expression e)
	 */
}