package cd.frontend.semantic; import cd.frontend.semantic.SemanticFailure.Cause; import cd.ir.Symbol; import java.util.*; /** * A simple symbol table, with a pointer to the enclosing scope. * Used by {@link TypeChecker} to store the various scopes for * local, parameter, and field lookup. */ public class SymTable { private final Map map = new HashMap(); private final SymTable parent; public SymTable(SymTable parent) { this.parent = parent; } public void add(S sym) { // check that the symbol is not already declared *at this level* if (containsLocally(sym.name)) throw new SemanticFailure(Cause.DOUBLE_DECLARATION); map.put(sym.name, sym); } public List allSymbols() { List result = new ArrayList(); SymTable st = this; while (st != null) { for (S sym : st.map.values()) result.add(sym); st = st.parent; } return result; } public Collection localSymbols() { return this.map.values(); } /** * True if there is a declaration with the given name at any * level in the symbol table */ public boolean contains(String name) { return get(name) != null; } /** * True if there is a declaration at THIS level in the symbol * table; may return {@code false} even if a declaration exists * in some enclosing scope */ public boolean containsLocally(String name) { return this.map.containsKey(name); } /** * Base method: returns {@code null} if no symbol by that * name can be found, in this table or in its parents */ public S get(String name) { S res = map.get(name); if (res != null) return res; if (parent == null) return null; return parent.get(name); } /** * Finds the symbol with the given name, or fails with a * NO_SUCH_TYPE error. Only really makes sense to use this * if S == TypeSymbol, but we don't strictly forbid it... */ public S getType(String name) { S res = get(name); if (res == null) throw new SemanticFailure( Cause.NO_SUCH_TYPE, "No type '%s' was found", name); return res; } }