package de.unisiegen.tpml.core.bigstep ;
import java.util.LinkedList ;
import de.unisiegen.tpml.core.ProofRuleException ;
import de.unisiegen.tpml.core.expressions.Expression ;
import de.unisiegen.tpml.core.interpreters.Store ;
/**
* Default implementation of the <code>BigStepProofContext</code> interface.
* The big step proof context is used in the big step proof rules (and thereby
* the rule sets) to communicate with the proof model. For the proof model, the
* context is used to register redo and undo actions during a single proof step
* and collect the actions later.
*
* @author Benedikt Meurer
* @version $Rev$
* @see de.unisiegen.tpml.core.bigstep.AbstractBigStepProofRuleSet
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext
*/
final class DefaultBigStepProofContext implements BigStepProofContext
{
//
// Attributes
//
/**
* The big step proof model to which this context is connected.
*/
private BigStepProofModel model ;
/**
* The list of registered redo actions.
*
* @see #addRedoAction(Runnable)
* @see #getRedoActions()
*/
private LinkedList < Runnable > redoActions = new LinkedList < Runnable > ( ) ;
/**
* The list of registered undo actions.
*
* @see #addUndoAction(Runnable)
* @see #getUndoActions()
*/
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 pModel {@link BigStepProofModel} on which this context should
* operate.
* @throws NullPointerException if <code>model</code> is <code>null</code>.
*/
DefaultBigStepProofContext ( BigStepProofModel pModel )
{
if ( pModel == null )
{
throw new NullPointerException ( "model is null" ) ; //$NON-NLS-1$
}
this.model = pModel ;
}
//
// Primitives
//
/**
* {@inheritDoc}
*
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext#addProofNode(de.unisiegen.tpml.core.bigstep.BigStepProofNode,
* de.unisiegen.tpml.core.expressions.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 de.unisiegen.tpml.core.bigstep.BigStepProofContext#addProofNode(de.unisiegen.tpml.core.bigstep.BigStepProofNode,
* de.unisiegen.tpml.core.expressions.Expression,
* de.unisiegen.tpml.core.interpreters.Store)
*/
public void addProofNode ( BigStepProofNode node , Expression expression ,
Store store )
{
this.model.contextAddProofNode ( this , ( DefaultBigStepProofNode ) node ,
new DefaultBigStepProofNode ( expression , store ) ) ;
}
/**
* {@inheritDoc}
*
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext#isMemoryEnabled()
*/
public boolean isMemoryEnabled ( )
{
return this.model.isMemoryEnabled ( ) ;
}
/**
* {@inheritDoc}
*
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext#newNoopRule(java.lang.String)
*/
public BigStepProofRule newNoopRule ( String name )
{
return AbstractBigStepProofRule.newNoopRule ( name ) ;
}
/**
* {@inheritDoc}
*
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext#setProofNodeResult(de.unisiegen.tpml.core.bigstep.BigStepProofNode,
* de.unisiegen.tpml.core.bigstep.BigStepProofResult)
*/
public void setProofNodeResult ( BigStepProofNode node ,
BigStepProofResult result )
{
this.model.contextSetProofNodeResult ( this ,
( DefaultBigStepProofNode ) node , result ) ;
}
/**
* {@inheritDoc}
*
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext#setProofNodeResult(de.unisiegen.tpml.core.bigstep.BigStepProofNode,
* de.unisiegen.tpml.core.expressions.Expression)
*/
public void setProofNodeResult ( BigStepProofNode node , Expression value )
{
// default to inhert 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 de.unisiegen.tpml.core.bigstep.BigStepProofContext#setProofNodeResult(de.unisiegen.tpml.core.bigstep.BigStepProofNode,
* de.unisiegen.tpml.core.expressions.Expression,
* de.unisiegen.tpml.core.interpreters.Store)
*/
public void setProofNodeResult ( BigStepProofNode node , Expression value ,
Store store )
{
setProofNodeResult ( node , new BigStepProofResult ( store , value ) ) ;
}
/**
* {@inheritDoc}
*
* @see de.unisiegen.tpml.core.bigstep.BigStepProofContext#setProofNodeRule(de.unisiegen.tpml.core.bigstep.BigStepProofNode,
* de.unisiegen.tpml.core.bigstep.BigStepProofRule)
*/
public void setProofNodeRule ( BigStepProofNode node , BigStepProofRule rule )
{
this.model.contextSetProofNodeRule ( this ,
( DefaultBigStepProofNode ) node , rule ) ;
}
//
// Rule application
//
/**
* Used to implement the
* <code>BigStepProofModel#apply(BigStepProofRule, DefaultBigStepProofNode)</code>
* method in the {@link BigStepProofModel} class. Applies the
* <code>rule</code> to the <code>node</code>, recording
* <code>rule</code> for the <code>node</code> and recording all further
* actions that were performed, including the actions required to undo the
* application step.
*
* @param rule the big step proof rule.
* @param node the big step proof node.
* @throws ProofRuleException if the application of <code>rule</code> to
* <code>node</code> fails.
*/
void apply ( BigStepProofRule rule , BigStepProofNode node )
throws ProofRuleException
{
// record the proof step
setProofNodeRule ( node , rule ) ;
// try to apply the rule to the node
rule.apply ( this , node ) ;
// update all (unproven) super nodes
BigStepProofNode newNode = node ;
for ( ; ; )
{
// determine the parent node
newNode = newNode.getParent ( ) ;
if ( newNode == null )
{
break ;
}
// update the parent node
updateNode ( newNode ) ;
}
}
/**
* Used to implement the
* <code>BigStepProofModel#apply(BigStepProofRule, DefaultBigStepProofNode)</code>
* method in the {@link BigStepProofModel} class. Reverts all previously
* performed actions, using the recorded undo actions. The recorded undo
* actions will be cleared afterwards.
*/
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 one of its child nodes.
* 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 all child nodes are finished and
* one of the child nodes resulted in an exception, the first such 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.
* @see #apply(BigStepProofRule, BigStepProofNode)
*/
void updateNode ( BigStepProofNode node )
{
// skip the node if its already proven
if ( node.isProven ( ) )
{
return ;
}
// check if all child nodes are finished...
boolean childrenFinished = true ;
for ( int n = 0 ; childrenFinished && n < node.getChildCount ( ) ; ++ n )
{
childrenFinished = ( childrenFinished && node.getChildAt ( n )
.isFinished ( ) ) ;
}
// ...and if so, check if any resulted in an exception
BigStepProofNode nodeWithExn = null ;
if ( childrenFinished )
{
for ( int n = 0 ; n < node.getChildCount ( ) ; ++ n )
{
nodeWithExn = node.getChildAt ( n ) ;
if ( nodeWithExn.getResult ( ).getValue ( ).isException ( ) )
{
break ;
}
nodeWithExn = null ;
}
}
// determine the rule that was applied to the node
AbstractBigStepProofRule rule = ( AbstractBigStepProofRule ) node
.getRule ( ) ;
// check if child node resulted in an exception
if ( nodeWithExn != null )
{
// generate an exception rule for the node
setProofNodeRule ( node , rule.toExnRule ( node.getIndex ( nodeWithExn ) ) ) ;
// forward the exception value
setProofNodeResult ( node , nodeWithExn.getResult ( ) ) ;
}
else
{
// use the rule's update() mechanism
rule.update ( this , node ) ;
}
}
//
// Context action handling
//
/**
* Appends the <code>redoAction</code> to the list of redoable actions and
* runs the <code>redoAction</code>.
*
* @param redoAction the redo action to add.
* @throws NullPointerException if <code>redoAction</code> is
* <code>null</code>.
* @see #addUndoAction(Runnable)
* @see #getRedoActions()
*/
void addRedoAction ( Runnable redoAction )
{
if ( redoAction == null )
{
throw new NullPointerException ( "redoAction is null" ) ; //$NON-NLS-1$
}
// perform the action
redoAction.run ( ) ;
// record the action
this.redoActions.add ( redoAction ) ;
}
/**
* Prepends the <code>undoAction</code> to the list of undoable actions.
*
* @param undoAction the undo action to add.
* @throws NullPointerException if <code>undoAction</code> is
* <code>null</code>.
* @see #addRedoAction(Runnable)
* @see #getUndoActions()
*/
void addUndoAction ( Runnable undoAction )
{
if ( undoAction == null )
{
throw new NullPointerException ( "undoAction is null" ) ; //$NON-NLS-1$
}
// record the action
this.undoActions.add ( 0 , undoAction ) ;
}
/**
* Returns a single <code>Runnable</code> that runs all previously
* registered redo actions.
*
* @return a single <code>Runnable</code> to run all redo actions.
* @see #addRedoAction(Runnable)
* @see #getUndoActions()
*/
Runnable getRedoActions ( )
{
return new Runnable ( )
{
@ SuppressWarnings ( "synthetic-access" )
public void run ( )
{
for ( Runnable redoAction : DefaultBigStepProofContext.this.redoActions )
{
redoAction.run ( ) ;
}
}
} ;
}
/**
* Returns a single <code>Runnable</code> that runs all previously
* registered undo actions.
*
* @return a single <code>Runnable</code> to run all undo actions.
* @see #addUndoAction(Runnable)
* @see #getRedoActions()
*/
Runnable getUndoActions ( )
{
return new Runnable ( )
{
@ SuppressWarnings ( "synthetic-access" )
public void run ( )
{
for ( Runnable undoAction : DefaultBigStepProofContext.this.undoActions )
{
undoAction.run ( ) ;
}
}
} ;
}
}