package org.scribble.visit;
import java.util.LinkedList;
import org.scribble.ast.ProtocolDecl;
import org.scribble.ast.ScribNode;
import org.scribble.main.Job;
import org.scribble.main.ScribbleException;
import org.scribble.sesstype.kind.ProtocolKind;
import org.scribble.visit.context.ModuleContextVisitor;
import org.scribble.visit.env.Env;
// By default, EnvVisitor only manipulates internal Env stack -- so AST/dels not affected
// Attaching Envs to Dels has to be done manually by each pass
// FIXME: make a ProtocolDeclContextVisitor (caches ProtocolDeclContext, e.g. roles, modifiers) between this and ModuleContextVisitor
public abstract class EnvVisitor<T extends Env<?>> extends ModuleContextVisitor
{
private LinkedList<T> envs = new LinkedList<T>(); // Deque
public EnvVisitor(Job job)
{
super(job);
}
@Override
protected final void enter(ScribNode parent, ScribNode child) throws ScribbleException
{
super.enter(parent, child);
if (child instanceof ProtocolDecl) // Only the root ProtocolDecl is visited: subprotocols visit the body directly
{
ProtocolDecl<? extends ProtocolKind> pd = (ProtocolDecl<?>) child;
pushEnv(makeRootProtocolDeclEnv(pd));
}
envEnter(parent, child);
}
@Override
protected final ScribNode leave(ScribNode parent, ScribNode child, ScribNode visited) throws ScribbleException
{
ScribNode n = envLeave(parent, child, visited);
if (n instanceof ProtocolDecl) // Only the root ProtocolDecl is visited by SubprotocolVisitor (subprotocols visit the body directly)
{
this.envs.pop();
}
return super.leave(parent, child, n);
}
protected abstract T makeRootProtocolDeclEnv(ProtocolDecl<? extends ProtocolKind> pd);
protected void envEnter(ScribNode parent, ScribNode child) throws ScribbleException
{
//..could push copy of parent Env onto visitor stack for use by visitor pass (del env-leave routine should pop and push back the final result)
//..but only if want an env for every node (unless restrict to specific nodes types -- e.g. interaction nodes) -- as opposed to only e.g. compound nodes, as done via del
//..so either do base env management here or via del -- here, need to do instanceof; in delegates, need to duplicate base push/pop for each pass
//..no: should be only compound interaction nodes, as typing environments
//return this;
}
protected ScribNode envLeave(ScribNode parent, ScribNode child, ScribNode visited) throws ScribbleException
{
return visited;
}
// Hack? e.g. for ModuleDecl
public boolean hasEnv()
{
return !this.envs.isEmpty();
}
public T peekEnv()
{
return this.envs.peek();
}
public T peekParentEnv()
{
//return this.envs.get(this.envs.size() - 2);
return this.envs.get(1);
}
public void pushEnv(T env)
{
this.envs.push(env);
}
public T popEnv()
{
return this.envs.pop();
}
}