package ai.domain.expressions;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.VariableDeclaration;
import ai.common.FatalAIError;
import ai.domain.DomainIntf;
import ai.domain.Variable;
import ai.domain.intervals.eval.EvaluationUtils;
public abstract class ExpressionEvaluatorBase<DI extends DomainIntf<DI>, PS> implements ExpressionEvaluatorIntf<DI> {
protected abstract class ExpressionVisitorBase extends AbstractExpressionVisitor {
public PS result;
protected ExpressionVisitorBase(PS input) {
this.result = input;
}
protected final void ensureCorrectTypeOrBoxing(Expression expr) {
if (!EvaluationUtils.isIntegerType(expr) && !EvaluationUtils.isIntegerTypeBoxing(expr))
throw getException("I shouldn't be here? '%s'", expr);
}
protected final void ensureIntegerType(Expression expr) {
if (!EvaluationUtils.isIntegerType(expr))
throw getException("I shouldn't be here? '%s'", expr);
}
//
// protected final void ensureCorrectType(Expression expr) {
// if (!isInterestingType(expr))
// throw getException("I shouldn't be here? '%s'", expr);
// }
protected abstract void beforeVisitChild();
// result = result.setLeft(null);
protected final void acceptChildNoTypeCheck(Expression child) {
beforeVisitChild();
child.accept(this);
verifyResult(result, child);
}
protected abstract void processFloatExpression(Expression expr);
protected final void acceptChild(Expression child) {
if (EvaluationUtils.isFloatType(child)) {
processFloatExpression(child);
return;
}
ensureCorrectTypeOrBoxing(child);
acceptChildNoTypeCheck(child);
}
protected final RuntimeException unhandledNodeException(Expression node) {
return getException("Unhandled node '%s(%s)'", node.getClass(), node);
}
protected void setNewResult(Expression expr, PS newResult) {
verifyResult(newResult, expr);
result = newResult;
}
}
protected abstract boolean isInterestingType(Expression expr);
protected abstract boolean isInterestingType(VariableDeclaration variableDeclaration);
protected abstract PS processNewVariable(PS input, Variable var, boolean isArgument);
protected abstract RuntimeException getException(String message, Object... args);
protected abstract ExpressionVisitorBase getEvaluator(PS input);
protected abstract PS constructEvaluationStateFromDomain(DI input);
public abstract DI constructDomainFromEvaluationState(PS input);
protected abstract void verifyResult(PS result, Expression expr);
public PS evaluateExpression(Expression expr, PS input) {
ExpressionVisitorBase eval = getEvaluator(input);
expr.accept(eval);
PS result = eval.result;
verifyResult(result, expr);
// Pair<T, DI> result = eval.result;
// if (result == null)
// throw getException("NO RESULT!! '%s'", expr);
// if (result.left == null)
// throw getException("NO RESULT!! '%s'", expr);
// if (result.right == null)
// throw getException("NO RESULT!! '%s'", expr);
return result;
}
@Override
public final DI evaluate(Expression expr, DI input) {
if (!isInterestingType(expr))
return null;
PS result = evaluateExpression(expr, constructEvaluationStateFromDomain(input));
return constructDomainFromEvaluationState(result);
}
@Override
public final DI evaluate(SimpleName name, Expression initializerOrNull, DI input,
boolean asAssignment) {
if (!isInterestingType(name))
return null;
PS result = constructEvaluationStateFromDomain(input);
if (initializerOrNull != null)
result = evaluateExpression(initializerOrNull, result);
Variable variable = EvaluationUtils.tryGetVariable(name);
if (variable == null)
throw new FatalAIError("Cannot resolve type variable: '%s'", name);
if (!asAssignment || initializerOrNull == null)
result = processNewVariable(result, variable, asAssignment);
else
result = processVariableAssignment(result, name);
return constructDomainFromEvaluationState(result);
}
@Override
public final DI evaluateNewArgument(SimpleName argument, DI input) {
if (!isInterestingType(argument))
return null;
Variable variable = EvaluationUtils.tryGetVariable(argument);
if (variable == null)
throw new FatalAIError("Cannot resolve type variable: '%s'", argument);
PS result = constructEvaluationStateFromDomain(input);
result = processNewVariable(result, variable, true);
return constructDomainFromEvaluationState(result);
}
public abstract PS processVariableAssignment(PS input, Expression toWhat);
}