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

global_forward pass

parent 2cf77637
No related branches found
No related tags found
No related merge requests found
Pipeline #50 passed with warnings with stages
in 3 minutes and 28 seconds
...@@ -47,6 +47,10 @@ public class SymbolTable<T> { ...@@ -47,6 +47,10 @@ public class SymbolTable<T> {
return this; return this;
} }
public void overwrite_put(String k, T v) {
tab.put(k, v);
}
/** Returns whether NAME has a mapping in this region (ignoring /** Returns whether NAME has a mapping in this region (ignoring
* enclosing regions. */ * enclosing regions. */
public boolean declares(String name) { public boolean declares(String name) {
......
...@@ -22,11 +22,25 @@ public class StudentAnalysis { ...@@ -22,11 +22,25 @@ public class StudentAnalysis {
// declarationAnalyzer.getGlobals(); // declarationAnalyzer.getGlobals();
SymbolTable<SymbolType> globalSym = new SymbolTable<>(); SymbolTable<SymbolType> globalSym = new SymbolTable<>();
//if (!program.hasErrors()) {
// TODO: I should run this part again and again, until symbolTable convergences. // TODO: I should run this part again and again, until symbolTable convergences.
TypeChecker symBuilder = new TypeChecker(globalSym, program.errors, true); TypeChecker symBuilder = new TypeChecker(globalSym, program.errors, true);
program.dispatch(symBuilder); program.dispatch(symBuilder);
//} // program.dispatch(symBuilder); // Twice run to update these use-before-decl globalDecl/nonlocalDecl symTable entry.
// note: thanks to the silly grammar, it doesn't allow type-deduction.
// so we can support use-before-decl by only one extra run, rather than many many times.
// now globalDecl and nonLocalDecl relies to the second run.
// but we can just allow globalDecl and nonLocalDecl to update symTable on the typeCheckerRun below!
// what a silly design!
// def fuck():
// def shit():
// def func():
// nonlocal c
// # ...
// nonlocal b
// c:decltype(b) = None
// nonlocal a
// b:decltype(a) = None
if(!program.hasErrors()) { if(!program.hasErrors()) {
TypeChecker next_time = new TypeChecker(symBuilder.getGlobals(), program.errors, false); TypeChecker next_time = new TypeChecker(symBuilder.getGlobals(), program.errors, false);
......
...@@ -24,7 +24,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -24,7 +24,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
/** Collector for errors. */ /** Collector for errors. */
private Errors errors; private Errors errors;
private boolean isFirstRun; private boolean isBuildingSym;
public boolean buildingSymDone;
/** Creates a type checker using GLOBALSYMBOLS for the initial global /** Creates a type checker using GLOBALSYMBOLS for the initial global
* symbol table and ERRORS0 to receive semantic errors. */ * symbol table and ERRORS0 to receive semantic errors. */
...@@ -32,7 +33,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -32,7 +33,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
sym = globalSymbols; sym = globalSymbols;
globals = sym; globals = sym;
errors = errors0; errors = errors0;
isFirstRun = firstRun; isBuildingSym = firstRun;
buildingSymDone = true;
} }
public SymbolTable<SymbolType> getGlobals() { public SymbolTable<SymbolType> getGlobals() {
return globals; return globals;
...@@ -42,15 +44,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -42,15 +44,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
* The message is constructed with MESSAGE and ARGS as for * The message is constructed with MESSAGE and ARGS as for
* String.format. */ * String.format. */
private void err(Node node, String message, Object... args) { private void err(Node node, String message, Object... args) {
if(!isFirstRun) if(!isBuildingSym)
errors.semError(node, message, args); errors.semError(node, message, args);
} }
///////////////////////////// Program ////////////////////////////////////// ///////////////////////////// Program //////////////////////////////////////
@Override @Override
public SymbolType analyze(Program program) { public SymbolType analyze(Program program) {
if(isFirstRun) if(isBuildingSym) {
sym.put("object", OBJECT_TYPE); sym.put("object", OBJECT_TYPE);
sym.put("print", new FuncType(new ArrayList<ValueType>(Arrays.asList(OBJECT_TYPE)), NONE_TYPE));
}
for (Declaration decl : program.declarations) { for (Declaration decl : program.declarations) {
String name = decl.getIdentifier().name; String name = decl.getIdentifier().name;
...@@ -64,11 +68,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -64,11 +68,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
} }
// TODO: DO NOT throw on duplicate id. generate a compiler error. // TODO: DO NOT throw on duplicate id. generate a compiler error.
if(isFirstRun) if(isBuildingSym)
sym.put(name, type); sym.put(name, type);
} }
if(isFirstRun) if(isBuildingSym)
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash. // firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
return null; return null;
for (Stmt stmt : program.statements) { for (Stmt stmt : program.statements) {
...@@ -80,7 +84,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -80,7 +84,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
///////////////////////////// Def&decl s ////////////////////////////////////// ///////////////////////////// Def&decl s //////////////////////////////////////
@Override @Override
public SymbolType analyze(VarDef varDef) { public SymbolType analyze(VarDef varDef) {
if(isFirstRun) { if(isBuildingSym) {
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash. // firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
return resolveTypeAnnotation(varDef.var.type); return resolveTypeAnnotation(varDef.var.type);
} }
...@@ -93,9 +97,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -93,9 +97,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
@Override @Override
public SymbolType analyze(ClassDef classDef) { public SymbolType analyze(ClassDef classDef) {
if(isFirstRun) { if(isBuildingSym) {
assert classDef.memberMap == null; if(classDef.memberMap == null)
classDef.memberMap = new HashMap<>(); // clearing may prevent symTable from convergence forever. classDef.memberMap = new HashMap<>(); // clearing may prevent symTable from convergence forever.
} }
assert classDef.memberMap != null; assert classDef.memberMap != null;
...@@ -128,7 +132,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -128,7 +132,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
for(Declaration decl : classDef.declarations) { for(Declaration decl : classDef.declarations) {
String name = decl.getIdentifier().name; String name = decl.getIdentifier().name;
SymbolType type = decl.dispatch(this); SymbolType type = decl.dispatch(this);
if(isFirstRun) if(isBuildingSym)
classDef.memberMap.put(name, type); classDef.memberMap.put(name, type);
} }
System.out.println("debug: self_type=" + result_type.toString() + ", where symbolMap=" + result_type.memberMap); System.out.println("debug: self_type=" + result_type.toString() + ", where symbolMap=" + result_type.memberMap);
...@@ -139,9 +143,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -139,9 +143,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
@Override @Override
public SymbolType analyze(FuncDef funcDef) { public SymbolType analyze(FuncDef funcDef) {
if(isFirstRun) { if(isBuildingSym) {
assert funcDef.symTable == null; if(funcDef.symTable == null)
sym = funcDef.symTable = new SymbolTable<SymbolType>(sym); funcDef.symTable = new SymbolTable<SymbolType>(sym);
sym = funcDef.symTable;
} }
else else
sym = funcDef.symTable; sym = funcDef.symTable;
...@@ -154,7 +159,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -154,7 +159,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
ValueType type = resolveTypeAnnotation(param.type); ValueType type = resolveTypeAnnotation(param.type);
//if(typeIsUserDefinedClass(type)) //if(typeIsUserDefinedClass(type))
// type = (ValueType) sym.get(((ClassValueType) type).className()); // type = (ValueType) sym.get(((ClassValueType) type).className());
if(isFirstRun) if(isBuildingSym)
sym.put(name, type); sym.put(name, type);
args.add(type); args.add(type);
} }
...@@ -162,11 +167,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -162,11 +167,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
for(Declaration decl : funcDef.declarations) { for(Declaration decl : funcDef.declarations) {
String name = decl.getIdentifier().name; String name = decl.getIdentifier().name;
SymbolType type = decl.dispatch(this); SymbolType type = decl.dispatch(this);
if(isFirstRun) if(isBuildingSym)
sym.put(name, type); sym.put(name, type);
} }
if(!isFirstRun) { if(!isBuildingSym) {
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash. // firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
for(Stmt stmt : funcDef.statements) { for(Stmt stmt : funcDef.statements) {
stmt.dispatch(this); stmt.dispatch(this);
...@@ -174,7 +179,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -174,7 +179,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
} }
FuncType funcT = new FuncType(args, resolveTypeAnnotation(funcDef.returnType)); FuncType funcT = new FuncType(args, resolveTypeAnnotation(funcDef.returnType));
if(isFirstRun) if(isBuildingSym)
sym.put(funcDef.name.name, funcT); // this funcdef should be add to both parentSym and localSym to support recursive func. sym.put(funcDef.name.name, funcT); // this funcdef should be add to both parentSym and localSym to support recursive func.
// TA don't like it. OK I won't dispatch this id... // TA don't like it. OK I won't dispatch this id...
...@@ -191,11 +196,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -191,11 +196,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
public SymbolType analyze(GlobalDecl globalDecl) { public SymbolType analyze(GlobalDecl globalDecl) {
String name = globalDecl.variable.name; String name = globalDecl.variable.name;
SymbolType T = globals.get(name); SymbolType T = globals.get(name);
if(T == null) System.out.println("DEBUG< GOL< " + isBuildingSym + " buildingSym, name=" + name + ", Type=" + T);
if(T == null) {
if(isBuildingSym)
return OBJECT_TYPE; // workaround for fucking use-before-decl
errors.semError(globalDecl, "global id '" + name + "' not found in global scope.."); errors.semError(globalDecl, "global id '" + name + "' not found in global scope..");
}
if(sym == globals) // ref equal if(sym == globals) // ref equal
errors.semError(globalDecl, "global declaration '" + name + "' not allowed in global scope."); errors.semError(globalDecl, "global declaration '" + name + "' not allowed in global scope.");
//sym.put(name, T); if(!isBuildingSym)
// dirty! see comment in StudentAnalysis.java
sym.overwrite_put(name, T);
return T; return T;
} }
...@@ -203,10 +214,16 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -203,10 +214,16 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
public SymbolType analyze(NonLocalDecl nonLocalDecl) { public SymbolType analyze(NonLocalDecl nonLocalDecl) {
String name = nonLocalDecl.variable.name; String name = nonLocalDecl.variable.name;
SymbolType T = sym.get(name); // auto-iterate through the tree. SymbolType T = sym.get(name); // auto-iterate through the tree.
if(T == null) if(T == null) {
if(isBuildingSym)
return OBJECT_TYPE;
errors.semError(nonLocalDecl, "nonlocal id '" + name + "' not found in parent scope.."); errors.semError(nonLocalDecl, "nonlocal id '" + name + "' not found in parent scope..");
}
if(sym == globals) if(sym == globals)
errors.semError(nonLocalDecl, "nonlocal declaration '" + name + "' not allowed in global scope."); errors.semError(nonLocalDecl, "nonlocal declaration '" + name + "' not allowed in global scope.");
if(!isBuildingSym)
// dirty! see comment in StudentAnalysis.java
sym.overwrite_put(name, T);
return T; return T;
} }
...@@ -414,7 +431,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -414,7 +431,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
for(Expr arg : node.args) { for(Expr arg : node.args) {
args_type.add(arg.dispatch(this)); args_type.add(arg.dispatch(this));
} }
if(!fType.parameters.equals(args_type)) { if(!matchArgList(args_type, fType.parameters)) {
err(node, "function parameter type list mismatch: " + node.function.name + ". Expected " + fType.parameters.toString() + ", got " + args_type.toString()); err(node, "function parameter type list mismatch: " + node.function.name + ". Expected " + fType.parameters.toString() + ", got " + args_type.toString());
} }
return node.setInferredType(fType.returnType); return node.setInferredType(fType.returnType);
...@@ -511,7 +528,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -511,7 +528,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
return NONE_TYPE; return NONE_TYPE;
} }
//System.out.println("manual lookup: memberMap=" + ((ClassValueType)sym.get(objType.toString())).memberMap ); //System.out.println("manual lookup: memberMap=" + ((ClassValueType)sym.get(objType.toString())).memberMap );
System.out.println("debug: isFirstRun=" + isFirstRun + ", memberMap=" + objType.memberMap + ", objtype=" + objType.toString()); System.out.println("debug: isBuildingSym=" + isBuildingSym + ", memberMap=" + objType.memberMap + ", objtype=" + objType.toString());
// Won't work. // Won't work.
SymbolType resultType = objType.memberMap.get(node.member.name); SymbolType resultType = objType.memberMap.get(node.member.name);
if(resultType == null) { if(resultType == null) {
...@@ -603,6 +620,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> { ...@@ -603,6 +620,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
return new ListValueType(elementType); return new ListValueType(elementType);
} }
///////////////////////////// helpers ///////////////////////////////
private boolean typeConvertible(SymbolType from, SymbolType to) { private boolean typeConvertible(SymbolType from, SymbolType to) {
if(from == null || to == null) if(from == null || to == null)
throw new RuntimeException("debug: SymbolType can not be null"); throw new RuntimeException("debug: SymbolType can not be null");
......
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