diff --git a/run.sh b/run.sh index d99c3395294356fac7a81b696461e7a2ca64c89b..3dcbe1dd40dc36886846dea85820453abc3561fb 100755 --- a/run.sh +++ b/run.sh @@ -13,6 +13,8 @@ elif [[ "$task" = type ]]; then java -cp "$classPath" chocopy.ChocoPy --pass=.s --out "$output" "$input" elif [[ "$task" = ass ]]; then java -cp "$classPath" chocopy.ChocoPy --pass=.s --dir src/test/data/pa2/sample --test +elif [[ "$task" = build ]]; then + mvn clean package > /dev/null 2>&1 && echo success || echo failed fi exit $? diff --git a/src/main/java/chocopy/pa2/StudentAnalysis.java b/src/main/java/chocopy/pa2/StudentAnalysis.java index 40aef9b4fe56066b1922726ba26ba30ae6e7bff9..0676798f61e5783947f0db46bfcc50698ab622e9 100644 --- a/src/main/java/chocopy/pa2/StudentAnalysis.java +++ b/src/main/java/chocopy/pa2/StudentAnalysis.java @@ -15,11 +15,12 @@ public class StudentAnalysis { return program; } - DeclarationAnalyzer declarationAnalyzer = - new DeclarationAnalyzer(program.errors); - program.dispatch(declarationAnalyzer); - SymbolTable<SymbolType> globalSym = - declarationAnalyzer.getGlobals(); + //DeclarationAnalyzer declarationAnalyzer = + // new DeclarationAnalyzer(program.errors); + //program.dispatch(declarationAnalyzer); + //SymbolTable<SymbolType> globalSym = + // declarationAnalyzer.getGlobals(); + SymbolTable<SymbolType> globalSym = new SymbolTable<>(); if (!program.hasErrors()) { TypeChecker typeChecker = diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java index 3a915a3df6e4d5c04dbacf5d00240ea8ad027824..8f97c7f25cb505f0ee899d62c6e16c678cd0b02d 100644 --- a/src/main/java/chocopy/pa2/TypeChecker.java +++ b/src/main/java/chocopy/pa2/TypeChecker.java @@ -15,11 +15,15 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { /** The current symbol table (changes depending on the function * being analyzed). */ - private SymbolTable<SymbolType> sym; +// private SymbolTable<SymbolType> sym; + + /** Current symbol table. Changes with new declarative region. */ + private SymbolTable<SymbolType> sym = new SymbolTable<>(); + /** Global symbol table. */ + private final SymbolTable<SymbolType> globals = sym; /** Collector for errors. */ private Errors errors; - /** Creates a type checker using GLOBALSYMBOLS for the initial global * symbol table and ERRORS0 to receive semantic errors. */ public TypeChecker(SymbolTable<SymbolType> globalSymbols, Errors errors0) { @@ -34,10 +38,112 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { errors.semError(node, message, args); } + @Override + public SymbolType analyze(VarDef varDef) { + SymbolType lType = varDef.value.dispatch(this); + SymbolType vType = varDef.var.dispatch(this); + if(!vType.equals(lType)) + err(varDef, "incorrect initialization type"); + return lType; + } + + @Override + public SymbolType analyze(ClassDef classDef) { + assert classDef.memberMap == null; + classDef.memberMap = new HashMap<>(); + assert classDef.memberMap != null; + + ClassValueType result_type = new ClassValueType(classDef.name.name); + SymbolTable<SymbolType> symLayer = new SymbolTable<>(sym); + symLayer.put("self", result_type); + sym = symLayer; + + for(Declaration decl : classDef.declarations) { + String name = decl.getIdentifier().name; + SymbolType type = decl.dispatch(this); + classDef.memberMap.put(name, type); + } + + sym = sym.getParent(); + return new ClassValueType(classDef.name.name); + } + + @Override + public SymbolType analyze(FuncDef funcDef) { + System.out.println("debug: start funcDef: " + funcDef.getClass().getName()); + assert funcDef.symTable == null; + sym = funcDef.symTable = new SymbolTable<SymbolType>(sym); + assert funcDef.symTable != null; // may suck if partial-compiling happens... + + // Func parameter list + List<ValueType> args = new ArrayList<>(); + for(TypedVar param : funcDef.params) { + String name = param.identifier.name; + ValueType type = ValueType.annotationToValueType(param.type); + sym.put(name, type); + args.add(type); + } + + for(Declaration decl : funcDef.declarations) { + String name = decl.getIdentifier().name; + SymbolType type = decl.dispatch(this); + sym.put(name, type); + } + + // function scope ends.. backtracking... + sym = sym.getParent(); + if(sym == null) + throw new RuntimeException("logic error: sym parent is null while returning.."); + FuncType funcT = new FuncType(args, ValueType.annotationToValueType(funcDef.returnType)); + return funcT; + } + + @Override + public SymbolType analyze(GlobalDecl globalDecl) { + String name = globalDecl.variable.name; + SymbolType T = globals.get(name); + if(T == null) + errors.semError(globalDecl, "global id '" + name + "' not found in global scope.."); + if(sym == globals) // ref equal + errors.semError(globalDecl, "global declaration '" + name + "' not allowed in global scope."); + //sym.put(name, T); + return T; + } + + @Override + public SymbolType analyze(NonLocalDecl nonLocalDecl) { + String name = nonLocalDecl.variable.name; + SymbolType T = sym.get(name); // auto-iterate through the tree. + if(T == null) + errors.semError(nonLocalDecl, "nonlocal id '" + name + "' not found in parent scope.."); + if(sym == globals) + errors.semError(nonLocalDecl, "nonlocal declaration '" + name + "' not allowed in global scope."); + return T; + } + + // Just a helper.. + @Override + public SymbolType analyze(TypedVar node) { + return ValueType.annotationToValueType(node.type); + } + + ///////// end + @Override public SymbolType analyze(Program program) { for (Declaration decl : program.declarations) { - decl.dispatch(this); + String name = decl.getIdentifier().name; + + SymbolType type = decl.dispatch(this); + System.out.println("decl type " + type.toString()); + + // recolic: what's the teacher willing to do??? + if (type == null) { + continue; + } + + // TODO: DO NOT throw on duplicate id. generate a compiler error. + sym.put(name, type); } for (Stmt stmt : program.statements) { stmt.dispatch(this); @@ -52,12 +158,12 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { } @Override - public SymbolType analyze(IntegerLiteral i) { - return i.setInferredType(SymbolType.INT_TYPE); + public SymbolType analyze(IntegerLiteral node) { + return node.setInferredType(INT_TYPE); } @Override public SymbolType analyze(StringLiteral node) { - return node.setInferredType(SymbolType.STR_TYPE); + return node.setInferredType(STR_TYPE); } @Override public SymbolType analyze(NoneLiteral node) { @@ -65,7 +171,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { } @Override public SymbolType analyze(BooleanLiteral node) { - return node.setInferredType(SymbolType.BOOL_TYPE); + return node.setInferredType(BOOL_TYPE); } @Override @@ -117,18 +223,19 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { case "<": case ">=": case "<=": - if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE) { + if(!(left_type.equals(INT_TYPE) && right_type.equals(INT_TYPE))) { + System.out.println("debug: left=" + left_type.toString() + ", right=" + right_type.toString()); err(node, "Syntax Error: operand should be INT"); } break; case "and": case "or": - if(left_type != ValueType.BOOL_TYPE || right_type != ValueType.BOOL_TYPE) { + if(!(left_type.equals(BOOL_TYPE) && right_type.equals(BOOL_TYPE))) { err(node, "Syntax Error: operand should be BOOL"); } break; case "+": - if(left_type != ValueType.INT_TYPE && left_type != ValueType.STR_TYPE && ! left_type.isListType()) { + if(!(left_type.equals(INT_TYPE) || left_type.equals(STR_TYPE) || left_type.isListType())) { err(node, "Syntax Error: operand of + should be INT or STR or LIST"); } // fallthrough: do left-right match check. @@ -233,10 +340,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { public SymbolType analyze(IndexExpr node) { SymbolType list_type = node.list.dispatch(this); SymbolType index_type = node.index.dispatch(this); - if(index_type != INT_TYPE) { + if(!index_type.equals(INT_TYPE)) { err(node, "index_type should be int."); } - if(list_type == STR_TYPE) { + if(list_type.equals(STR_TYPE)) { return node.setInferredType(STR_TYPE); } else if(list_type.isListType()) { @@ -256,7 +363,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { SymbolType this_type = expr.dispatch(this); if(elementType == null) elementType = this_type; - if(this_type != elementType) + if(!this_type.equals(elementType)) err(node, "list elements must have the same type."); } ListValueType resultType = new ListValueType(elementType); @@ -299,6 +406,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { public SymbolType analyze(Identifier id) { String varName = id.name; SymbolType varType = sym.get(varName); + System.out.println("var " + varName + "->" + varType.toString()); if (varType != null && varType.isValueType()) { return id.setInferredType(varType);