diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java index 8a135a4e8a1cfa868ac3b62a8a6dfd1b555ffbee..aa8724ad6eabf9c0c52c471a9e424ee04fd8f3d7 100644 --- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java +++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java @@ -82,6 +82,10 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<SymbolType> { 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.."); return new FuncType(ValueType.annotationToValueType(funcDef.returnType)); } diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java index 3aeb45c44ad88bb26a7220bf9d1b9c64ec6516bf..1bf1afa15c6f20ea29ce007f6d557d9e36676706 100644 --- a/src/main/java/chocopy/pa2/TypeChecker.java +++ b/src/main/java/chocopy/pa2/TypeChecker.java @@ -2,17 +2,14 @@ package chocopy.pa2; import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.SymbolTable; +import chocopy.common.analysis.types.FuncType; +import chocopy.common.analysis.types.ListValueType; import chocopy.common.analysis.types.SymbolType; import chocopy.common.analysis.types.ValueType; -import chocopy.common.astnodes.BinaryExpr; -import chocopy.common.astnodes.Declaration; -import chocopy.common.astnodes.Errors; -import chocopy.common.astnodes.ExprStmt; -import chocopy.common.astnodes.Identifier; -import chocopy.common.astnodes.IntegerLiteral; -import chocopy.common.astnodes.Node; -import chocopy.common.astnodes.Program; -import chocopy.common.astnodes.Stmt; +import chocopy.common.astnodes.*; +import org.jetbrains.annotations.NotNull; + +import java.util.*; import static chocopy.common.analysis.types.SymbolType.INT_TYPE; import static chocopy.common.analysis.types.SymbolType.OBJECT_TYPE; @@ -63,6 +60,48 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { public SymbolType analyze(IntegerLiteral i) { return i.setInferredType(SymbolType.INT_TYPE); } + @Override + public SymbolType analyze(StringLiteral node) { + return node.setInferredType(SymbolType.STR_TYPE); + } + @Override + public SymbolType analyze(NoneLiteral node) { + return node.setInferredType(SymbolType.NONE_TYPE); + } + @Override + public SymbolType analyze(BooleanLiteral node) { + return node.setInferredType(SymbolType.BOOL_TYPE); + } + + @Override + public SymbolType analyze(AssignStmt node) { + SymbolType right_type = node.value.dispatch(this); + if(right_type == null) + right_type = ValueType.NONE_TYPE; + if(node.targets.size() == 1) { + String target = node.targets.get(0).toString(); + System.out.println("debug: assign to target " + target); + SymbolType left_type = sym.get(target); + if(left_type == null) { + err(node, "Syntax error: assign to non-declared variable."); + return OBJECT_TYPE; + } + if(!left_type.equals(right_type)) { + err(node, "Syntax error: implicit type convertion not allowed."); + } + return right_type; + } + else { + if(!right_type.isListType()) { + err(node, "Syntax error: assign non-list type to list targets"); + return OBJECT_TYPE; + } + ListValueType right_ls_type = (ListValueType) right_type; + // TODO: assign list to list + err(node, "Not implemented error: assign list to list"); + return OBJECT_TYPE; + } + } @Override public SymbolType analyze(BinaryExpr node) { @@ -70,23 +109,6 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { SymbolType left_type = node.left.dispatch(this); SymbolType right_type = node.right.dispatch(this); - //switch (e.operator) { - //case "-": - //case "*": - //case "//": - //case "%": - // if (INT_TYPE.equals(t1) && INT_TYPE.equals(t2)) { - // return e.setInferredType(INT_TYPE); - // } else { - // err(e, "Cannot apply operator `%s` on types `%s` and `%s`", - // e.operator, t1, t2); - // return e.setInferredType(INT_TYPE); - // } - //default: - // return e.setInferredType(OBJECT_TYPE); - //} - - switch(op) { case "-": case "*": @@ -96,26 +118,31 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { case "<": case ">=": case "<=": - if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE) + if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE) { 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 != ValueType.BOOL_TYPE || right_type != ValueType.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 != ValueType.INT_TYPE && left_type != ValueType.STR_TYPE && ! left_type.isListType()) { err(node, "Syntax Error: operand of + should be INT or STR or LIST"); + } // fallthrough case "==": case "!=": case "is": - if(node.left.getInferredType() != node.right.getInferredType()) + if(node.left.getInferredType() != node.right.getInferredType()) { err(node, "Syntax Error: binary operator operand type mismatch"); + } break; default: err(node, "Syntax Error: binary operator operand type not supported."); + return OBJECT_TYPE; } // Now set target type. @@ -146,6 +173,28 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { return node.setInferredType(result_type); } + @Override + public SymbolType analyze(CallExpr node) { + SymbolType funcType = sym.get(node.function.name); + if(funcType == null) { + err(node, "calling undeclared function " + node.function.name); + return OBJECT_TYPE; + } + if(!funcType.isFuncType()) { + err(node, "calling non-function variable " + node.function.name); + return OBJECT_TYPE; + } + FuncType fType = (FuncType)funcType; + List<SymbolType> args_type = new ArrayList<SymbolType>(); + for(Expr arg : node.args) { + args_type.add(arg.dispatch(this)); + } + if(!fType.parameters.equals(args_type)) { + err(node, "function parameter type list mismatch: " + node.function.name + ". Expected " + fType.parameters.toString() + ", got " + args_type.toString()); + } + return node.setInferredType(fType.returnType); + } + @Override public SymbolType analyze(Identifier id) { String varName = id.name;