package st; import java.util.*; import misc.*; import heat.TypecheckException; /** * Class which provides methods for interacting with and managing * the symbol table. Maintains context-awareness to keep the state * of each symbol consistent. */ public class SymbolTable { private HashMap symt; // the mapping of ids to Instances private HashMap active; // the current scope of the visitor (class, method) public SymbolTable() { MinimalLogger.info("Creating a new SymbolTable..."); this.symt = new HashMap<>(); this.active = new HashMap<>(); } @Override public String toString() { StringBuilder mapAsString = new StringBuilder("{"); for (TokenKey key : this.symt.keySet()) { mapAsString.append(key.toString() + ":" + this.symt.get(key).getType() + ", "); } mapAsString.delete(mapAsString.length()-2, mapAsString.length()).append("}"); return mapAsString.toString(); } /** * Methods intended to be used during the first pass * * Will always throw a typecheck error when symbols are not distinct. */ public void put(TokenKey id, AbstractInstance symbol) { MinimalLogger.info(String.format("Inserting %s -> %s", id, symbol.getType())); if (this.symt.get(id) != null) throw new TypecheckException(String.format("SymbolTable tried to place %s twice!", id.toString())); this.symt.put(id, symbol); } /** * Methods intended to be used during the second pass */ public void setExtend(String arg) { ClassInstance cls = (ClassInstance) this.active.get(TypeEnum.classname); ClassInstance ext = this.getClass(arg); if (ext == null) throw new TypecheckException(String.format("There is no %s to extend!", arg)); MinimalLogger.info(String.format("%s found to extend %s", cls.getName(), ext.getName())); cls.setExtend(ext); TokenKey k; for (TypeInstance t : ext.getLocals()) { k = new TokenKey(t.getName(), TypeEnum.integer, cls, null); if (this.symt.get(k) == null) { MinimalLogger.info(String.format("Added %s (%s) as a local var of %s (%s)", t.getName(), t.getType(), cls.getName(), cls.getType())); cls.addLocal(t); this.symt.put(k, t); } else { MinimalLogger.info(String.format("%s found to be overridden in %s.", t.getName(), cls.getName())); } } for (MethodInstance m : ext.getMethods()) { k = new TokenKey(m.getName(), TypeEnum.method, cls, null); if (this.symt.get(k) == null) { MinimalLogger.info(String.format("Added %s (%s) as a method of %s (%s)", m.getName(), m.getType(), cls.getName(), cls.getType())); this.symt.put(k, m); cls.addMethod(m); } else { MethodInstance exist = (MethodInstance) this.symt.get(k); ArrayList expected = exist.getArguments(); ArrayList actual = m.getArguments(); if (expected.size() != actual.size() || !exist.getReturn().equalsOnExtend(m.getReturn())) throw new TypecheckException(String.format("SymbolTable found that %s is overwritten in %s!", m.getName(), cls.getName())); for (int i = 0; i < actual.size(); ++i) { if (!expected.get(i).getClassInstance().equals(actual.get(i).getClassInstance())) { throw new TypecheckException(String.format("SymbolTable found that %s is overwritten in %s!", m.getName(), cls.getName())); } } MinimalLogger.info(String.format("%s found to be overridden in %s.", m.getName(), cls.getName())); } } } public void addLocal(String lvar) { TypeInstance var = this.getType(lvar); AbstractInstance par; if (this.active.get(TypeEnum.method) != null) { // we are in a method MethodInstance par1 = (MethodInstance) this.active.get(TypeEnum.method); par1.addLocal(var); par = par1; } else { ClassInstance par1 = (ClassInstance) this.active.get(TypeEnum.classname); par1.addLocal(var); par = par1; } MinimalLogger.info(String.format("Added %s (%s) as a local var of %s (%s)", var.getName(), var.getType(), par.getName(), par.getType())); } public void addMethod(String mtd) { ClassInstance cls = (ClassInstance) this.active.get(TypeEnum.classname); MethodInstance lmtd = this.getMethod(mtd); cls.addMethod(lmtd); MinimalLogger.info(String.format("Added %s as a method of %s", lmtd.getName(), cls.getName())); } public void addParameter(String arg) { MethodInstance mtd = (MethodInstance) this.active.get(TypeEnum.method); TypeInstance para = this.getType(arg); mtd.addArgument(para); // also adds to local vars MinimalLogger.info(String.format("Added %s as a parameter of %s", para.getName(), mtd.getName())); MinimalLogger.info(String.format("Added %s as a localvar of %s", para.getName(), mtd.getName())); } public void addClassInstance(TypeInstance t, String c) { ClassInstance cls = (c != null) ? this.getClass(c) : null; if (cls != null) MinimalLogger.info(String.format("%s is an instance of class %s", t.getName(), c)); t.addClassInstance(cls); } /** * Methods to safely retrieve differentiable types * in `typecheck', `vaporize' libraries */ public void setActive(TypeEnum type, AbstractInstance id) { MinimalLogger.info(String.format("%s is now the active %s.", id.getName(), type)); this.active.put(type, id); } public void removeActive(TypeEnum type) { AbstractInstance id = this.getActive(type); MinimalLogger.info(String.format("%s is no longer the active %s.", id.getName(), type)); this.active.remove(type); } public TypeInstance getType(String name) { TokenKey id = new TokenKey(name, TypeEnum.integer, (ClassInstance) this.getActive(TypeEnum.classname), (MethodInstance) this.getActive(TypeEnum.method)); AbstractInstance symbol; TypeInstance ret = ((symbol = this.symt.get(id)) != null && symbol instanceof TypeInstance) ? (TypeInstance) symbol : null; if (ret == null) MinimalLogger.severe(String.format("getType returning null for missing alias %s!", id)); return ret; } public TypeInstance getTypeAttr(String name) { TokenKey id = new TokenKey(name, TypeEnum.integer, (ClassInstance) this.getActive(TypeEnum.classname), null); AbstractInstance symbol; TypeInstance ret = ((symbol = this.symt.get(id)) != null && symbol instanceof TypeInstance) ? (TypeInstance) symbol : null; if (ret == null) MinimalLogger.severe(String.format("getType returning null for missing alias %s!", id)); return ret; } public MethodInstance getMethod(String name) { TokenKey id = new TokenKey(name, TypeEnum.method, (ClassInstance) this.getActive(TypeEnum.classname), null); AbstractInstance symbol; MethodInstance ret = ((symbol = this.symt.get(id)) != null && symbol instanceof MethodInstance) ? (MethodInstance) symbol : null; if (ret == null) MinimalLogger.severe(String.format("getMethod returning null for missing alias %s!", id)); return ret; } public MethodInstance getMethod(String name, ClassInstance c) { TokenKey id = new TokenKey(name, TypeEnum.method, c, null); AbstractInstance symbol; MethodInstance ret = ((symbol = this.symt.get(id)) != null && symbol instanceof MethodInstance) ? (MethodInstance) symbol : null; if (ret == null) MinimalLogger.severe(String.format("getMethod returning null for missing alias %s!", id)); return ret; } public ClassInstance getClass(String name) { TokenKey id = new TokenKey(name, TypeEnum.classname, null, null); AbstractInstance symbol; ClassInstance ret = ((symbol = this.symt.get(id)) != null && symbol instanceof ClassInstance) ? (ClassInstance) symbol : null; if (ret == null) MinimalLogger.severe(String.format("getClass returning null for missing alias %s!", id)); return ret; } public AbstractInstance getActive(TypeEnum type) { return this.active.get(type); } }