package org.scribble.del.local;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.scribble.ast.AstFactoryImpl;
import org.scribble.ast.ScribNode;
import org.scribble.ast.local.LContinue;
import org.scribble.ast.name.simple.RecVarNode;
import org.scribble.del.ContinueDel;
import org.scribble.main.ScribbleException;
import org.scribble.model.endpoint.EState;
import org.scribble.model.endpoint.actions.EAction;
import org.scribble.sesstype.name.RecVar;
import org.scribble.visit.ProtocolDefInliner;
import org.scribble.visit.context.EGraphBuilder;
import org.scribble.visit.env.InlineProtocolEnv;
import org.scribble.visit.wf.ReachabilityChecker;
import org.scribble.visit.wf.env.ReachabilityEnv;
public class LContinueDel extends ContinueDel implements LSimpleInteractionNodeDel
{
@Override
public LContinue leaveProtocolInlining(ScribNode parent, ScribNode child, ProtocolDefInliner inl, ScribNode visited) throws ScribbleException
{
LContinue lc = (LContinue) visited;
RecVarNode recvar = (RecVarNode) ((InlineProtocolEnv) lc.recvar.del().env()).getTranslation();
LContinue inlined = AstFactoryImpl.FACTORY.LContinue(lc.getSource(), recvar);
inl.pushEnv(inl.popEnv().setTranslation(inlined));
return (LContinue) super.leaveProtocolInlining(parent, child, inl, lc);
}
@Override
public LContinue leaveReachabilityCheck(ScribNode parent, ScribNode child, ReachabilityChecker checker, ScribNode visited) throws ScribbleException
{
// "Entering" the continue here in leave, where we can merge the new state into the parent Env
// Generally: if side effecting Env state to be merged into the parent (not just popped and discarded), leave must be overridden to do so
LContinue lc = (LContinue) visited;
ReachabilityEnv env = checker.popEnv().addContinueLabel(lc.recvar.toName());
setEnv(env); // Env recording probably not needed for all LocalInteractionNodes, just the compound ones, like for WF-choice checking
checker.pushEnv(checker.popEnv().mergeContext(env));
return lc;
}
@Override
public LContinue leaveEGraphBuilding(ScribNode parent, ScribNode child, EGraphBuilder graph, ScribNode visited) throws ScribbleException
{
LContinue lr = (LContinue) visited;
RecVar rv = lr.recvar.toName();
if (graph.util.isUnguardedInChoice())
{
graph.util.addContinueEdge(graph.util.getEntry(), rv);
}
else
{
// ** "Overwrites" previous edge built by send/receive(s) leading to this continue
Iterator<EState> preds = graph.util.getPredecessors().iterator();
Iterator<EAction> prevs = graph.util.getPreviousActions().iterator();
EState entry = graph.util.getEntry();
Set<List<Object>> removed = new HashSet<>();
// HACK: for identical edges, i.e. same pred/prev/succ (e.g. rec X { choice at A { A->B:1 } or { A->B:1 } continue X; }) // FIXME: do here, or refactor into GraphBuilder?
// Because duplicate edges preemptively pruned by ModelState.addEdge, but corresponding predecessors not pruned // FIXME: make uniform
while (preds.hasNext())
{
EState pred = preds.next();
EAction prev = prevs.next();
List<Object> tmp = Arrays.asList(pred, prev, entry);
if (!removed.contains(tmp))
{
removed.add(tmp);
graph.util.removeEdgeFromPredecessor(pred, prev); // Assumes pred is a predecessor, and removes pred from current predecessors..
}
graph.util.addRecursionEdge(pred, prev, graph.util.getRecursionEntry(rv)); // May be repeated for non-det, but OK // Combine with removeEdgeFromPredecessor?
}
}
return (LContinue) super.leaveEGraphBuilding(parent, child, graph, lr);
}
}