package org.scribble.del.local;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.scribble.ast.AstFactoryImpl;
import org.scribble.ast.Choice;
import org.scribble.ast.ScribNode;
import org.scribble.ast.local.LChoice;
import org.scribble.ast.local.LProtocolBlock;
import org.scribble.ast.name.simple.RoleNode;
import org.scribble.del.ChoiceDel;
import org.scribble.main.ScribbleException;
import org.scribble.sesstype.kind.RoleKind;
import org.scribble.sesstype.name.RecVar;
import org.scribble.sesstype.name.Role;
import org.scribble.visit.ProtocolDefInliner;
import org.scribble.visit.context.EGraphBuilder;
import org.scribble.visit.context.ProjectedChoiceDoPruner;
import org.scribble.visit.context.ProjectedChoiceSubjectFixer;
import org.scribble.visit.context.UnguardedChoiceDoProjectionChecker;
import org.scribble.visit.context.env.UnguardedChoiceDoEnv;
import org.scribble.visit.env.InlineProtocolEnv;
import org.scribble.visit.wf.ReachabilityChecker;
import org.scribble.visit.wf.env.ReachabilityEnv;
public class LChoiceDel extends ChoiceDel implements LCompoundInteractionNodeDel
{
/* // Not needed: just enters and pushes, done by base routine (only overwite if do extra stuff, like pushChoiceParent)
@Override
public void enterUnguardedChoiceDoProjectionCheck(ScribNode parent, ScribNode child, ChoiceUnguardedSubprotocolChecker checker) throws ScribbleException
{
ChoiceUnguardedSubprotocolEnv env = checker.peekEnv().enterContext();
checker.pushEnv(env);
}*/
@Override
public ScribNode leaveUnguardedChoiceDoProjectionCheck(ScribNode parent, ScribNode child, UnguardedChoiceDoProjectionChecker checker, ScribNode visited) throws ScribbleException
{
Choice<?> cho = (Choice<?>) visited;
List<UnguardedChoiceDoEnv> benvs =
cho.getBlocks().stream().map((b) -> (UnguardedChoiceDoEnv) b.del().env()).collect(Collectors.toList());
UnguardedChoiceDoEnv merged = checker.popEnv().mergeContexts(benvs);
checker.pushEnv(merged);
return (Choice<?>) super.leaveUnguardedChoiceDoProjectionCheck(parent, child, checker, cho); // Done merge of children here, super does merge into parent
}
@Override
public ScribNode leaveProjectedChoiceDoPruning(ScribNode parent, ScribNode child, ProjectedChoiceDoPruner pruner, ScribNode visited) throws ScribbleException
{
LChoice lc = (LChoice) visited;
List<LProtocolBlock> blocks = lc.getBlocks().stream().filter((b) -> !b.isEmpty()).collect(Collectors.toList());
if (blocks.isEmpty())
{
return null;
}
return lc.reconstruct(lc.subj, blocks);
}
@Override
public ScribNode leaveProjectedChoiceSubjectFixing(ScribNode parent, ScribNode child, ProjectedChoiceSubjectFixer fixer, ScribNode visited) throws ScribbleException
{
LChoice lc = (LChoice) visited;
List<LProtocolBlock> blocks = lc.getBlocks();
Set<Role> subjs = blocks.stream()
.map((b) -> b.getInteractionSeq().getInteractions().get(0).inferLocalChoiceSubject(fixer))
//.filter((r) -> !r.toString().equals(DummyProjectionRoleNode.DUMMY_PROJECTION_ROLE))
.collect(Collectors.toSet());
if (subjs.size() == 0)
{
//throw new RuntimeScribbleException("TODO: unable to infer projection subject: " + parent);
throw new RuntimeException("Shouldn't get in here: " + subjs); // FIXME: should be OK now by model-based WF
}
else
{
subjs = subjs.stream()
.map((r) -> fixer.isRecVarRole(r) ? fixer.getChoiceSubject(new RecVar(r.toString())) : r) // Never needed?
.collect(Collectors.toSet());
}
// HACK? (for non- role-balanced choice cases)
subjs = subjs.stream().filter((s) -> s != null).collect(Collectors.toSet());
if (subjs.size() > 1) // Unnecessary: due to WF check in GChoiceDel.leaveInlinedPathCollection -- would be better as a check on locals than in projection anyway
{
String self = fixer.getModuleContext().root.getSimpleName().toString(); // HACK
self = self.substring(self.lastIndexOf('_')+1, self.length()); // FIXME: not sound (if role names include "_")
throw new ScribbleException(lc.getSource(), "Cannot project onto " + self + " due to inconsistent local choice subjects: " + subjs); // self not recorded -- can derive from LProtocolDecl RoleDeclList
//throw new RuntimeException("Shouldn't get in here: " + subjs);
}
RoleNode subj = (RoleNode) AstFactoryImpl.FACTORY.SimpleNameNode(null, RoleKind.KIND, // FIXME? null source OK?
//blocks.get(0).getInteractionSeq().getInteractions().get(0).inferLocalChoiceSubject(fixer).toString());
subjs.iterator().next().toString());
fixer.setChoiceSubject(subj.toName());
LChoice projection = AstFactoryImpl.FACTORY.LChoice(lc.getSource(), subj, blocks);
return projection;
}
@Override
public ScribNode leaveProtocolInlining(ScribNode parent, ScribNode child, ProtocolDefInliner inl, ScribNode visited) throws ScribbleException
{
LChoice lc = (LChoice) visited;
List<LProtocolBlock> blocks =
lc.getBlocks().stream().map((b) -> (LProtocolBlock) ((InlineProtocolEnv) b.del().env()).getTranslation()).collect(Collectors.toList());
RoleNode subj = lc.subj.clone();
LChoice inlined = AstFactoryImpl.FACTORY.LChoice(lc.getSource(), subj, blocks);
inl.pushEnv(inl.popEnv().setTranslation(inlined));
return (LChoice) super.leaveProtocolInlining(parent, child, inl, lc);
}
@Override
public LChoice leaveReachabilityCheck(ScribNode parent, ScribNode child, ReachabilityChecker checker, ScribNode visited) throws ScribbleException
{
LChoice cho = (LChoice) visited;
List<ReachabilityEnv> benvs =
cho.getBlocks().stream().map((b) -> (ReachabilityEnv) b.del().env()).collect(Collectors.toList());
ReachabilityEnv merged = checker.popEnv().mergeForChoice(benvs);
checker.pushEnv(merged);
return (LChoice) LCompoundInteractionNodeDel.super.leaveReachabilityCheck(parent, child, checker, visited); // records the current checker Env to the current del; also pops and merges that env into the parent env
}
@Override
public void enterEGraphBuilding(ScribNode parent, ScribNode child, EGraphBuilder graph)
{
super.enterEGraphBuilding(parent, child, graph);
graph.util.enterChoice();
}
public LChoice visitForFsmConversion(EGraphBuilder graph, LChoice child)
{
try
{
for (LProtocolBlock block : child.getBlocks())
{
graph.util.pushChoiceBlock();
block.accept(graph);
graph.util.popChoiceBlock();
}
}
catch (ScribbleException e)
{
throw new RuntimeException("Shouldn't get in here: " + e);
}
return child;
}
@Override
public ScribNode leaveEGraphBuilding(ScribNode parent, ScribNode child, EGraphBuilder graph, ScribNode visited) throws ScribbleException
{
graph.util.leaveChoice();
return super.leaveEGraphBuilding(parent, child, graph, visited);
}
}