package org.scribble.visit.context; import org.scribble.ast.ProtocolDecl; import org.scribble.ast.ScribNode; import org.scribble.ast.context.ModuleContext; import org.scribble.ast.local.LChoice; import org.scribble.ast.local.LDo; import org.scribble.ast.local.LInteractionNode; import org.scribble.ast.local.LProtocolBlock; import org.scribble.main.Job; import org.scribble.main.ScribbleException; import org.scribble.sesstype.SubprotocolSig; import org.scribble.sesstype.kind.ProtocolKind; import org.scribble.sesstype.name.ProtocolName; import org.scribble.visit.SubprotocolVisitor; import org.scribble.visit.context.env.UnguardedChoiceDoEnv; // FIXME: refactor as a choice subject candidate collector (i.e. NameCollector -- thought that is an OffsetSubprotocolCollector, does that make a difference?) public class UnguardedChoiceDoProjectionChecker extends SubprotocolVisitor<UnguardedChoiceDoEnv> //public class ChoiceUnguardedSubprotocolChecker extends NoEnvSubprotocolVisitor { //private final LChoice cho; // Useless: subprotocovisitor visits a role-substituted clone private boolean shouldPrune = false; // OK here, or reinstant in env? public UnguardedChoiceDoProjectionChecker(Job job, ModuleContext mcontext, LChoice cho) { super(job); setModuleContext(mcontext); } public void setPruneCheck() { this.shouldPrune = true; } public boolean shouldCheckPrune() { return this.shouldPrune; } @Override protected UnguardedChoiceDoEnv makeRootProtocolDeclEnv(ProtocolDecl<? extends ProtocolKind> pd) { return new UnguardedChoiceDoEnv(); } @Override public ScribNode visit(ScribNode parent, ScribNode child) throws ScribbleException { if (child instanceof LChoice) { LChoice lc = (LChoice) child; return visitOverrideForLDoPruning(parent, lc); } return super.visit(parent, child); } private ScribNode visitOverrideForLDoPruning(ScribNode parent, LChoice lc) throws ScribbleException { for (LProtocolBlock b : lc.getBlocks()) { LInteractionNode in = b.getInteractionSeq().getInteractions().get(0); if (in instanceof LDo) { LDo ld = (LDo) in; ProtocolName<?> fullname = getModuleContext().checkProtocolDeclDependencyFullName(ld.proto.toName()); SubprotocolSig sig = new SubprotocolSig(fullname, ld.roles.getRoles(), ld.args.getArguments()); if (sig.equals(getStack().get(0))) // Cf. SubprotocolVisitor.isRootedCycle { //if (isRootedCycle()) // ChoiceUnguardedSubprotocolChecker is a (regular) SubprotocolVisitor which pushes a subprotosig on root decl entry (ProjectedSubprotocolPruner.visit) // Check for "rooted" cycle to ensure it's specifically the cycle from the root proto decl (back) to the target do // FIXME: but cycle to specific "target do" is not ensured: could be another instance of a do with the same subprotosig... an inherent issue of the current subprotocolvisitor framework // FIXME: this algorithm works for some use cases for is still wrong (prunes some that it shouldn't -- e.g. mutually pruneable choice-unguarded do's) // *** what we really need is to check for 0 inferred choice subjects up to recursion back (if any) to to the parent choice -- problem is current framework doesn't make identifying (e.g. ==) the original choice easy *** // no?: we don't need to come back to specifically the original choice: we follow the control flow into the target protocoldecl and if we encounter a recursion, regardless of whether it is back to the original choice-do or not, then it's a recursion and that's where the control flow (from this original do) will remain // the issue is arising since WF was relaxed to allow unbalanced choice case roles: with balanced, subject inference is always fine as long as roles are used? (and prev assumed no choice-unguarded do's?) { setPruneCheck(); return lc; } } } } return super.visit(parent, lc); } @Override protected void subprotocolEnter(ScribNode parent, ScribNode child) throws ScribbleException { super.subprotocolEnter(parent, child); child.del().enterUnguardedChoiceDoProjectionCheck(parent, child, this); } @Override protected ScribNode subprotocolLeave(ScribNode parent, ScribNode child, ScribNode visited) throws ScribbleException { visited = visited.del().leaveUnguardedChoiceDoProjectionCheck(parent, child, this, visited); return super.subprotocolLeave(parent, child, visited); } }