package org.scribble.ast.context; import java.util.HashMap; import java.util.Map; import org.scribble.ast.DataTypeDecl; import org.scribble.ast.ImportDecl; import org.scribble.ast.ImportModule; import org.scribble.ast.MessageSigNameDecl; import org.scribble.ast.Module; import org.scribble.ast.NonProtocolDecl; import org.scribble.ast.global.GProtocolDecl; import org.scribble.ast.local.LProtocolDecl; import org.scribble.main.JobContext; import org.scribble.main.ScribbleException; import org.scribble.sesstype.kind.Global; import org.scribble.sesstype.kind.Kind; import org.scribble.sesstype.kind.ProtocolKind; import org.scribble.sesstype.kind.SigKind; import org.scribble.sesstype.name.DataType; import org.scribble.sesstype.name.GProtocolName; import org.scribble.sesstype.name.LProtocolName; import org.scribble.sesstype.name.MessageSigName; import org.scribble.sesstype.name.ModuleName; import org.scribble.sesstype.name.Name; import org.scribble.sesstype.name.ProtocolName; // Context information specific to each module as a root (wrt. to visitor passes) public class ModuleContext { public final ModuleName root; // full name // All transitive name dependencies of this module: all names fully qualified // The ScribNames maps are basically just used as sets (identity map) // Cf. ProtocolDeclContext protocol dependencies from protocoldecl as root private final ScribNames deps = new ScribNames(); // The modules and member names that are visible from this Module -- mapped to "cannonical" (fully qualified) names // visible names -> fully qualified names // Directly visible names from this module private final ScribNames visible = new ScribNames(); // Made by ModuleContextBuilder // ModuleContext is the root context public ModuleContext(JobContext jcontext, Module root) throws ScribbleException { ModuleName fullname = root.getFullModuleName(); ModuleName simpname = root.moddecl.getDeclName(); this.root = fullname; // All transitive dependencies (for inlined and subprotocol visiting) addModule(this.deps, root, fullname); addImportDependencies(jcontext, root); // Names directly visible from this module addModule(this.visible, root, fullname); if (!fullname.equals(simpname)) { addModule(this.visible, root, simpname); // Adds simple name of root as visible, and members qualified by simple name } addVisible(jcontext, root); // Adds imports and members by their "direct" names (unqualified, except for no-alias imports) } // Register mod under name modname, modname could be the full module name or an import alias // Adds member names qualified by mod private static void addModule(ScribNames names, Module mod, ModuleName modname) throws ScribbleException { names.modules.put(modname, mod.getFullModuleName()); for (NonProtocolDecl<?> npd : mod.getNonProtocolDecls()) { if (npd.isDataTypeDecl()) { DataTypeDecl dtd = (DataTypeDecl) npd; DataType qualif = new DataType(modname, dtd.getDeclName()); names.data.put(qualif, dtd.getFullMemberName(mod)); } else //if (npd.isMessageSigNameDecl()) { MessageSigNameDecl msnd = (MessageSigNameDecl) npd; MessageSigName qualif = new MessageSigName(modname, msnd.getDeclName()); names.sigs.put(qualif, msnd.getFullMemberName(mod)); } } for (GProtocolDecl gpd : mod.getGlobalProtocolDecls()) { GProtocolName qualif = new GProtocolName(modname, gpd.getHeader().getDeclName()); names.globals.put(qualif, gpd.getFullMemberName(mod)); } for (LProtocolDecl lpd : mod.getLocalProtocolDecls()) { LProtocolName qualif = new LProtocolName(modname, lpd.getHeader().getDeclName()); names.locals.put(qualif, lpd.getFullMemberName(mod)); } } // Could move to ImportModule but would need a defensive copy setter, or cache info in builder and create on leave private void addImportDependencies(JobContext jcontext, Module mod) throws ScribbleException { for (ImportDecl<?> id : mod.getImportDecls()) { if (id.isImportModule()) { ImportModule im = (ImportModule) id; ModuleName fullmodname = im.modname.toName(); if (!this.deps.modules.containsKey(fullmodname)) { Module imported = jcontext.getModule(fullmodname); addModule(this.deps, imported, fullmodname); // Unlike for visible, only doing full names here addImportDependencies(jcontext, imported); } } else { throw new RuntimeException("TODO: " + id); } } } // Adds "local" imports by alias or full name // Adds "local" members by simple names private void addVisible(JobContext jcontext, Module root) throws ScribbleException { // Unlike for deps, visible is not done transitively for (ImportDecl<?> id : root.getImportDecls()) { if (id.isImportModule()) { ImportModule im = (ImportModule) id; ModuleName fullname = im.modname.toName(); ModuleName visname = (im.isAliased()) ? im.getAlias() : fullname; // getVisibleName doesn't use fullname if (this.visible.modules.containsKey(visname)) { throw new ScribbleException(id.getSource(), "Duplicate visible module name: " + visname); } Module imported = jcontext.getModule(fullname); addModule(this.visible, imported, visname); } else { throw new RuntimeException("TODO: " + id); } } for (NonProtocolDecl<?> npd : root.getNonProtocolDecls()) { if (npd.isDataTypeDecl()) { DataTypeDecl dtd = (DataTypeDecl) npd; DataType visname = new DataType(dtd.getDeclName().toString()); this.visible.data.put(visname, dtd.getFullMemberName(root)); } else //if (npd.isMessageSigNameDecl()) { MessageSigNameDecl msnd = (MessageSigNameDecl) npd; MessageSigName visname = new MessageSigName(msnd.getDeclName().toString()); this.visible.sigs.put(visname, msnd.getFullMemberName(root)); } } for (GProtocolDecl gpd : root.getGlobalProtocolDecls()) { GProtocolName visname = new GProtocolName(gpd.getHeader().getDeclName().toString()); this.visible.globals.put(visname, gpd.getFullMemberName(root)); } for (LProtocolDecl lpd : root.getLocalProtocolDecls()) { LProtocolName visname = new LProtocolName(lpd.getHeader().getDeclName().toString()); this.visible.locals.put(visname, lpd.getFullMemberName(root)); } } /*public boolean isDataTypeDependency(DataType typename) { return this.deps.data.keySet().contains(typename); } public boolean isMessageSigNameDependency(Name<? extends SigKind> signame) { return this.deps.sigs.containsKey(signame); }*/ // FIXME: deprecate -- now redundant: proto should already be full name by namedisamb (and this.deps only stores full names) // Refactored as a "check" for now (although still redundant, not actually checking anything) //public <K extends ProtocolKind> ProtocolName<K> getProtocolDeclDependencyFullName(ProtocolName<K> proto) public <K extends ProtocolKind> ProtocolName<K> checkProtocolDeclDependencyFullName(ProtocolName<K> proto) { return getProtocolDeclFullName(this.deps, proto); } public boolean isDataTypeVisible(DataType typename) { return this.visible.data.keySet().contains(typename); } public boolean isMessageSigNameVisible(Name<? extends SigKind> signame) { return this.visible.sigs.containsKey(signame); } public DataType getVisibleDataTypeFullName(DataType visname) { return getFullName(this.visible.data, visname); } public boolean isVisibleDataType(DataType visname) { return this.visible.isVisibleDataType(visname); } public MessageSigName getVisibleMessageSigNameFullName(MessageSigName visname) { return getFullName(this.visible.sigs, visname); } public <K extends ProtocolKind> ProtocolName<K> getVisibleProtocolDeclFullName(ProtocolName<K> visname) { return getProtocolDeclFullName(this.visible, visname); } public <K extends ProtocolKind> boolean isVisibleProtocolDeclName(ProtocolName<K> visname) { return this.visible.isVisibleProtocolDeclName(visname); } public static <K extends ProtocolKind> ProtocolName<K> getProtocolDeclFullName(ScribNames names, ProtocolName<K> proto) { ProtocolName<? extends ProtocolKind> pn = (proto.getKind().equals(Global.KIND)) ? getFullName(names.globals, (GProtocolName) proto) : getFullName(names.locals, (LProtocolName) proto); @SuppressWarnings("unchecked") ProtocolName<K> tmp = (ProtocolName<K>) pn; return tmp; } private static <T extends Name<K>, K extends Kind> T getFullName(Map<T, T> map, T visname) { if (!map.containsKey(visname)) { // FIXME: runtime exception bad -- make a guard method throw new RuntimeException("Unknown name: " + visname); } return map.get(visname); } @Override public String toString() { return "[deps=" + this.deps + ", visible=" + this.visible + "]"; } } class ScribNames { // names -> fully qualified names protected final Map<ModuleName, ModuleName> modules = new HashMap<>(); protected final Map<DataType, DataType> data = new HashMap<>(); protected final Map<MessageSigName, MessageSigName> sigs = new HashMap<>(); protected final Map<GProtocolName, GProtocolName> globals = new HashMap<>(); protected final Map<LProtocolName, LProtocolName> locals = new HashMap<>(); @Override public String toString() { return "(modules=" + this.modules + ", types=" + this.data + ", sigs=" + this.sigs + ", globals=" + this.globals + ", locals=" + this.locals + ")"; } public <K extends ProtocolKind> boolean isVisibleProtocolDeclName(ProtocolName<K> visname) { return this.globals.containsKey(visname) || this.locals.containsKey(visname); } public boolean isVisibleDataType(DataType visname) { return this.data.containsKey(visname); } }