package bigstep.rules; import common.ProofRuleException; import expressions.Application; import expressions.CurriedLet; import expressions.CurriedLetRec; import expressions.Expression; import expressions.Lambda; import expressions.Let; import expressions.LetRec; import expressions.MultiLet; import expressions.Projection; import expressions.Recursion; import bigstep.BigStepProofContext; import bigstep.BigStepProofNode; import bigstep.BigStepProofRule; /** * This class represents the big step rule <b>(LET)</b>. * * @author Benedikt Meurer * @version $Id$ */ public final class LetRule extends BigStepProofRule { // // Constructor // /** * Allocates a new <code>LetRule</code> instance. */ public LetRule() { super(false, "LET"); } // // Primitives // /** * {@inheritDoc} * * @see bigstep.BigStepProofRule#apply(bigstep.BigStepProofContext, bigstep.BigStepProofNode) */ @Override public void apply(BigStepProofContext context, BigStepProofNode node) throws ProofRuleException, ClassCastException { Expression e = node.getExpression(); if (e instanceof CurriedLet || e instanceof CurriedLetRec) { // determine the first sub expression CurriedLet curriedLet = (CurriedLet)e; Expression e1 = curriedLet.getE1(); // generate the appropriate lambda abstractions String[] identifiers = curriedLet.getIdentifiers(); for (int n = identifiers.length - 1; n > 0; --n) { e1 = new Lambda(identifiers[n], e1); } // add the recursion for letrec if (e instanceof CurriedLetRec) { e1 = new Recursion(identifiers[0], e1); } // add the proof node context.addProofNode(node, e1); } else if (e instanceof MultiLet) { // proof the first sub expression MultiLet multiLet = (MultiLet)e; context.addProofNode(node, multiLet.getE1()); } else { // determine the first sub expression Let let = (Let)e; Expression e1 = let.getE1(); // add the recursion for letrec if (e instanceof LetRec) { e1 = new Recursion(let.getId(), e1); } // add the proof node context.addProofNode(node, e1); } } /** * {@inheritDoc} * * @see bigstep.BigStepProofRule#update(bigstep.BigStepProofContext, bigstep.BigStepProofNode) */ @Override public void update(BigStepProofContext context, BigStepProofNode node) { // check if we have exactly one proven child node if (node.getChildCount() == 1 && node.getChildAt(0).isProven()) { // determine the value of the first child node Expression value0 = node.getChildAt(0).getResult().getValue(); // determine the expression for the node Expression e = (Expression)node.getExpression(); // check the expression type if (e instanceof CurriedLet) { // add a proof node for e2 (CurriedLet/CurriedLetRec) CurriedLet curriedLet = (CurriedLet)e; context.addProofNode(node, curriedLet.getE2().substitute(curriedLet.getIdentifiers()[0], value0)); } else if (e instanceof MultiLet) { // determine the second sub expression e2 (MultiLet) MultiLet multiLet = (MultiLet)e; Expression e2 = multiLet.getE2(); // perform the required substitutions String[] identifiers = multiLet.getIdentifiers(); for (int n = 0; n < identifiers.length; ++n) { // substitute: (#l_n value0) for id e2 = e2.substitute(identifiers[n], new Application(new Projection(identifiers.length, n + 1), value0)); } // add a proof node for e2 context.addProofNode(node, e2); } else { // add a proof node for e2 (Let/LetRec) Let let = (Let)e; context.addProofNode(node, let.getE2().substitute(let.getId(), value0)); } } else if (node.getChildCount() == 2) { // forward the result of the second child node context.setProofNodeResult(node, node.getChildAt(1).getResult()); } else { super.update(context, node); } } }