package chocopy.pa2; import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.SymbolTable; import chocopy.common.analysis.types.*; import chocopy.common.astnodes.*; import java.util.*; /** Analyzes declarations to create a top-level symbol table. */ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { /** Current symbol table. Changes with new declarative region. */ private SymbolTable sym = new SymbolTable<>(); /** Global symbol table. */ private final SymbolTable globals = sym; /** Receiver for semantic error messages. */ private final Errors errors; private ClassVType current_class=null; /** A new declaration analyzer sending errors to ERRORS0. */ public DeclarationAnalyzer(Errors errors0) { errors = errors0; ClassVType cvt = new ClassVType("object"); FuncValueType init = new FuncValueType(Type.OBJECT_TYPE); init.parameters.add(Type.OBJECT_TYPE); SymbolTable cvt_scope=new SymbolTable<>(sym); cvt_scope.put("init",init); cvt.scope=cvt_scope; sym.put("object", cvt); cvt = new ClassVType("int"); init = new FuncValueType(Type.INT_TYPE); init.parameters.add(Type.INT_TYPE); cvt_scope=new SymbolTable<>(sym); cvt_scope.put("init",init); cvt.scope=cvt_scope; sym.put("int", cvt); cvt = new ClassVType("str"); init = new FuncValueType(Type.STR_TYPE); init.parameters.add(Type.STR_TYPE); cvt_scope=new SymbolTable<>(sym); cvt_scope.put("init",init); cvt.scope=cvt_scope; sym.put("str", cvt); cvt = new ClassVType("bool"); init = new FuncValueType(Type.BOOL_TYPE); init.parameters.add(Type.BOOL_TYPE); cvt_scope=new SymbolTable<>(sym); cvt_scope.put("init",init); cvt.scope=cvt_scope; sym.put("bool", cvt); } public SymbolTable getGlobals() { return globals; } @Override public Type analyze(Program program) { for (Declaration decl : program.declarations) { Identifier id = decl.getIdentifier(); String name = id.name; Type type = decl.dispatch(this); if (type == null) { continue; } if (sym.declares(name)) { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); } else if (sym.get(name)!= null && sym.get(name) instanceof ClassVType) { errors.semError( id, "Cannot shadow class name: %s", name); continue; } else { sym.put(name, type); } } // Check for return statements at top for (Stmt stmt : program.statements) { if (stmt instanceof ReturnStmt) errors.semError( stmt, "Return statement cannot appear at the top level"); } return null; } @Override public Type analyze(FuncDef node) { FuncValueType current_func=new FuncValueType((ValueType) node.returnType.dispatch(this)); SymbolTable current_scope=new SymbolTable<>(sym); sym=current_scope; for (TypedVar param : node.params) { if (sym.declares(param.identifier.name)) { errors.semError( node.name, "Duplicate declaration of identifier in same " + "scope: %s", param.identifier.name); continue; } else if (sym.get(param.identifier.name)!= null && sym.get(param.identifier.name) instanceof ClassVType) { errors.semError( param.identifier, "Cannot shadow class name: %s", param.identifier.name); continue; } Type p = param.dispatch(this); current_func.parameters.add((ValueType)p); sym.put(param.identifier.name, p); } for (Declaration decl : node.declarations) { Identifier id = decl.getIdentifier(); String name = id.name; Type type = decl.dispatch(this); if (type == null) { continue; } if (sym.declares(name)) { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); continue; } else if (sym.get(name)!= null && sym.get(name) instanceof ClassVType) { errors.semError(id, "Cannot shadow class name: %s", name); continue; } else { sym.put(name, type); } } /*for(String s:sym.getDeclaredSymbols()) System.out.println(" "+s);*/ sym = sym.getParent(); return current_func; } @Override public Type analyze(GlobalDecl node) { if (globals.declares(node.variable.name)==false) { errors.semError( node.variable, "Not a global variable: %s", node.variable.name); return null; } return globals.get(node.variable.name); } public boolean compare_functions(FuncValueType fun1, FuncValueType fun2) { if (fun1.returnType.equals(fun2.returnType)==false) return false; if (fun1.parameters.size() != fun2.parameters.size()) return false; for (int i=1; i current_scope=new SymbolTable<>(sym); sym=current_scope; current_class=cvt; Type super_class = sym.get(node.superClass.name); cvt.super_class = (ClassVType)super_class; SymbolTable super_scope=null; Set super_syms=null; if (super_class == null) { errors.semError( node.name, "Super-class not defined: %s", node.superClass.name); } else if ((super_class instanceof ClassVType)==false) { errors.semError( node.name, "Super-class must be a class: %s", node.superClass.name); } else if (node.superClass.name.equals("int") || node.superClass.name.equals("bool") || node.superClass.name.equals("str")) { errors.semError( node.name, "Cannot extend special class: %s", node.superClass.name); } else { super_scope = cvt.super_class.scope; super_syms = super_scope.getDeclaredSymbols(); for (Declaration decl : node.declarations) { Identifier id = decl.getIdentifier(); String name = id.name; Type type = decl.dispatch(this); if (type == null) continue; if (sym.declares(name)) { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); } if (type instanceof ClassVType || type instanceof ListValueType) {//Check for attribute type if (super_syms.contains(name)) {//Check for redefined superclass attribute errors.semError( id, "Cannot re-define attribute: %s", name); } else sym.put(name, type); } else if(type instanceof FuncValueType) {//For function declarations List params = ((FuncValueType)type).parameters; if(params.size() < 1 || (params.get(0) instanceof ClassVType==false) || ((ClassVType)params.get(0)).className.equals(current_class.className)==false) errors.semError( id, "First parameter of method must be of same class: %s", name); if (super_syms.contains(name)) { if ((super_scope.get(id.name) instanceof FuncValueType)==false) errors.semError(id, "Cannot re-define attribute: %s" + name); else { FuncValueType super_func = (FuncValueType) super_scope.get(id.name); FuncValueType current_func = (FuncValueType) type; if (compare_functions(super_func, current_func)) sym.put(name, type); else errors.semError( id, "Method overridden with different type signature: %s" + name); } } else sym.put(name, type); } } } for (String super_sym : super_syms) { if (sym.getDeclaredSymbols().contains(super_sym)==false) sym.put(super_sym, super_scope.get(super_sym)); } sym = sym.getParent(); current_class=null; return cvt; } @Override public Type analyze(VarDef node) { Type var_type = sym.get(node.var.identifier.name); if (node.var.identifier.name!=current_class.className && var_type==null) errors.semError( node, "Cannot re-define attribute: %s", node.var.identifier.name); return ValueType.annotationToValueType(node.var.type); } @Override public Type analyze(ListType node) { return ValueType.annotationToValueType(node); } }