All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wyil.transform.SymbolTable Maven / Gradle / Ivy


/**
 * Responsible for resolving a name which occurs at some position in a
 * compilation unit. This takes into account the context and, if necessary, will
 * traverse important statements to resolve the query. For example, consider a
 * compilation unit entitled "file":
 *
 * 
 * import std::ascii::*
 *
 * function f(T1 x, T2 y) -> (int r):
 *    return g(x,y)
 * 
* * Here the name "g" is not fully qualified. Depending on which * file the matching declaration of g occurs will depend on what * its fully qualified name is. For example, if g is declared in * the current compilation unit then it's fully quaified name would be * test.g. However, it could well be declared in a compilation unit * matching the import whiley.lang.*. * * @author David J. Pearce * */ package wyil.transform; import static wyil.lang.WyilFile.Modifier; import static wyil.lang.WyilFile.Name; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import wycc.util.AbstractCompilationUnit.Identifier; import wycc.util.AbstractCompilationUnit.Tuple; import wyil.lang.WyilFile; import wyil.lang.WyilFile.Decl; import wyil.lang.WyilFile.Decl.Named; import wyil.lang.WyilFile.QualifiedName; /** * Represents the cumulative knowledge of all symbols used in resolving names * for the given module. This is determined by the module itself, along with any * dependencies. * * @author David J. Pearce * */ public class SymbolTable { /** * The enclosing WyilFile this symbol table is operating on. */ private final WyilFile target; /** * Cached information about symbols available in the given WyilFile and external * dependencies. */ private final HashMap symbolTable = new HashMap<>(); /** * The consolidation list identifies those which need to be consolidated */ private final HashSet consolidations = new HashSet<>(); /** * Construct a symbol table containing meta-data on a given target file and its * dependencies. * * @param target * @param deps */ public SymbolTable(WyilFile target, List deps) { this.target = target; // Decl.Module module = target.getModule(); // Register all internal symbols for (Decl.Unit unit : module.getUnits()) { symbolTable.put(unit.getName(), new LocalGroup(unit)); } // Register all external symbols for(int i=0;i!=deps.size();++i) { Decl.Module dep = deps.get(i).getModule(); for (Decl.Unit unit : dep.getUnits()) { symbolTable.put(unit.getName(), new ExternalGroup(unit)); } } // Register any available (i.e. imported) external symbols for (Decl.Unit unit : module.getExterns()) { ExternalGroup group = (ExternalGroup) symbolTable.get(unit.getName()); group.register(unit); } } /** * Check whether a given qualified name is registered. That is, whether or not * there is a corresponding name in a given group. * * @param name * @return */ public boolean contains(QualifiedName name) { Name unit = name.getUnit(); // Get information associated with this unit SymbolTable.Group group = symbolTable.get(unit); return group != null && group.isValid(name.getName()); } /** * Check whether a given unit is known to this symbol table. * * @param name * @return */ public boolean contains(Name name) { // Get information associated with this unit SymbolTable.Group group = symbolTable.get(name); return group != null; } /** * Check whether a given symbol is currently external to the enclosing WyilFile. * Specifically, this indicates whether or not a stub is available for it. * * @param name * @return */ public boolean isAvailable(QualifiedName name) { SymbolTable.Group group = symbolTable.get(name.getUnit()); return group != null && group.isAvailable(name.getName()); } /** * Check whether a given unit is know to this symbol table. * * @param name * @return */ public Group getGroup(Name name) { return symbolTable.get(name); } /** * Get the actual declarations associated with a given symbol. * * @param name * @return */ public List getRegisteredDeclarations(QualifiedName name) { Group g = symbolTable.get(name.getUnit()); if (g != null) { return g.getRegisteredDeclarations(name.getName()); } else { return Collections.EMPTY_LIST; } } /** * Get the available declarations associated with a given symbol. * * @param name * @return */ public List getAvailableDeclarations(QualifiedName name) { Group g = symbolTable.get(name.getUnit()); if (g != null) { return g.getAvailableDeclarations(name.getName()); } else { return Collections.EMPTY_LIST; } } /** * Make available declarations for an external symbol. This makes those * declarations available within the target for linking. * * @param name Fully qualified name of symbol being consolidated. * @param available List of declaration stubs which have now been imported into * the target. */ public void addAvailable(QualifiedName name, List available) { ExternalGroup group = (ExternalGroup) symbolTable.get(name.getUnit()); // for (int i = 0; i != available.size(); ++i) { group.addAvailable(available.get(i)); } } /** * Consolidate the status of external symbols. For example, this will ensure all * external units which have imported symbols are made available. Likewise, it * may garbage collect available symbols and units which are no longer required. * * @return */ public void consolidate() { Decl.Module module = target.getModule(); for(ExternalGroup group : consolidations) { // TODO: this could be made way more efficient by collecting all consolidate // units into one batch module.putExtern(group.consolidate()); } consolidations.clear(); } /** * Represents a group of symbols which are related through their enclosing * compilation unit. * * @author David J. Pearce * */ public interface Group { /** * Check whether a given symbol existing within this group or not. * * @param name * @return */ public boolean isValid(Identifier name); /** * Check whether a given symbol as a declaration available within the target. * Local symbols are always available. Non-local symbols may be available if * they have been imported. * * @param name * @return */ public boolean isAvailable(Identifier name); /** * Get the concrete declarations associated with a given symbol * * @param name * @return */ public List getRegisteredDeclarations(Identifier name); /** * Get the available declarations associated with a given symbol * * @param name * @return */ public List getAvailableDeclarations(Identifier name); } private static abstract class AbstractGroup implements Group { /** * The list of known symbols associated with this group. */ protected final HashMap entries = new HashMap<>(); @Override public boolean isAvailable(Identifier name) { if(entries.containsKey(name)) { return entries.get(name).isAvailable(); } else { return false; } } @Override public boolean isValid(Identifier name) { return entries.containsKey(name); } @Override public List getRegisteredDeclarations(Identifier name) { if(entries.containsKey(name)) { return entries.get(name).getDeclarations(); } else { return Collections.EMPTY_LIST; } } @Override public List getAvailableDeclarations(Identifier name) { if (entries.containsKey(name)) { return entries.get(name).getAvailable(); } else { return Collections.EMPTY_LIST; } } } /** * Record information associated with a given group of symbols (i.e. as located * in same compilation unit). * * @author David J. Pearce * */ public static class LocalGroup extends AbstractGroup { /** * Construct a local group to represent a given unit in the target. * * @param unit */ public LocalGroup(Decl.Unit unit) { for(Decl d : unit.getDeclarations()) { if(d instanceof Decl.Named) { Decl.Named n = (Decl.Named) d; get(n.getName()).addAvailable(n); } } } // FIXME: we will need some methods for handling adding / removing declarations // as a result of incremental updates to the target. private LocalEntry get(Identifier name) { SymbolTable.LocalEntry r = entries.get(name); // if (r == null) { r = new SymbolTable.LocalEntry(); entries.put(name, r); } return r; } } public class ExternalGroup extends AbstractGroup { /** * The external declaration that this group is associated with. */ private final Decl.Unit external; /** * The available declaration representing this group in the target. This may be * null if the unit has not yet been imported. */ private Decl.Unit available; /** * Construct a non-local group to represent a given unit in the target. * * @param unit */ public ExternalGroup(Decl.Unit unit) { this.external = unit; // for(Decl d : unit.getDeclarations()) { if(d instanceof Decl.Named) { Decl.Named n = (Decl.Named) d; // Add public members only if(isPublic(n)) { get(n.getName()).addExternal(n); } } } } /** * Register an available unit declared within the target and all symbols * contained therein. * * @param declaration */ public void register(Decl.Unit available) { this.available = available; // Register as available all internal symbols for (Decl d : available.getDeclarations()) { if (d instanceof Decl.Named) { addAvailable((Decl.Named) d); } } } public void addAvailable(Decl.Named available) { get(available.getName()).addAvailable(available); if(this.available == null) { consolidations.add(this); } } /** * Called when this group has available symbols but there is no enclosing unit * is available in the target. */ public Decl.Unit consolidate() { Tuple declarations = new Tuple<>(getAllAvailable()); available = new Decl.Unit(external.getName(), declarations); return available; } private List getAllAvailable() { ArrayList available = new ArrayList<>(); for(Map.Entry e : entries.entrySet()) { available.addAll(e.getValue().getAvailable()); } return available; } private Entry get(Identifier name) { SymbolTable.ExternalEntry r = entries.get(name); // if (r == null) { r = new SymbolTable.ExternalEntry(); entries.put(name, r); } return r; } /** * Check whether named declaration is public or not. * * @param decl * @return */ private boolean isPublic(Decl.Named decl) { return decl.getModifiers().match(Modifier.Public.class) != null; } } /** * A generic interface for describing symbols. * * @author David J. Pearce * */ public interface Entry { /** * Check whether this entry is currently available in the target. Local symbols * are always available. Non-local symbols may be available if they have been * imported at some point. * * @return */ public boolean isAvailable(); /** * Get the available declarations for this symbol which in the target. * * @return */ public List getAvailable(); /** * Get the actual declarations for this symbol. * * @return */ public List getDeclarations(); /** * Add an available declaration for this symbol. * * @param decl */ public void addAvailable(Decl.Named decl); /** * Add an external declaration for this symbol. * * @param decl */ public void addExternal(Decl.Named decl); } /** * Represents an entry which is declared in the target file. This is the easy * case as we never need to import local entries. * * @author David J. Pearce * */ public static class LocalEntry implements Entry { /** * Identifies the complete set of declarations associated with this symbol. */ private final ArrayList declarations; public LocalEntry() { this.declarations = new ArrayList<>(); } @Override public boolean isAvailable() { return true; } @Override public List getAvailable() { return declarations; } @Override public List getDeclarations() { return declarations; } @Override public void addAvailable(Named decl) { declarations.add(decl); } @Override public void addExternal(Named decl) { throw new UnsupportedOperationException(); } } /** * Represents a symbol external to the given target. Such a symbol may have * already been imported into the target as a stub. * * @author David J. Pearce * */ public static class ExternalEntry implements Entry { /** * Identifies available declarations for this symbol */ private final ArrayList availables = new ArrayList<>(); /** * Identifies external declarations for this symbol */ private final ArrayList externals = new ArrayList<>(); @Override public boolean isAvailable() { return availables.size() > 0; } @Override public List getAvailable() { return availables; } @Override public List getDeclarations() { return externals; } @Override public void addAvailable(Named decl) { availables.add(decl); } @Override public void addExternal(Named decl) { externals.add(decl); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy