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> {
return this;
}
public void overwrite_put(String k, T v) {
tab.put(k, v);
}
/** Returns whether NAME has a mapping in this region (ignoring
* enclosing regions. */
public boolean declares(String name) {
......
......@@ -22,11 +22,25 @@ public class StudentAnalysis {
// declarationAnalyzer.getGlobals();
SymbolTable<SymbolType> globalSym = new SymbolTable<>();
//if (!program.hasErrors()) {
// TODO: I should run this part again and again, until symbolTable convergences.
TypeChecker symBuilder = new TypeChecker(globalSym, program.errors, true);
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()) {
TypeChecker next_time = new TypeChecker(symBuilder.getGlobals(), program.errors, false);
......
......@@ -24,7 +24,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
/** Collector for errors. */
private Errors errors;
private boolean isFirstRun;
private boolean isBuildingSym;
public boolean buildingSymDone;
/** Creates a type checker using GLOBALSYMBOLS for the initial global
* symbol table and ERRORS0 to receive semantic errors. */
......@@ -32,7 +33,8 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
sym = globalSymbols;
globals = sym;
errors = errors0;
isFirstRun = firstRun;
isBuildingSym = firstRun;
buildingSymDone = true;
}
public SymbolTable<SymbolType> getGlobals() {
return globals;
......@@ -42,15 +44,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
* The message is constructed with MESSAGE and ARGS as for
* String.format. */
private void err(Node node, String message, Object... args) {
if(!isFirstRun)
if(!isBuildingSym)
errors.semError(node, message, args);
}
///////////////////////////// Program //////////////////////////////////////
@Override
public SymbolType analyze(Program program) {
if(isFirstRun)
if(isBuildingSym) {
sym.put("object", OBJECT_TYPE);
sym.put("print", new FuncType(new ArrayList<ValueType>(Arrays.asList(OBJECT_TYPE)), NONE_TYPE));
}
for (Declaration decl : program.declarations) {
String name = decl.getIdentifier().name;
......@@ -64,11 +68,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
}
// TODO: DO NOT throw on duplicate id. generate a compiler error.
if(isFirstRun)
if(isBuildingSym)
sym.put(name, type);
}
if(isFirstRun)
if(isBuildingSym)
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
return null;
for (Stmt stmt : program.statements) {
......@@ -80,7 +84,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
///////////////////////////// Def&decl s //////////////////////////////////////
@Override
public SymbolType analyze(VarDef varDef) {
if(isFirstRun) {
if(isBuildingSym) {
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
return resolveTypeAnnotation(varDef.var.type);
}
......@@ -93,9 +97,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
@Override
public SymbolType analyze(ClassDef classDef) {
if(isFirstRun) {
assert classDef.memberMap == null;
classDef.memberMap = new HashMap<>(); // clearing may prevent symTable from convergence forever.
if(isBuildingSym) {
if(classDef.memberMap == null)
classDef.memberMap = new HashMap<>(); // clearing may prevent symTable from convergence forever.
}
assert classDef.memberMap != null;
......@@ -128,7 +132,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
for(Declaration decl : classDef.declarations) {
String name = decl.getIdentifier().name;
SymbolType type = decl.dispatch(this);
if(isFirstRun)
if(isBuildingSym)
classDef.memberMap.put(name, type);
}
System.out.println("debug: self_type=" + result_type.toString() + ", where symbolMap=" + result_type.memberMap);
......@@ -139,9 +143,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
@Override
public SymbolType analyze(FuncDef funcDef) {
if(isFirstRun) {
assert funcDef.symTable == null;
sym = funcDef.symTable = new SymbolTable<SymbolType>(sym);
if(isBuildingSym) {
if(funcDef.symTable == null)
funcDef.symTable = new SymbolTable<SymbolType>(sym);
sym = funcDef.symTable;
}
else
sym = funcDef.symTable;
......@@ -154,7 +159,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
ValueType type = resolveTypeAnnotation(param.type);
//if(typeIsUserDefinedClass(type))
// type = (ValueType) sym.get(((ClassValueType) type).className());
if(isFirstRun)
if(isBuildingSym)
sym.put(name, type);
args.add(type);
}
......@@ -162,11 +167,11 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
for(Declaration decl : funcDef.declarations) {
String name = decl.getIdentifier().name;
SymbolType type = decl.dispatch(this);
if(isFirstRun)
if(isBuildingSym)
sym.put(name, type);
}
if(!isFirstRun) {
if(!isBuildingSym) {
// firstRun: symbolTable and memberMap is not useable now. STOP dispatching to avoid crash.
for(Stmt stmt : funcDef.statements) {
stmt.dispatch(this);
......@@ -174,7 +179,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
}
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.
// TA don't like it. OK I won't dispatch this id...
......@@ -191,11 +196,17 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
public SymbolType analyze(GlobalDecl globalDecl) {
String name = globalDecl.variable.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..");
}
if(sym == globals) // ref equal
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;
}
......@@ -203,10 +214,16 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
public SymbolType analyze(NonLocalDecl nonLocalDecl) {
String name = nonLocalDecl.variable.name;
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..");
}
if(sym == globals)
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;
}
......@@ -414,7 +431,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
for(Expr arg : node.args) {
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());
}
return node.setInferredType(fType.returnType);
......@@ -511,7 +528,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
return NONE_TYPE;
}
//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.
SymbolType resultType = objType.memberMap.get(node.member.name);
if(resultType == null) {
......@@ -603,6 +620,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
return new ListValueType(elementType);
}
///////////////////////////// helpers ///////////////////////////////
private boolean typeConvertible(SymbolType from, SymbolType to) {
if(from == null || to == 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