package bigstep;
import java.util.LinkedList;
import common.ProofRuleException;
import common.interpreters.Store;
import expressions.Expression;
/**
* Default implementation of the <code>BigStepProofContext</code> interface.
*
* @author Benedikt Meurer
* @version $Id$
*
* @see bigstep.BigStepProofContext
*/
final class DefaultBigStepProofContext implements BigStepProofContext {
//
// Attributes
//
/**
* TODO Add documentation here.
*/
private BigStepProofModel model;
/**
* TODO Add documentation here.
*/
private LinkedList<Runnable> redoActions = new LinkedList<Runnable>();
/**
* TODO Add documentation here.
*/
private LinkedList<Runnable> undoActions = new LinkedList<Runnable>();
//
// Constructor (package)
//
/**
* Allocates a new <code>DefaultBigStepProofContext</code> with the specified
* <code>model</code> and <code>node</code>.
*
* @param model the {@link BigStepProofModel} on which this context
* should operate.
*
* @throws NullPointerException if <code>model</code> is <code>null</code>.
*/
DefaultBigStepProofContext(BigStepProofModel model) {
if (model == null) {
throw new NullPointerException("model is null");
}
this.model = model;
}
//
// Rule application
//
/**
* TODO Add documentation here.
*/
void apply(BigStepProofRule rule, BigStepProofNode node) throws ProofRuleException {
// record the proof step
setProofNodeRule(node, rule);
// try to apply the rule to the node
try {
rule.apply(this, node);
}
catch (ClassCastException e) {
throw new ProofRuleException(node, rule, e);
}
// update all (unproven) super nodes
for (;;) {
// determine the parent node
BigStepProofNode parentNode = (BigStepProofNode)node.getParent();
if (parentNode == null) {
break;
}
// update the parent node
updateNode(parentNode, node);
// continue with the next one
node = parentNode;
}
}
/**
* TODO Add documentation here.
*/
void revert() {
// undo all already performed changes
for (Runnable undoAction : this.undoActions) {
undoAction.run();
}
this.undoActions.clear();
}
/**
* Updates the <code>node</code> after a change to the <code>childNode</code>.
* This is needed for non-axiom rules, like <b>(APP)</b>, that need to react
* to proof steps on child nodes. If the <code>node</code> is already proven,
* no action will be performed.
*
* If the <code>childNode</code>'s value is an exception, the exception will
* be forwarded to the <code>node</code>.
*
* Otherwise the {@link BigStepProofRule#update(BigStepProofContext, BigStepProofNode)}
* method of the rule that was applied to <code>node</code> will be executed to
* update the state of the <code>node</code>.
*
* @param node the node to update.
* @param childNode the child node that was changed.
*/
void updateNode(BigStepProofNode node, BigStepProofNode childNode) {
// skip the node if its already proven
if (node.isProven()) {
return;
}
// determine the rule that was applied to the node
BigStepProofRule rule = node.getRule();
// check if child node resulted in an exception
if (childNode.isProven() && childNode.getResult().getValue().isException()) {
// generate an exception rule for the node
setProofNodeRule(node, rule.toExnRule(node.getIndex(childNode)));
// forward the exception value
setProofNodeResult(node, childNode.getResult());
}
else {
// use the rule's update() mechanism
rule.update(this, node);
}
}
//
// Context action handling
//
/**
* TODO Add documentation here.
*
* @param redoAction
*/
void addRedoAction(Runnable redoAction) {
// perform the action
redoAction.run();
// record the action
this.redoActions.add(redoAction);
}
/**
* TODO Add documentation here.
*
* @param undoAction
*/
void addUndoAction(Runnable undoAction) {
// record the action
this.undoActions.add(0, undoAction);
}
/**
* TODO Add documentation here.
*
* @return
*/
Runnable getRedoActions() {
return new Runnable() {
public void run() {
for (Runnable redoAction : DefaultBigStepProofContext.this.redoActions) {
redoAction.run();
}
}
};
}
/**
* TODO Add documentation here.
*
* @return
*/
Runnable getUndoActions() {
return new Runnable() {
public void run() {
for (Runnable undoAction : DefaultBigStepProofContext.this.undoActions) {
undoAction.run();
}
}
};
}
//
// Proof tree updates
//
/**
* {@inheritDoc}
*
* @see BigStepProofContext#addProofNode(BigStepProofNode, Expression)
*/
public void addProofNode(BigStepProofNode node, Expression expression) {
// default to inherit the store of the parent node
Store store = node.getStore();
// use the store of the last child node (if proven)
if (node.getChildCount() > 0) {
BigStepProofResult result = node.getLastChild().getResult();
if (result != null) {
store = result.getStore();
}
}
// and add the new node
addProofNode(node, expression, store);
}
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofContext#addProofNode(bigstep.BigStepProofNode, expressions.Expression, common.interpreters.Store)
*/
public void addProofNode(BigStepProofNode node, Expression expression, Store store) {
this.model.contextAddProofNode(this, (DefaultBigStepProofNode)node, expression, store);
}
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofContext#isMemoryEnabled()
*/
public boolean isMemoryEnabled() {
return this.model.isMemoryEnabled();
}
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofContext#setProofNodeResult(bigstep.BigStepProofNode, bigstep.BigStepProofResult)
*/
public void setProofNodeResult(BigStepProofNode node, BigStepProofResult result) {
this.model.contextSetProofNodeResult(this, (DefaultBigStepProofNode)node, result);
}
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofContext#setProofNodeResult(bigstep.BigStepProofNode, expressions.Expression)
*/
public void setProofNodeResult(BigStepProofNode node, Expression value) {
// default to inherit the store of this node
Store store = node.getStore();
// use the store of the last child node (if proven)
if (node.getChildCount() > 0) {
BigStepProofResult result = node.getLastChild().getResult();
if (result != null) {
store = result.getStore();
}
}
// add the result
setProofNodeResult(node, value, store);
}
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofContext#setProofNodeResult(bigstep.BigStepProofNode, expressions.Expression, common.interpreters.Store)
*/
public void setProofNodeResult(BigStepProofNode node, Expression value, Store store) {
setProofNodeResult(node, new DefaultBigStepProofResult(store, value));
}
/**
* {@inheritDoc}
*
* @see bigstep.BigStepProofContext#setProofNodeRule(bigstep.BigStepProofNode, bigstep.BigStepProofRule)
*/
public void setProofNodeRule(BigStepProofNode node, BigStepProofRule rule) {
this.model.contextSetProofNodeRule(this, (DefaultBigStepProofNode)node, rule);
}
}