package freeboogie.tc; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; import freeboogie.ast.*; import freeboogie.util.Err; /** * Collects information about global names. * Reports any duplicate names. * * @author rgrig * @author reviewed by TODO */ @SuppressWarnings("unused") // many unused parameters public class GlobalsCollector extends Transformer { // the namespace of user defined types private HashMap<String, TypeDecl> types; // the namespace of procedures and functions private HashMap<String, Procedure> procs; private HashMap<String, Function> funcs; // the namespace of constants and global variables private HashMap<String, ConstDecl> consts; private HashMap<String, VariableDecl> vars; // where there any errors? private boolean errors = false; private void reset() { types = new HashMap<String, TypeDecl>(); procs = new HashMap<String, Procedure>(); funcs = new HashMap<String, Function>(); consts = new HashMap<String, ConstDecl>(); vars = new HashMap<String, VariableDecl>(); } /** * Returns whether there where duplicated declarations. * @param ast the AST to be processed * @return whether there are name clashes in the input */ public boolean process(Declaration ast) { reset(); ast.eval(this); return errors; } // === name query functions == /** * Gets the definition for a type name. * @param s the type name * @return the definition, or {@code null} if none */ public TypeDecl typeDef(String s) { return types.get(s); } /** * Look up a procedure definition. * @param s the name of the procedure * @return the definition of the procedure, or {@code null} if not found */ public Procedure procDef(String s) { return procs.get(s); } /** * Look up a function definition. * @param s the name of the function * @return the definition of the function, or {@code null} if not found */ public Function funDef(String s) { return funcs.get(s); } /** * Looks up an id in the global (constants and variables) namespace. * @param s the identifier * @return the definition, or {@code null} if not found; it can be * a {@code ConstDecl} or a {@code VariableDecl} */ public Declaration idDef(String s) { Declaration r = consts.get(s); if (r != null) return r; return vars.get(s); } // === functions to add name-to-def links and to check for duplicates === // if s is in h then report an error at location l private <D extends Declaration> void check(HashMap<String, D> h, String s, AstLocation l) { if (h.get(s) == null) return; Err.error("" + l + ": Identifier " + s + " was already defined."); errors = true; } private void addTypeDef(String s, TypeDecl d) { check(types, s, d.loc()); types.put(s, d); } private void addProcDef(String s, Procedure d) { check(procs, s, d.loc()); check(funcs, s, d.loc()); procs.put(s, d); } private void addFunDef(String s, Function d) { check(procs, s, d.loc()); check(funcs, s, d.loc()); funcs.put(s, d); } private void addConstDef(String s, ConstDecl d) { check(consts, s, d.loc()); check(vars, s, d.loc()); consts.put(s, d); } private void addVarDef(String s, VariableDecl d) { check(consts, s, d.loc()); check(vars, s, d.loc()); vars.put(s, d); } // === dump, for debug === private <D extends Declaration> void dump(Map<String, D> h) { TreeMap<AstLocation, String> ordered = new TreeMap<AstLocation, String>(); for (Map.Entry<String, D> e : h.entrySet()) ordered.put(e.getValue().loc(), e.getKey()); for (Map.Entry<AstLocation, String> e : ordered.entrySet()) System.out.println(e.getValue() + " " + e.getKey()); } /** Dumps the internal data for debug. */ public void dump() { System.out.println("\n*** User defined types ***"); dump(types); System.out.println("\n*** Procedures and functions ***"); dump(procs); dump(funcs); System.out.println("\n*** Constants and variables ***"); dump(consts); dump(vars); } // === the visiting functions === @Override public void see(TypeDecl typeDecl, String name, Declaration tail) { addTypeDef(name, typeDecl); if (tail != null) tail.eval(this); } @Override public void see(ConstDecl constDecl, String id, Type type, Declaration tail) { addConstDef(id, constDecl); if (tail != null) tail.eval(this); } @Override public void see(Function function, Signature sig, Declaration tail) { addFunDef(sig.getName(), function); if (tail != null) tail.eval(this); } @Override public void see(VariableDecl variableDecl, String name, Type type, Declaration tail) { addVarDef(name, variableDecl); if (tail != null) tail.eval(this); } @Override public void see(Procedure procedure, Signature sig, Specification spec, Declaration tail) { addProcDef(sig.getName(), procedure); if (tail != null) tail.eval(this); } // === visit methods that skip places that might contain local variable decls === @Override public void see(Axiom axiom, Expr expr, Declaration tail) { if (tail != null) tail.eval(this); } @Override public void see(Implementation implementation, Signature sig, Body body, Declaration tail) { if (tail != null) tail.eval(this); } }