From 2cf776372deb942d787c4e485f055f04a568c5c0 Mon Sep 17 00:00:00 2001 From: Recolic Keghart <root@recolic.net> Date: Mon, 8 Apr 2019 01:25:38 -0700 Subject: [PATCH] fix class inherit problems, fix type conversion, fix class member, fix some expr infer, etc --- .../common/analysis/types/ClassValueType.java | 8 +++ src/main/java/chocopy/pa2/TypeChecker.java | 69 +++++++++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/main/java/chocopy/common/analysis/types/ClassValueType.java b/src/main/java/chocopy/common/analysis/types/ClassValueType.java index c845503..0f01243 100644 --- a/src/main/java/chocopy/common/analysis/types/ClassValueType.java +++ b/src/main/java/chocopy/common/analysis/types/ClassValueType.java @@ -18,12 +18,20 @@ public class ClassValueType extends ValueType { @JsonIgnore public Map<String, SymbolType> memberMap = null; + @JsonIgnore + public ClassValueType parent = OBJECT_TYPE; + /** A class type for the class named CLASSNAME. */ @JsonCreator public ClassValueType(@JsonProperty String className) { this.className = className; } + public ClassValueType(String className, ClassValueType parentType) { + this.className = className; + parent = parentType; + } + /** A class type for the class referenced by CLASSTYPEANNOTATION. */ public ClassValueType(ClassType classTypeAnnotation) { this.className = classTypeAnnotation.className; diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java index 2b4ea8f..19a64f5 100644 --- a/src/main/java/chocopy/pa2/TypeChecker.java +++ b/src/main/java/chocopy/pa2/TypeChecker.java @@ -102,6 +102,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { // My-name already pushed to symbolMap // TA doesn't like this: // classDef.name.dispatch(this); // TA doesn't like this: // classDef.superClass.dispatch(this); + ClassValueType superType = (ClassValueType) classDef.superClass.dispatch(this); + classDef.superClass.setInferredType(null); // make TA happy // Append parent to child if not exist. if(!classDef.superClass.name.equals("object")) { @@ -115,7 +117,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { } } - ClassValueType result_type = new ClassValueType(classDef.name.name); + ClassValueType result_type = new ClassValueType(classDef.name.name, superType); result_type.memberMap = classDef.memberMap; SymbolTable<SymbolType> symLayer = new SymbolTable<>(sym); // TODO: Maybe this is not necessary. I'm a cxx programmer. @@ -245,6 +247,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { Identifier id = (Identifier) target; left_type = id.dispatch(this); } + else if(target instanceof MemberExpr) { + MemberExpr memberExpr = (MemberExpr) target; + left_type = memberExpr.dispatch(this); + } else { err(node, "Not implemented assignStmt, target=" + target.getClass().getName()); } @@ -512,7 +518,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { err(node, "undefined identifier " + node.member.name + " as object member."); return NONE_TYPE; } - return resultType; + return node.setInferredType(resultType); } @Override @@ -525,13 +531,31 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { FuncType funcType = (FuncType) methodType; List<SymbolType> args_type = new ArrayList<>(); + if(node.method instanceof MemberExpr) { + args_type.add(((MemberExpr)node.method).object.getInferredType()); + } for(Expr expr : node.args) { args_type.add(expr.dispatch(this)); } - if(!args_type.equals(funcType.parameters)) { - err(node, "function/method parameter list mismatch"); + + if(!matchArgList(args_type, funcType.parameters)) { + err(node, "function/method parameter list mismatch. Got " + args_type.toString() + ",expecting " + funcType.parameters); + } + return node.setInferredType(funcType.returnType); + } + private boolean matchArgList(List<SymbolType> got, List<ValueType> expect) { + System.out.println("debug> match arg> " + got + " -> " + expect + ", size " + got.size() + expect.size()); + if(got.size() != expect.size()) + return false; + for(int cter = 0; cter < got.size(); ++cter) { + System.out.println("debug> match arg> " + got.get(cter).toString() + " -> " + expect.get(cter).toString()); + if(typeConvertible(got.get(cter), expect.get(cter))) + continue; // ok + else + return false; } - return funcType.returnType; + System.out.println("debug> SUCC match arg> " + got + " -> " + expect + ", size " + got.size() + expect.size()); + return true; } ///////////////////////////// Others ////////////////////////////////////// @@ -587,14 +611,44 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { if(from.equals(EMPTY_TYPE)) from = new ListValueType(NONE_TYPE); if(to.equals(EMPTY_TYPE)) to = new ListValueType(NONE_TYPE); if(!from.isListType() || !to.isListType()) { + // Cast class to parent + if(from instanceof ClassValueType && to instanceof ClassValueType) { + if(_typeConvertible_calcClassInheritChainCommonNode((ClassValueType) from, (ClassValueType) to).equals(to)) + return true; // Can cast from->to + } return from.equals(to); } + // Convert list to list: ListValueType lsFrom = (ListValueType) from, lsTo = (ListValueType) to; if(lsFrom.elementType == null || lsFrom.elementType.equals(NONE_TYPE)) return true; return typeConvertible(lsFrom.elementType, lsTo.elementType); } + private ClassValueType _typeConvertible_calcClassInheritChainCommonNode(ClassValueType l, ClassValueType r) { + int l_depth = 1, r_depth = 1; + ClassValueType l_curr = l, r_curr = r; + while(!l_curr.equals(OBJECT_TYPE)) { + ++l_depth; + l_curr = l_curr.parent; + } + while(!r_curr.equals(OBJECT_TYPE)) { + ++r_depth; + r_curr = r_curr.parent; + } + l_curr = l; + r_curr = r; + for(;l_depth > r_depth; --l_depth) + l_curr = l_curr.parent; + for(;r_depth > l_depth; --r_depth) + r_curr = r_curr.parent; + while(!l_curr.equals(r_curr)) { // NOTE: Use reference compare + l_curr = l_curr.parent; + r_curr = r_curr.parent; + } + if(l_curr == null) return OBJECT_TYPE; + else return l_curr; + } private SymbolType calcCommonType(SymbolType another, SymbolType preferred) { SymbolType l = another, r = preferred; if(l == null || r == null) @@ -607,6 +661,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { return r; if(typeConvertible(r, l)) return l; + if(another instanceof ClassValueType && preferred instanceof ClassValueType) { + return _typeConvertible_calcClassInheritChainCommonNode((ClassValueType) another, (ClassValueType) preferred); + } return OBJECT_TYPE; } private boolean typeIsUserDefinedClass(SymbolType type) { @@ -622,13 +679,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { } private ValueType fixClassTypeProblem(ValueType valType) { if(typeIsUserDefinedClass(valType)) { - System.out.println("debug: annotation class name resolved." + valType.className()); ClassValueType realType = (ClassValueType)sym.get(valType.className()); if(realType == null) { System.out.println("FIXME: annotation uses an unknown class type. Unable to assign member map."); return valType; } - System.out.println("debug: -m- " + realType.memberMap); return realType; } else -- GitLab