Final bug fixes.

Worklog.
Added test diff.py demonstrating the differences between the reference compiler.
This commit is contained in:
bill
2021-04-03 02:54:25 +08:00
parent 617dbdd3b5
commit c86e536fe3
11 changed files with 3052 additions and 106 deletions
@@ -4,7 +4,11 @@ import chocopy.common.analysis.AbstractNodeAnalyzer;
import chocopy.common.analysis.SymbolTable;
import chocopy.common.analysis.types.*;
import chocopy.common.astnodes.*;
import java_cup.runtime.Symbol;
import java.util.*;
import com.fasterxml.jackson.annotation.JacksonInject.Value;
/** Analyzes declarations to create a top-level symbol table. */
public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
{
@@ -22,61 +26,51 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
// In the second pass, typeAnalyzer will call declanalyzer to
// analyze local vars/func/class defs and create sub-scope symtable.
private ClassVType current_class=null;
private boolean postCheck = false;
private String classDefError = null;
/** A new declaration analyzer sending errors to ERRORS0. */
public void initScope(SymbolTable<Type> s){
// Symbol table entry for object class
ClassVType cvt = new ClassVType("object"), obj = cvt;
s.put("object", cvt);
//Symbol table entry for int class
cvt = new ClassVType("int");
cvt.super_class = obj;
s.put("int", cvt);
//Symbol table entry for str class
cvt = new ClassVType("str");
cvt.super_class = obj;
s.put("str", cvt);
//Symbol table entry for bool class
cvt = new ClassVType("bool");
cvt.super_class = obj;
s.put("bool", cvt);
//Symbol table entry for None return type
cvt = new ClassVType("<None>");
cvt.super_class = obj;
s.put("<None>", cvt);
//Symbol table entry for inbuilt print function
ArrayList<ValueType> param = new ArrayList<ValueType>();
param.add(Type.OBJECT_TYPE);
s.put("print", new FuncType(param, Type.NONE_TYPE));
//Symbol table entry for inbuilt len function
param = new ArrayList<ValueType>();
param.add(Type.OBJECT_TYPE);
s.put("len", new FuncType(param, Type.INT_TYPE));
//Symbol table entry for inbuilt input function
s.put("input", new FuncType(new ArrayList<>(), Type.STR_TYPE));
}
public SymbolTable<Type> createScope(SymbolTable<Type> s){
SymbolTable<Type> newScope = new SymbolTable<>(s);
initScope(newScope);
return newScope;
}
public DeclarationAnalyzer(Errors errors0)
{
firstPass = true;
errors = errors0;
globals = sym;
// Symbol table entry for object class
ClassVType cvt = new ClassVType("object"), obj = cvt;
FuncType init = new FuncType(Type.OBJECT_TYPE);
init.parameters.add(Type.OBJECT_TYPE);
SymbolTable<Type> cvt_scope=new SymbolTable<>(sym);
cvt_scope.put("init",init);
cvt.scope=cvt_scope;
sym.put("object", cvt);
//Symbol table entry for int class
cvt = new ClassVType("int");
cvt.super_class = obj;
init = new FuncType(Type.INT_TYPE);
init.parameters.add(Type.INT_TYPE);
cvt_scope=new SymbolTable<>(sym);
cvt_scope.put("init",init);
cvt.scope=cvt_scope;
sym.put("int", cvt);
//Symbol table entry for str class
cvt = new ClassVType("str");
cvt.super_class = obj;
init = new FuncType(Type.STR_TYPE);
init.parameters.add(Type.STR_TYPE);
cvt_scope=new SymbolTable<>(sym);
cvt_scope.put("init",init);
cvt.scope=cvt_scope;
sym.put("str", cvt);
//Symbol table entry for bool class
cvt = new ClassVType("bool");
cvt.super_class = obj;
init = new FuncType(Type.BOOL_TYPE);
init.parameters.add(Type.BOOL_TYPE);
cvt_scope=new SymbolTable<>(sym);
cvt_scope.put("init",init);
cvt.scope=cvt_scope;
sym.put("bool", cvt);
//Symbol table entry for None return type
cvt = new ClassVType("<None>");
cvt.super_class = obj;
sym.put("<None>", cvt);
//Symbol table entry for inbuilt print function
ArrayList<ValueType> param = new ArrayList<ValueType>();
param.add(Type.OBJECT_TYPE);
sym.put("print", new FuncType(param, Type.NONE_TYPE));
//Symbol table entry for inbuilt len function
param = new ArrayList<ValueType>();
param.add(Type.OBJECT_TYPE);
sym.put("len", new FuncType(param, Type.INT_TYPE));
//Symbol table entry for inbuilt input function
sym.put("input", new FuncType(new ArrayList<>(), Type.STR_TYPE));
initScope(sym);
typeChecker = new TypeChecker(globals, errors);
}
@@ -91,10 +85,10 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
{
return globals;
}
private void putSymChecked(Node node, String name, Type ty)
private boolean putSymChecked(Node node, String name, Type ty)
{
if (ty == null)
return;
return false;
if (globals.get(name)!= null && !(ty instanceof ClassVType) && globals.get(name) instanceof ClassVType) //class names are only in global scope
errors.semError(node, "Cannot shadow class name: %s", name);
@@ -102,7 +96,11 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
errors.semError(
node, "Duplicate declaration of identifier in same scope: %s", name);
else
{
sym.put(name, ty);
return true;
}
return false;
}
@Override
public Type analyze(Program program)
@@ -126,42 +124,53 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
@Override
public Type analyze(FuncDef node)
{
Type fTy = globals.get(node.name.name);
FuncType current_func=null;
if(!postCheck){
Type fTy = null;
if(sym.declares(node.name.name))
fTy = sym.get(node.name.name);
if(!(fTy instanceof FuncType))
{
if(fTy == null)
FuncType current_func=null;
if(!(fTy instanceof FuncType))
{
current_func = new FuncType(new ArrayList<ValueType>(),
ValueType.annotationToValueType(node.returnType));
for (TypedVar param : node.params)
if(fTy == null)
{
Type p = ValueType.annotationToValueType(param.type);
current_func.parameters.add((ValueType)p);
}
sym.put(node.name.name, current_func);
if(!firstPass)
{
SymbolTable<Type> parent = sym.getParent();
if(parent!=null && parent != globals){
parent.put(node.name.name, current_func);
current_func = new FuncType(new ArrayList<ValueType>(),
ValueType.annotationToValueType(node.returnType));
for (TypedVar param : node.params)
{
ValueType p = ValueType.annotationToValueType(param.type);
current_func.parameters.add(p);
if(classDefError != null && p.className().equals(classDefError))
errors.semError(param.type, "Invalid type annotation; there is no class named: %s", classDefError);
}
sym.put(node.name.name, current_func);
if(!firstPass)
{
SymbolTable<Type> parent = sym.getParent();
if(parent!=null && parent != globals){
parent.put(node.name.name, current_func);
}
}
}
else if(fTy instanceof ClassVType)
errors.semError(node.name, "Cannot shadow class name: %s", node.name.name);
else
errors.semError(
node.name, "Duplicate declaration of identifier in same scope: %s", node.name.name);
}
else if(fTy instanceof ClassVType)
errors.semError(node.name, "Cannot shadow class name: %s", node.name.name);
else
else if(firstPass || sym.declares(node.name.name))
errors.semError(
node.name, "Duplicate declaration of identifier in same scope: %s", node.name.name);
if(!firstPass){
}
return current_func;
} else {
postCheck = false;
}
else if(firstPass || sym.declares(node.name.name))
errors.semError(
node.name, "Duplicate declaration of identifier in same scope: %s", node.name.name);
if(!firstPass){
ValueType returnType = ValueType.annotationToValueType(node.returnType);
if(returnType!=null && !returnType.isSpecialType() && !returnType.isListType() && !(globals.get(returnType.className()) instanceof ClassVType))
errors.semError(
@@ -187,13 +196,14 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
decl.dispatch(this);
else
decl.dispatch(typeChecker);
for(Declaration decl : otherDefs)
decl.dispatch(this);
for(Declaration decl : otherDefs)
if(decl instanceof FuncDef)
decl.dispatch(typeChecker);
else
decl.dispatch(this);
return null;
}
return current_func;
}
public boolean compare_functions(FuncType fun1, FuncType fun2)
@@ -212,7 +222,10 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
public Type analyze(ClassDef node)
{
ClassVType cvt=new ClassVType(node.name.name);
SymbolTable<Type> current_scope=new SymbolTable<>(sym);
if(!putSymChecked(node.name, node.name.name, cvt))
classDefError = node.name.name;
SymbolTable<Type> current_scope=createScope(sym);
sym=current_scope;
current_class=cvt;
Type super_class = sym.get(node.superClass.name);
@@ -262,9 +275,10 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
errors.semError(id, "Method overridden with different type signature: __init__");
else
sym.put(name, current_func);
if(params.size() < 1 || (params.get(0) instanceof ClassValueType==false) || ((ClassValueType)params.get(0)).className().equals(current_class.className)==false)
if(params.size() < 1 || !(params.get(0) instanceof ClassValueType) || !((ClassValueType)params.get(0)).className().equals(current_class.className))
errors.semError(
id, "First parameter of the following method must be of the enclosing class: %s", name);
if(curr_syms.contains(name)){
errors.semError(id, "Duplicate declaration of identifier in same scope: %s", name);
}
@@ -303,7 +317,7 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
sym = sym.getParent();
current_class.scope = current_scope;
current_class=null;
putSymChecked(node.name, node.name.name, cvt);
classDefError = null;
return cvt;
}
boolean isVariableType(Type ty)
@@ -343,7 +357,8 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
Type varVType = sym.get(className);
if(!(className != null && varVType instanceof ClassVType))
errors.semError(node.var.type, "Invalid type annotation; there is no class named: %s", (className!=null?className:""));
else if(val_type!=Type.NONE_TYPE && !StudentAnalysis.subClassOf(varVType,val_type, sym))
else if((!val_type.equals(Type.NONE_TYPE) && !StudentAnalysis.subClassOf(varVType,val_type, sym))||
val_type.equals(Type.NONE_TYPE) && var_type.isSpecialType())
errors.semError(node, "Expected type `%s`; got type `%s`", varVType, val_type);
}
return var_type;
@@ -357,4 +372,7 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
{
this.current_class = current_class;
}
public void setPostCheck(){
postCheck = true;
}
}
@@ -90,7 +90,7 @@ public class StudentAnalysis {
TypeChecker typeChecker = new TypeChecker(globalSym, program.errors);
program.dispatch(typeChecker);
}
//System.out.println(program);
// System.out.println(program);
return program;
}
}
+43 -14
View File
@@ -15,6 +15,7 @@ import static chocopy.common.analysis.types.Type.INT_TYPE;
import static chocopy.common.analysis.types.Type.OBJECT_TYPE;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.text.StyledEditorKit.BoldAction;
@@ -33,7 +34,9 @@ public class TypeChecker extends AbstractNodeAnalyzer<Type> {
private boolean returned = false, member = false;
/** Collector for errors. */
private final Errors errors;
private Boolean assign = false;
private boolean assign = false;
private boolean declAnalyzed = false;
private final HashMap<FuncDef, SymbolTable<Type>> funcScopes;
/**
* Creates a type checker using GLOBALSYMBOLS for the initial global symbol table and ERRORS0 to
* receive semantic errors.
@@ -44,14 +47,23 @@ public class TypeChecker extends AbstractNodeAnalyzer<Type> {
errors = errors0;
currReturnType = null;
declAnalyzer = new DeclarationAnalyzer(errors0, this, globalSymbols);
funcScopes = new HashMap<>();
}
/**
* Inserts an error message in NODE if there isn't one already. The message is constructed with
* MESSAGE and ARGS as for String.format.
*/
boolean isVariableType(Type ty){
private boolean isVariableType(Type ty){
return ty.isSpecialType() || ty.equals(Type.OBJECT_TYPE);
}
public boolean pushDeclAnalyzed() {
boolean orig = declAnalyzed;
declAnalyzed = true;
return orig;
}
public void popDeclAnalyzed(boolean orig) {
declAnalyzed = orig;
}
private Type declAnalyze(Node node){
//if(currentScope != sym)
declAnalyzer.setScope(currentScope);
@@ -129,20 +141,37 @@ public class TypeChecker extends AbstractNodeAnalyzer<Type> {
public Type analyze(BooleanLiteral node) {
return node.setInferredType(Type.BOOL_TYPE);
}
public void dispatchFuncDef(FuncDef node, SymbolTable<Type> scope, boolean declAnalyzed){
boolean prevDeclAnalyzed = this.declAnalyzed;
this.declAnalyzed = declAnalyzed;
SymbolTable<Type> origScope = currentScope;
currentScope = scope;
node.dispatch(this);
currentScope = origScope;
this.declAnalyzed = prevDeclAnalyzed;
}
@Override
public Type analyze(FuncDef node) {
returned = false;
Type prevReturnType = this.currReturnType;
currentScope = new SymbolTable<>(currentScope);
this.currReturnType = ValueType.annotationToValueType(node.returnType);
declAnalyze(node);
for(Stmt st : node.statements)
st.dispatch(this);
SymbolTable<Type> origScope = currentScope;
if(funcScopes.get(node) != null)
System.out.println("error");
{
currentScope = declAnalyzer.createScope(currentScope);
funcScopes.put(node, currentScope);
declAnalyzer.setPostCheck();
declAnalyze(node);
//currentScope = funcScopes.get(node);
returned = false;
Type prevReturnType = this.currReturnType;
this.currReturnType = ValueType.annotationToValueType(node.returnType);
for(Stmt st : node.statements)
st.dispatch(this);
if(currReturnType != null && currReturnType.isSpecialType() && !returned)
err(node.name, "All paths in this function/method must have a return statement: %s", node.name.name);
this.currReturnType = prevReturnType;
currentScope = currentScope.getParent();
if(currReturnType != null && currReturnType.isSpecialType() && !returned)
err(node.name, "All paths in this function/method must have a return statement: %s", node.name.name);
this.currReturnType = prevReturnType;
}
currentScope = origScope;
return null;
}
@@ -274,7 +303,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<Type> {
ty = currentScope.get(((ClassValueType) ty).className());
if(ty instanceof ClassVType){
ClassVType classTy = (ClassVType) ty;
Type type = classTy.scope.get(node.member.name);
Type type = classTy.scope == null? null:classTy.scope.get(node.member.name);
if(type != null)
return node.setInferredType(type);
else