package bigstep.rules;
import bigstep.BigStepProofContext;
import bigstep.BigStepProofNode;
import bigstep.BigStepProofRule;
import common.ProofRuleException;
import common.interpreters.MutableStore;
import expressions.Application;
import expressions.BinaryOperator;
import expressions.BinaryOperatorException;
import expressions.Expression;
import expressions.InfixOperation;
import expressions.UnaryOperatorException;
/**
* Abstract base class for big step rules that can be applied to
* binary operators, both in {@link expressions.Application}s and
* {@link expressions.InfixOperation}s.
*
* @author Benedikt Meurer
* @version $Id$
*
* @see bigstep.rules.AbstractUnaryOperatorRule
*/
abstract class AbstractBinaryOperatorRule extends BigStepProofRule {
//
// Constructor (protected)
//
/**
* Allocates a new <code>AbstractBinaryOperatorRule</code> with
* the specified <code>name</code>.
*
* @param name the name of the rule.
*/
protected AbstractBinaryOperatorRule(String name) {
super(true, name);
}
//
// Primitives
//
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofRule#apply(bigstep.BigStepProofContext, bigstep.BigStepProofNode)
*/
@Override
public final void apply(BigStepProofContext context, BigStepProofNode node) throws ProofRuleException, ClassCastException {
try {
// depends on whether we have an Application or InfixOperation
BinaryOperator op;
Expression e1;
Expression e2;
// check if Application or InfixOperation
Expression e = node.getExpression();
if (e instanceof Application) {
// Application: (op e1) e2
Application a1 = (Application)e;
Application a2 = (Application)a1.getE1();
op = (BinaryOperator)a2.getE1();
e1 = a2.getE2();
e2 = a1.getE2();
}
else {
// otherwise must be an InfixOperation
InfixOperation infixOperation = (InfixOperation)e;
op = infixOperation.getOp();
e1 = infixOperation.getE1();
e2 = infixOperation.getE2();
}
// verify that op, e1 and e2 are values
if (!op.isValue() || !e1.isValue() || !e2.isValue()) {
throw new ProofRuleException(node, this);
}
// allocate a new store and perform the application
MutableStore store = new MutableStore(node.getStore());
Expression value = applyTo(store, op, e1, e2);
context.setProofNodeResult(node, value, store);
}
catch (BinaryOperatorException e) {
throw new ProofRuleException(node, this, e);
}
}
/**
* This method must be implemented by derived classes to handle the actual application of
* the operator <code>op</code> to the expressions <code>e1</code> and <code>e2</code>,
* which are generated to be values.
*
* Memory operators may modify the <code>store</code> as needed.
*
* @param store the {@link MutableStore} required for memory operators like <code>:=</code>.
* @param op the binary operator to apply to <code>e1</code> and <code>e2</code>.
* @param e1 the first operand, which is garantied to be a value.
* @param e2 the second operand, which is garantied to be a value.
*
* @return the resulting value of the operator application.
*
* @throws ClassCastException if either <code>e1</code> or <code>e2</code> is invalid
* for the operator.
* @throws UnaryOperatorException if the operator <code>op</code> cannot be applied to
* <code>e1</code> and <code>e2</code>.
*/
public abstract Expression applyTo(MutableStore store, BinaryOperator op, Expression e1, Expression e2) throws ClassCastException, BinaryOperatorException;
}