EvaluatorBuilder.java

package org.microspace.evaluator;

import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.microspace.evaluator.EvaluatorParser.ExpressionContext;
import org.microspace.evaluator.EvaluatorParser.Expression_atomContext;
import org.microspace.evaluator.EvaluatorParser.Expression_listContext;
import org.microspace.evaluator.EvaluatorParser.Expression_plus_minusContext;
import org.microspace.evaluator.EvaluatorParser.Expression_times_slashContext;
import org.microspace.evaluator.EvaluatorParser.Number_literalContext;
import org.microspace.evaluator.EvaluatorParser.Plus_minusContext;
import org.microspace.evaluator.EvaluatorParser.Times_slashContext;

/**
 * Build an Evaluator.
 * 
 * @author Gaspar Sinai - {@literal gaspar.sinai@microspace.org}
 * @version 2017-10-16
 */
public class EvaluatorBuilder implements EvaluatorListener {
	
	Stack <Expression> expressionStack = new Stack<>();
	
	final Evaluator evaluator;
	
	public EvaluatorBuilder (String expression) {
		EvaluatorLexer lexer = new EvaluatorLexer(CharStreams.fromString(expression));
		CommonTokenStream tokens = new CommonTokenStream(lexer);
		EvaluatorParser parser = new EvaluatorParser(tokens);
		parser.setErrorHandler(new BailErrorStrategy());
		ParseTree tree;
		try {
			tree = parser.expression();
		} catch (ParseCancellationException ex) {
			throw new IllegalArgumentException ("Syntax Error", ex);
		}
		ParseTreeWalker walker = new ParseTreeWalker();
		walker.walk(this, tree);
		evaluator = new Evaluator (expressionStack.peek());
	}
	
	public Evaluator getEvaluator() {
		return evaluator;
	}

	@Override
	public void visitTerminal(TerminalNode node) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visitErrorNode(ErrorNode node) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void enterEveryRule(ParserRuleContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitEveryRule(ParserRuleContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void enterNumber_literal(Number_literalContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitNumber_literal(Number_literalContext ctx) {
		expressionStack.push (new ExpressionLiteral(new BigDecimal(ctx.getText())));
	}


	@Override
	public void enterExpression_atom(Expression_atomContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitExpression_atom(Expression_atomContext ctx) {
		if (ctx.VARIABLE() != null) {
			expressionStack.push (new ExpressionVariable(ctx.getText()));
		}
	}

	@Override
	public void enterExpression_list(Expression_listContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitExpression_list(Expression_listContext ctx) {
		expressionStack.peek ().setNeedsBracket(true);
	}

	@Override
	public void enterExpression(ExpressionContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitExpression(ExpressionContext ctx) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see org.microspace.evaluator.EvaluatorListener#enterTimes_slash(org.microspace.evaluator.EvaluatorParser.Times_slashContext)
	 */
	@Override
	public void enterTimes_slash(Times_slashContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitTimes_slash(Times_slashContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void enterPlus_minus(Plus_minusContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitPlus_minus(Plus_minusContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void enterExpression_plus_minus(Expression_plus_minusContext ctx) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void exitExpression_plus_minus(Expression_plus_minusContext ctx) {
		Stack <Expression> reverseStack = new Stack<>();
		List<ExpressionAtom.Operator> plusMinusOperatorLR = new LinkedList<> ();
		for (int i=0; i< ctx.plus_minus().size(); i++) {
			reverseStack.push(expressionStack.pop());
			if (ctx.plus_minus().get(i).PLUS() != null) {
				plusMinusOperatorLR.add(ExpressionAtom.Operator.PLUS);
			} else if (ctx.plus_minus().get(i).MINUS() != null){
				plusMinusOperatorLR.add(ExpressionAtom.Operator.MINUS);
			}

		}
		while (reverseStack.size() > 0) {
			Expression exp1 = expressionStack.pop();
			Expression exp2 = reverseStack.pop();
			Expression expAtom = new ExpressionAtom(exp1, plusMinusOperatorLR.remove(0), exp2);
			expressionStack.push (expAtom);
		}		
		
	}

	/* (non-Javadoc)
	 * @see org.microspace.evaluator.EvaluatorListener#enterExpression_times_slash(org.microspace.evaluator.EvaluatorParser.Expression_times_slashContext)
	 */
	@Override
	public void enterExpression_times_slash(Expression_times_slashContext ctx) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see org.microspace.evaluator.EvaluatorListener#exitExpression_times_slash(org.microspace.evaluator.EvaluatorParser.Expression_times_slashContext)
	 */
	@Override
	public void exitExpression_times_slash(Expression_times_slashContext ctx) {
		// TODO Auto-generated method stub
		Stack <Expression> reverseStack = new Stack<>();
		List<ExpressionAtom.Operator> timesSlashOperatorLR = new LinkedList<> ();
		for (int i=0; i< ctx.times_slash().size(); i++) {
			reverseStack.push(expressionStack.pop());
			if (ctx.times_slash().get(i).TIMES() != null) {
				timesSlashOperatorLR.add(ExpressionAtom.Operator.TIMES);
			} else if (ctx.times_slash().get(i).SLASH() != null){
				timesSlashOperatorLR.add(ExpressionAtom.Operator.SLASH);
			}

		}
		while (reverseStack.size() > 0) {
			Expression exp1 = expressionStack.pop();
			Expression exp2 = reverseStack.pop();
			Expression expAtom = new ExpressionAtom(exp1, timesSlashOperatorLR.remove(0), exp2);
			expressionStack.push (expAtom);
		}		
	}


}