ExpressionVisitor.java

package dev.civl.mc.library.civlc;

import dev.civl.sarl.IF.SymbolicUniverse;
import dev.civl.sarl.IF.expr.SymbolicExpression;
import dev.civl.sarl.IF.object.SymbolicObject;
import dev.civl.sarl.IF.object.SymbolicObject.SymbolicObjectKind;

/**
 * This class visits all child expressions of the given expression in a
 * Depth-first order. For each visited expression e,
 * {@link StatelessSimplificationAction} will be performed before and after e's
 * children being visited.
 * 
 * @author ziqing
 *
 */
abstract class ExpressionVisitor {
	/**
	 * A reference to a {@link SymbolicUniverse}.
	 */
	protected SymbolicUniverse universe;

	/**
	 * The action that can be performed on the expression when it is visited by
	 * the {@link ExpressionVisitor}. Two kinds of actions can be implemented:
	 * <code>pre:</code> the action should be performed before the children of
	 * the expression being visited and <code>post:</code> the action should be
	 * performed after the children of the expression being visited.
	 * 
	 * @author ziqing
	 *
	 */
	interface StatelessSimplificationAction {
		/**
		 * the action should be performed before the children of the expression
		 * being visited
		 * 
		 * @param expr
		 * @return
		 */
		SymbolicExpression pre(SymbolicExpression expr);

		/**
		 * the action should be performed after the children of the expression
		 * being visited
		 * 
		 * @param expr
		 * @return
		 */
		SymbolicExpression post(SymbolicExpression expr);
	}

	ExpressionVisitor(SymbolicUniverse universe) {
		this.universe = universe;
	}

	/**
	 * Visit the expression in a Depth-first order and performing
	 * {@link StatelessSimplificationAction}s on them.
	 * 
	 * @param expr
	 * @param action
	 * @return
	 */
	abstract SymbolicExpression visitExpression(SymbolicExpression expr);

	public SymbolicExpression visitExpressionChildren(SymbolicExpression expr) {
		boolean changed = false;
		int numArgs = expr.numArguments();
		SymbolicObject newArgs[] = new SymbolicObject[numArgs];

		for (int i = 0; i < numArgs; i++) {
			SymbolicObject arg = expr.argument(i);

			if (arg.symbolicObjectKind() == SymbolicObjectKind.EXPRESSION) {
				newArgs[i] = visitExpression((SymbolicExpression) arg);
				if (newArgs[i] != arg)
					changed = true;
			} else
				newArgs[i] = arg;
		}
		if (changed)
			return universe.make(expr.operator(), expr.type(), newArgs);
		else
			return expr;
	}
}