Skip to content
Snippets Groups Projects
Verified Commit 0afe8c44 authored by Recolic Keghart's avatar Recolic Keghart
Browse files

parent class, class memberMap fixes, etc

parent d080332c
No related branches found
No related tags found
No related merge requests found
Pipeline #48 passed with warnings with stages
in 4 minutes and 13 seconds
package chocopy.common.analysis;
import org.apache.tools.ant.taskdefs.PathConvert;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
......@@ -66,4 +68,13 @@ public class SymbolTable<T> {
return tab.isEmpty();
}
public String toString() {
String res = "{";
for(String k : tab.keySet()) {
res += k + "->" + tab.get(k).toString() + ";";
}
res += "}";
return res;
}
}
......@@ -23,12 +23,13 @@ public class StudentAnalysis {
SymbolTable<SymbolType> globalSym = new SymbolTable<>();
//if (!program.hasErrors()) {
TypeChecker typeChecker = new TypeChecker(globalSym, program.errors, true);
program.dispatch(typeChecker);
// TODO: I should run this part again and again, until symbolTable convergences.
TypeChecker symBuilder = new TypeChecker(globalSym, program.errors, true);
program.dispatch(symBuilder);
//}
if(!program.hasErrors()) {
TypeChecker next_time = new TypeChecker(typeChecker.getGlobals(), program.errors, false);
TypeChecker next_time = new TypeChecker(symBuilder.getGlobals(), program.errors, false);
program.dispatch(next_time);
}
......
......@@ -67,6 +67,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
if(isFirstRun)
sym.put(name, type);
}
if(isFirstRun)
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
return null;
for (Stmt stmt : program.statements) {
stmt.dispatch(this);
}
......@@ -76,6 +80,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
///////////////////////////// Def&decl s //////////////////////////////////////
@Override
public SymbolType analyze(VarDef varDef) {
if(isFirstRun) {
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
return resolveTypeAnnotation(varDef.var.type);
}
SymbolType lType = varDef.value.dispatch(this);
SymbolType vType = varDef.var.dispatch(this);
if(!(vType.equals(lType) || lType.equals(NONE_TYPE)))
......@@ -87,7 +95,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
public SymbolType analyze(ClassDef classDef) {
if(isFirstRun) {
assert classDef.memberMap == null;
classDef.memberMap = new HashMap<>();
classDef.memberMap = new HashMap<>(); // clearing may prevent symTable from convergence forever.
}
assert classDef.memberMap != null;
......@@ -95,9 +103,24 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
// TA doesn't like this: // classDef.name.dispatch(this);
// TA doesn't like this: // classDef.superClass.dispatch(this);
// Append parent to child if not exist.
if(!classDef.superClass.name.equals("object")) {
// This logic doesn't allow superClass use-before-decl, unless loop again and again until convergence.
ClassValueType superClassType = (ClassValueType) sym.get(classDef.superClass.name);
if(superClassType.memberMap != null) {
for(String k : superClassType.memberMap.keySet()) {
if(!classDef.memberMap.containsKey(k))
classDef.memberMap.put(k, superClassType.memberMap.get(k));
}
}
}
ClassValueType result_type = new ClassValueType(classDef.name.name);
result_type.memberMap = classDef.memberMap;
SymbolTable<SymbolType> symLayer = new SymbolTable<>(sym);
// TODO: Maybe this is not necessary. I'm a cxx programmer.
symLayer.put("self", result_type);
System.out.println("debug: self_type=" + result_type.toString() + ", where symbolMap=" + result_type.memberMap);
sym = symLayer;
for(Declaration decl : classDef.declarations) {
......@@ -106,9 +129,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
if(isFirstRun)
classDef.memberMap.put(name, type);
}
System.out.println("debug: self_type=" + result_type.toString() + ", where symbolMap=" + result_type.memberMap);
sym = sym.getParent();
return new ClassValueType(classDef.name.name);
return result_type;
}
@Override
......@@ -125,7 +149,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
List<ValueType> args = new ArrayList<>();
for(TypedVar param : funcDef.params) {
String name = param.identifier.name;
ValueType type = ValueType.annotationToValueType(param.type);
ValueType type = resolveTypeAnnotation(param.type);
//if(typeIsUserDefinedClass(type))
// type = (ValueType) sym.get(((ClassValueType) type).className());
if(isFirstRun)
sym.put(name, type);
args.add(type);
......@@ -138,11 +164,14 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
sym.put(name, type);
}
for(Stmt stmt : funcDef.statements) {
stmt.dispatch(this);
if(!isFirstRun) {
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
for(Stmt stmt : funcDef.statements) {
stmt.dispatch(this);
}
}
FuncType funcT = new FuncType(args, ValueType.annotationToValueType(funcDef.returnType));
FuncType funcT = new FuncType(args, resolveTypeAnnotation(funcDef.returnType));
if(isFirstRun)
sym.put(funcDef.name.name, funcT); // this funcdef should be add to both parentSym and localSym to support recursive func.
......@@ -217,7 +246,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
left_type = id.dispatch(this);
}
else {
err(node, "Not implemented assignStmt");
err(node, "Not implemented assignStmt, target=" + target.getClass().getName());
}
if(left_type == null) {
err(node, "Syntax error: assign to non-declared variable");
......@@ -475,7 +504,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
err(node, ". operator left operand is not object type.");
return NONE_TYPE;
}
SymbolType resultType = objType.memberMap.get(node.member.name); // currently won't work. classDef not analyzed.
//System.out.println("manual lookup: memberMap=" + ((ClassValueType)sym.get(objType.toString())).memberMap );
System.out.println("debug: isFirstRun=" + isFirstRun + ", memberMap=" + objType.memberMap + ", objtype=" + objType.toString());
// Won't work.
SymbolType resultType = objType.memberMap.get(node.member.name);
if(resultType == null) {
err(node, "undefined identifier " + node.member.name + " as object member.");
return NONE_TYPE;
......@@ -485,11 +517,13 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
@Override
public SymbolType analyze(MethodCallExpr node) {
FuncType funcType = (FuncType) node.method.dispatch(this);
if(funcType == null) {
err(node, "method is not callable.");
SymbolType methodType = node.method.dispatch(this);
if(!( methodType instanceof FuncType)) {
err(node, "method is not callable or not found.");
return NONE_TYPE;
}
FuncType funcType = (FuncType) methodType;
List<SymbolType> args_type = new ArrayList<>();
for(Expr expr : node.args) {
args_type.add(expr.dispatch(this));
......@@ -511,6 +545,12 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
}
System.out.println("var " + varName + "->" + varType.toString());
if(varType instanceof ClassValueType) {
// TODO: This is just a workaround. I don't know why this line is required.
// Should debug it sometime.
varType = fixClassTypeProblem((ValueType) varType);
}
if (varType != null) {
return id.setInferredType(varType);
}
......@@ -521,11 +561,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
@Override
public SymbolType analyze(TypedVar node) {
return ValueType.annotationToValueType(node.type);
SymbolType result_type = resolveTypeAnnotation(node.type);
//if(typeIsUserDefinedClass(result_type))
// result_type = sym.get(((ClassValueType)result_type).className());
return result_type;
}
@Override
public SymbolType analyze(ClassType node) {
return new ClassValueType(node.className);
// TODO: verify it.
throw new RuntimeException("TODO: not verified.");
//return new ClassValueType(node.className);
}
@Override
public SymbolType analyze(ListType node) {
......@@ -563,5 +609,33 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
return l;
return OBJECT_TYPE;
}
private boolean typeIsUserDefinedClass(SymbolType type) {
if(type instanceof ClassValueType) {
if(type.equals(INT_TYPE) || type.equals(BOOL_TYPE) || type.equals(STR_TYPE) || type.equals(NONE_TYPE) || type.equals(EMPTY_TYPE) || type.equals(OBJECT_TYPE))
return false;
if(type.isFuncType() || type.isListType())
return false;
return true;
}
else
return false;
}
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
return valType;
}
private ValueType resolveTypeAnnotation(TypeAnnotation annotation) {
return fixClassTypeProblem(ValueType.annotationToValueType(annotation));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment