package org.scribble.visit.wf; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.scribble.ast.ScribNode; import org.scribble.ast.global.GDelegationElem; import org.scribble.del.global.GDelegationElemDel; import org.scribble.main.Job; import org.scribble.main.ScribbleException; import org.scribble.sesstype.kind.NonRoleArgKind; import org.scribble.sesstype.kind.NonRoleParamKind; import org.scribble.sesstype.name.Name; import org.scribble.sesstype.name.RecVar; import org.scribble.sesstype.name.Role; import org.scribble.visit.context.ModuleContextVisitor; // Disambiguates ambiguous PayloadTypeOrParameter names and inserts implicit Scope names // Also canonicalises recvars public class NameDisambiguator extends ModuleContextVisitor { // For implicit scope generation: reset per ProtocolDecl //private int counter = 1; private Set<Role> roles = new HashSet<>(); private Map<String, NonRoleParamKind> params = new HashMap<>(); //private Set<RecVar> recvars = new HashSet<>(); //private Map<RecVar, Deque<RecVar>> recvars = new HashMap<>(); private Map<RecVar, Integer> recvars = new HashMap<>(); // Nesting count integer now unused (recvar renaming refactored to inlining -- don't want to mangle source AST) //private ProtocolDecl<?> root; // FIXME: factor out // Now unused (recvar renaming refactored to inlining -- don't want to mangle source AST) public NameDisambiguator(Job job) { super(job); } /*public ScopeNode getFreshScope() { return new ScopeNode(null, Scope.IMPLICIT_SCOPE_PREFIX + "." + counter++); }*/ // Most subclasses will override visitForSubprotocols (e.g. ReachabilityChecker, FsmConstructor), but sometimes still want to change whole visit pattern (e.g. Projector) @Override public ScribNode visit(ScribNode parent, ScribNode child) throws ScribbleException { /*if (child instanceof ProtocolDecl<?>) // FIXME: factor out { this.root = (ProtocolDecl<?>) child; }*/ enter(parent, child); ScribNode visited = visitForDisamb(parent, child); return leave(parent, child, visited); } protected ScribNode visitForDisamb(ScribNode parent, ScribNode child) throws ScribbleException { if (child instanceof GDelegationElem) { //return visitOverrideForDelegationElem(parent, (Do<?>) child); return ((GDelegationElemDel) child.del()).visitForNameDisambiguation(this, (GDelegationElem) child); } else { return child.visitChildren(this); } } @Override //public NameDisambiguator enter(ModelNode parent, ModelNode child) throws ScribbleException public void enter(ScribNode parent, ScribNode child) throws ScribbleException { super.enter(parent, child); child.del().enterDisambiguation(parent, child, this); } @Override public ScribNode leave(ScribNode parent, ScribNode child, ScribNode visited) throws ScribbleException { visited = visited.del().leaveDisambiguation(parent, child, this, visited); return super.leave(parent, child, visited); } public void clear() { //this.counter = 1; this.roles.clear(); this.params.clear(); this.recvars.clear(); // Should be unnecessary //this.pds.clear(); // No: called by ProtocolDecl leaveDisambiguation (i.e. before the above leave override) -- should be unnecessary anyway } public void addRole(Role role) { this.roles.add(role); } public boolean isBoundRole(Role role) { return this.roles.contains(role); } public void addParameter(Name<? extends NonRoleParamKind> param, NonRoleParamKind kind) { this.params.put(param.toString(), kind); } // name is a simple name (compound names are not ambiguous) public boolean isBoundParameter(Name<? extends NonRoleArgKind> name) // ArgKind allows AmbigNames { return this.params.containsKey(name.toString()); } public NonRoleParamKind getParameterKind(Name<? extends NonRoleArgKind> name) // ArgKind allows AmbigNames { return this.params.get(name.toString()); } //public void addRecVar(RecVar rv) public void pushRecVar(RecVar rv) { //this.recvars.add(rv); /*Deque<RecVar> deque = this.recvars.get(rv); if (deque.isEmpty()) { deque = new LinkedList<RecVar>(); this.recvars.put(rv, deque); } deque.push(..canonicalised name..);*/ if (!this.recvars.containsKey(rv)) { this.recvars.put(rv, 0); } else { this.recvars.put(rv, this.recvars.get(rv) + 1); } } public boolean isBoundRecVar(RecVar rv) { //return this.recvars.contains(rv); return this.recvars.containsKey(rv); } //public void removeRecVar(RecVar rv) public void popRecVar(RecVar rv) { //this.recvars.remove(rv); /*Deque<RecVar> deque = this.recvars.get(rv); deque.pop(); if (deque.isEmpty()) { this.recvars.remove(rv); }*/ Integer i = this.recvars.get(rv); if (i == 0) { this.recvars.remove(rv); // Cf. isBoundRecVar, uses containsKey } else { this.recvars.put(rv, i - 1); } } /*public String getCanonicalRecVarName(RecVar rv) { return getCanonicalRecVarName(this.getModuleContext().root, this.root.header.getDeclName(), rv.toString() + "_" + this.recvars.get(rv)); } // Cf. ProtocolDefInliner.newRecVarId public static String getCanonicalRecVarName(ModuleName fullmodname, ProtocolName<?> simpprotoname, String rv) { //return rv.toString(); return ("__" + fullmodname + "_" + simpprotoname + "_" + rv).replace('.', '_'); }*/ }