package org.scribble.visit;
import java.util.HashMap;
import java.util.Map;
import org.scribble.ast.Do;
import org.scribble.ast.InteractionSeq;
import org.scribble.ast.ProtocolDecl;
import org.scribble.ast.ScribNode;
import org.scribble.ast.context.ModuleContext;
import org.scribble.ast.global.GDo;
import org.scribble.ast.local.LDo;
import org.scribble.del.ProtocolDefDel;
import org.scribble.del.global.GDoDel;
import org.scribble.del.local.LDoDel;
import org.scribble.main.Job;
import org.scribble.main.JobContext;
import org.scribble.main.ScribbleException;
import org.scribble.sesstype.SubprotocolSig;
import org.scribble.sesstype.kind.ProtocolKind;
import org.scribble.sesstype.name.RecVar;
import org.scribble.visit.env.InlineProtocolEnv;
public class ProtocolDefInliner extends SubprotocolVisitor<InlineProtocolEnv>
{
private Map<SubprotocolSig, RecVar> subprotoRecVars = new HashMap<>(); // RecVars translation for subprotocol inlining
private Map<RecVar, Integer> recvars = new HashMap<>(); // Original RecVars, nesting count
public ProtocolDefInliner(Job job)
{
super(job);
}
public RecVar getSubprotocolRecVar(SubprotocolSig subsig)
{
return this.subprotoRecVars.get(subsig);
}
public void setSubprotocolRecVar(SubprotocolSig subsig)
{
this.subprotoRecVars.put(subsig, new RecVar(newSubprotocoolRecVarId(subsig)));
}
public void removeSubprotocolRecVar(SubprotocolSig subsig)
{
this.subprotoRecVars.remove(subsig);
}
private String newSubprotocoolRecVarId(SubprotocolSig sig)
{
// Hacky
return sig.toString()
.replace('.', '_')
.replace('<', '_')
.replace('>', '_')
.replace('(', '_')
.replace(')', '_')
.replace(' ', '_')
.replace(',', '_');
}
@Override
protected InlineProtocolEnv makeRootProtocolDeclEnv(ProtocolDecl<? extends ProtocolKind> pd)
{
return new InlineProtocolEnv();
}
@Override
public ScribNode visit(ScribNode parent, ScribNode child) throws ScribbleException
{
enter(parent, child);
ScribNode visited = visitForSubprotocols(parent, child);
if (visited instanceof ProtocolDecl<?>)
{
ProtocolDecl<?> pd = (ProtocolDecl<?>) visited;
this.job.debugPrintln("\n[DEBUG] Inlined root protocol "
+ pd.getFullMemberName(this.job.getContext().getModule(getModuleContext().root)) + ":\n"
+ ((ProtocolDefDel) pd.def.del()).getInlinedProtocolDef());
}
return leave(parent, child, visited);
}
@Override
public ScribNode visitForSubprotocols(ScribNode parent, ScribNode child) throws ScribbleException
{
if (child instanceof Do)
{
return visitOverrideForDo((InteractionSeq<?>) parent, (Do<?>) child);
}
ScribNode visited = super.visitForSubprotocols(parent, child);
/*if (visited instanceof ProtocolDecl<?>)
{
ProtocolDecl<?> pd = (ProtocolDecl<?>) visited;
getJob().debugPrintln("\n[DEBUG] Inlined protocol "
+ pd.getFullMemberName(getJobContext().getModule(getModuleContext().root)) + ":\n"
+ ((ProtocolDefDel) pd.def.del()).getInlinedProtocolDef());
}*/
return visited;
}
protected Do<?> visitOverrideForDo(InteractionSeq<?> parent, Do<?> child) throws ScribbleException
{
if (!isCycle())
{
//return (GDo) super.visitForSubprotocols(parent, child);
// Duplicated from SubprotocolVisitor#visitOverrideFoDo and modified to access discarded env -- FIXME: factor out this facility better
JobContext jc = this.job.getContext();
ModuleContext mc = getModuleContext();
ProtocolDecl<? extends ProtocolKind> pd = child.getTargetProtocolDecl(jc, mc);
ScribNode seq = applySubstitutions(pd.def.block.seq.clone());
seq = seq.accept(this);
pushEnv(popEnv().setTranslation(((InlineProtocolEnv) seq.del().env()).getTranslation()));
return child;
}
// If cycle, super routine does nothing anyway, so we can just replace with new stuff here
return (child instanceof GDo)
? ((GDoDel) child.del()).visitForSubprotocolInlining(this, (GDo) child)
: ((LDoDel) child.del()).visitForSubprotocolInlining(this, (LDo) child);
}
@Override
protected void subprotocolEnter(ScribNode parent, ScribNode child) throws ScribbleException
{
super.subprotocolEnter(parent, child);
child.del().enterProtocolInlining(parent, child, this);
}
@Override
protected ScribNode subprotocolLeave(ScribNode parent, ScribNode child, ScribNode visited) throws ScribbleException
{
visited = visited.del().leaveProtocolInlining(parent, child, this, visited);
return super.subprotocolLeave(parent, child, visited);
}
public void pushRecVar(RecVar rv)
{
if (!this.recvars.containsKey(rv))
{
this.recvars.put(rv, 0);
}
else
{
this.recvars.put(rv, this.recvars.get(rv) + 1);
}
}
public void popRecVar(RecVar rv)
{
Integer i = this.recvars.get(rv);
if (i == 0)
{
this.recvars.remove(rv);
}
else
{
this.recvars.put(rv, i - 1);
}
}
// Refactored here from NameDisambiguation
public String getCanonicalRecVarName(RecVar rv)
{
//return getCanonicalRecVarName(this.getModuleContext().root, this.root.header.getDeclName(), rv.toString() + "_" + this.recvars.get(rv));
Integer i = this.recvars.get(rv);
return (i == 0) ? rv.toString() : (rv.toString() + i);
}
}