package org.scribble.ast.global;
import java.util.List;
import org.antlr.runtime.tree.CommonTree;
import org.scribble.ast.Interruptible;
import org.scribble.ast.ProtocolBlock;
import org.scribble.ast.ScribNodeBase;
import org.scribble.ast.name.simple.ScopeNode;
import org.scribble.sesstype.kind.Global;
import org.scribble.sesstype.kind.ScopeKind;
import org.scribble.sesstype.name.Name;
//public class GlobalInterruptible extends Interruptible<GlobalProtocolBlock, GlobalInterrupt> implements GlobalInteractionNode
public class GInterruptible extends Interruptible<Global> implements GCompoundInteractionNode
{
/*public static final Function<Interrupt, GlobalInterrupt> toGlobalInterrupt =
(Interrupt interr)
-> (GlobalInterrupt) interr;
public static final Function<List<? extends Interrupt>, List<GlobalInterrupt>> toGlobalInterruptList =
(List<? extends Interrupt> interrs)
-> interrs.stream().map(GlobalInterruptible.toGlobalInterrupt).collect(Collectors.toList());*/
//public GlobalInterruptible(GlobalProtocolBlock block, List<GlobalInterrupt> interrs)
public GInterruptible(CommonTree source, ProtocolBlock<Global> block, List<GInterrupt> interrs)
{
//this(null, block, interrs, null, null);
this(source, null, block, interrs);
}
//public GlobalInterruptible(ScopeNode scope, GlobalProtocolBlock block, List<GlobalInterrupt> interrs)
public GInterruptible(CommonTree source, ScopeNode scope, ProtocolBlock<Global> block, List<GInterrupt> interrs)
{
//this(ct, scope, block, interrs, null, null);
super(source, scope, block, interrs);
}
@Override
protected ScribNodeBase copy()
{
throw new RuntimeException("TODO: " + this);
}
@Override
public GInterruptible clone()
{
throw new RuntimeException("TODO: " + this);
}
@Override
public boolean isEmptyScope()
{
throw new RuntimeException("TODO: " + this);
}
@Override
public Name<ScopeKind> getScopeElement()
{
throw new RuntimeException("TODO: " + this);
}
// FIXME: shouldn't be needed, but here due to Eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=436350
@Override
public Global getKind()
{
return GCompoundInteractionNode.super.getKind();
}
/*protected GlobalInterruptible(CommonTree ct, ScopeNode scope, GlobalProtocolBlock block, List<GlobalInterrupt> interrs, CompoundInteractionNodeContext icontext)
{
super(ct, scope, block, interrs, icontext);
}* /
protected GlobalInterruptible(CommonTree ct, ScopeNode scope, GlobalProtocolBlock block, List<GlobalInterrupt> interrs, CompoundInteractionNodeContext icontext, Env env)
{
super(ct, scope, block, interrs, icontext, env);
}
@Override
protected GlobalInterruptible reconstruct(CommonTree ct, ScopeNode scope, GlobalProtocolBlock block, List<GlobalInterrupt> interrs, CompoundInteractionNodeContext icontext, Env env)
{
return new GlobalInterruptible(ct, scope, block, interrs, icontext, env);
}
@Override
public GlobalInterruptible leaveDisambiguation(NameDisambiguator disamb) throws ScribbleException
{
ScopeNode scope = this.scope;
if (scope == null)
{
scope = disamb.getFreshScope();
}
//return new GlobalInterruptible(this.ct, scope, this.block, this.interrs);
return reconstruct(this.ct, scope, this.block, this.interrs, getContext(), getEnv());
}
@Override
public GlobalInterruptible leaveContextBuilding(NodeContextBuilder builder) throws ScribbleException
{
Interruptible<GlobalProtocolBlock, GlobalInterrupt> intt = super.leaveContextBuilding(builder);
ProtocolBlockContext bcontext = intt.block.getContext();
// Interrupt dests building done here (in the parent) because visitor pattern for context building doesn't easily allow children (block and interrupts) to see each other's contexts
List<GlobalInterrupt> interrs = new LinkedList<GlobalInterrupt>();
//ProtocolDeclContext pdcontext = builder.getProtocolDeclContext();
for (GlobalInterrupt interr : intt.interrs)
{
Role src = interr.src.toName();
List<Role> dests = new LinkedList<>(bcontext.getRoles());
// FIXME: also include other interrupt sources?
dests.remove(src);
GlobalInterruptContext icontext = new GlobalInterruptContext(dests);
interrs.add(new GlobalInterrupt(interr.ct, interr.src, interr.msgs, icontext, interr.getEnv()));
CompoundInteractionContext cicontext = (CompoundInteractionContext) builder.peekContext();
for (Role dest : dests) // Cannot do in super Interruptible because dest info not available yet
{
for (MessageNode mn : interr.msgs)
{
Message msg = mn.toMessage();
//((CompoundInteractionContext) builder.peekContext()).addInterrupt(src, dest, msg);
//builder.replaceContext(((CompoundInteractionContext) builder.peekContext()).addInterrupt(src, dest, msg));
cicontext = cicontext.addInterrupt(src, dest, msg);
}
}
builder.replaceContext(cicontext);
}
//return new GlobalInterruptible(intt.ct, intt.scope, intt.block, interrs, intt.getContext());
return reconstruct(intt.ct, intt.scope, intt.block, interrs, intt.getContext(), getEnv());
}
@Override
public GlobalInterruptible leaveProjection(Projector proj) //throws ScribbleException
{
ScopeNode scope = new ScopeNode(null, this.scope.toName().toString()); // Inconsistent to copy role nodes manually, but do via children visiting for other children
LocalProtocolBlock block = (LocalProtocolBlock) ((ProjectionEnv) this.block.getEnv()).getProjection();
/*List<LocalInterrupt> interrs =
this.interrs.stream().map(() -> (LocalInterrupt) ((ProjectionEnv) .getEnv()).getProjection()).collect(Collectors.toList());* /
LocalThrows thro = null;
List<LocalCatches> cats = new LinkedList<>();
for (GlobalInterrupt gi : this.interrs)
{
LocalInterrupt li = (LocalInterrupt) ((ProjectionEnv) gi.getEnv()).getProjection();
if (li != null)
{
if (li instanceof LocalThrows)
{
thro = (LocalThrows) li;
}
else
{
cats.add((LocalCatches) li);
}
}
}
LocalInterruptible projection = null;
if (!block.isEmpty() || thro != null)
{
projection = new LocalInterruptible(ct, scope, block, thro, cats);
}
this.setEnv(new ProjectionEnv(proj.getJobContext(), proj.getModuleContext(), projection));
return this;
}
/*@Override
public GlobalInterruptible leaveWFChoiceCheck(WellFormedChoiceChecker checker) throws ScribbleException
{
Interruptible<GlobalProtocolBlock, GlobalInterrupt> intt = super.leaveWFChoiceCheck(checker);
return new GlobalInterruptible(intt.ct, intt.scope, intt.block, intt.interrs, intt.getContext(), intt.getEnv());
}*/
/*@Override
public Env enter(EnvVisitor nv) throws ScribbleException
{
Env env = nv.getEnv();
if (nv instanceof WellFormednessChecker) // Hacky
{
Scope scope = this.scope.toName();
if (env.scopes.getScopes().contains(scope))
{
throw new ScribbleException("Duplicate scope: " + scope);
}
}
return super.enter(nv);
}
@Override
public GlobalInterruptible checkWellFormedness(WellFormednessChecker wfc) throws ScribbleException
{
GlobalInterruptible gi = (GlobalInterruptible) super.checkWellFormedness(wfc); // visitChildren
Env env = gi.block.getEnv();
Set<Role> roles = new HashSet<>();
for (Interrupt interr : gi.interrs)
{
//GlobalInterrupt interr = (GlobalInterrupt) foo;
Role src = interr.src.toName();
if (roles.contains(src))
{
throw new ScribbleException("Duplicate interrupt source role: " + src);
}
roles.add(src);
if (env.ops.getSources().contains(src))
{
Set<Operator> ops = new HashSet<>(env.ops.getAll(src));
List<Operator> tmp = interr.getOperators(env);
ops.retainAll(tmp);
if (!ops.isEmpty())
{
throw new ScribbleException("Bad interrupt operators: " + tmp);
}
}
}
return gi;
}
@Override
public LocalInterruptible project(Projector proj) throws ScribbleException
{
// Not calling super method (doing child visiting manually)
LocalProtocolBlock block = (LocalProtocolBlock) proj.visit(this.block);
LocalThrows thro = null;
List<LocalCatches> cats = new LinkedList<>();
for (Interrupt interr : this.interrs)
{
if (!interr.dests.isEmpty()) // HACK: make more proper -- if no one to throw interr to, cannot throw (so don't project)
{
LocalNode ln = (LocalNode) proj.visit(interr);
if (ln != null)
{
if (block == null)
{
LocalInteractionSequence lis = new LocalInteractionSequence(null, Collections.<LocalInteraction>emptyList());
block = new LocalProtocolBlock(null, lis);
}
if (ln instanceof LocalThrows)
{
if (thro != null)
{
throw new RuntimeException("Shouldn't get in here: " + this);
}
thro = (LocalThrows) ln;
}
else
{
cats.add((LocalCatches) ln);
}
}
}
}
if (block == null && thro == null && cats.isEmpty())
{
return null;
}
return new LocalInterruptible(null, this.scope, block, thro, cats);
}*/
/*@Override
public GlobalInterruptible visitChildren(NodeVisitor nv) throws ScribbleException
{
Interruptible<GlobalProtocolBlock, GlobalInterrupt> intt = super.visitChildren(nv);
//List<GlobalInterrupt> interrs = GlobalInterruptible.toGlobalInterruptList.apply(intt.interrs);
return new GlobalInterruptible(intt.ct, intt.scope, intt.block, intt.interrs, intt.getContext(), intt.getEnv());
}*/
}