diff --git a/WORKLOG.md b/WORKLOG.md
new file mode 100644
index 0000000..eef9fd0
--- /dev/null
+++ b/WORKLOG.md
@@ -0,0 +1,15 @@
+# Compiler Construction PA2 Worklog
+
+## Team:
+**Apoorva Ranade**(ar6496) **Sanjar Ahmadov**(sa5640) **Yinqi Sun**(ys3540)
+
+
+## Passes:
+ -
+## Recovery:
+ -
+
+## Challenges:
+ -
+## Improvements:
+ - Added more tests to rigorously check program flow and indentation.
diff --git a/src/main/java/chocopy/common/analysis/types/ClassVType.java b/src/main/java/chocopy/common/analysis/types/ClassVType.java
new file mode 100644
index 0000000..af04de7
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/ClassVType.java
@@ -0,0 +1,56 @@
+package chocopy.common.analysis.types;
+
+import chocopy.common.astnodes.ClassType;
+import chocopy.common.astnodes.Identifier;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import chocopy.common.analysis.SymbolTable;
+import java.util.Objects;
+
+/** Represents the semantic value of a simple class reference. */
+public class ClassVType extends ValueType {
+
+ /** The name of the class. */
+ public final String className;
+ public SymbolTable scope;
+ public ClassVType super_class;
+ /** A class type for the class named CLASSNAME. */
+ @JsonCreator
+ public ClassVType(@JsonProperty String className) {
+ this.className = className;
+ }
+
+ /** A class type for the class referenced by CLASSTYPEANNOTATION. */
+ public ClassVType(ClassType classTypeAnnotation) {
+ this.className = classTypeAnnotation.className;
+ }
+
+ @Override
+ @JsonProperty
+ public String className() {
+ return className;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ClassVType classType = (ClassVType) o;
+ return Objects.equals(className, classType.className);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(className);
+ }
+
+ @Override
+ public String toString() {
+ return className;
+ }
+}
diff --git a/src/main/java/chocopy/common/analysis/types/FuncType.java b/src/main/java/chocopy/common/analysis/types/FuncType.java
index 69fdefc..7d0f7a5 100644
--- a/src/main/java/chocopy/common/analysis/types/FuncType.java
+++ b/src/main/java/chocopy/common/analysis/types/FuncType.java
@@ -8,11 +8,13 @@ import java.util.List;
/** Semantic information for a function or method. */
public class FuncType extends Type {
+
/** Types of parameters. */
public final List parameters;
/** Function's return type. */
public final ValueType returnType;
+
/** Create a FuncType returning RETURNTYPE0, initially parameterless. */
public FuncType(ValueType returnType0) {
this(new ArrayList<>(), returnType0);
diff --git a/src/main/java/chocopy/common/analysis/types/FuncValueType.java b/src/main/java/chocopy/common/analysis/types/FuncValueType.java
new file mode 100644
index 0000000..5e73b46
--- /dev/null
+++ b/src/main/java/chocopy/common/analysis/types/FuncValueType.java
@@ -0,0 +1,49 @@
+package chocopy.common.analysis.types;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Semantic information for a function or method. */
+public class FuncValueType extends Type {
+
+ /** Function's name. */
+ //public final String name;
+
+ /** Types of parameters. */
+ public List parameters;
+ /** Function's return type. */
+ public final ValueType returnType;
+
+
+ /** Create a FuncType returning RETURNTYPE0, initially parameterless. */
+ public FuncValueType(ValueType returnType0) {
+ this(new ArrayList<>(), returnType0);
+ }
+
+ /**
+ * Create a FuncType for NAME0 with formal parameter types PARAMETERS0, returning type
+ * RETURNTYPE0.
+ */
+ @JsonCreator
+ public FuncValueType(List parameters0, ValueType returnType0) {
+ this.parameters = parameters0;
+ this.returnType = returnType0;
+ }
+
+ @Override
+ public boolean isFuncType() {
+ return true;
+ }
+
+ /** Return the type of the K-th parameter. */
+ public ValueType getParamType(int k) {
+ return parameters.get(k);
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+}
diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
index 29aaf5a..d2e5fc3 100644
--- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
+++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
@@ -2,54 +2,278 @@ package chocopy.pa2;
import chocopy.common.analysis.AbstractNodeAnalyzer;
import chocopy.common.analysis.SymbolTable;
-import chocopy.common.analysis.types.Type;
-import chocopy.common.analysis.types.ValueType;
+import chocopy.common.analysis.types.*;
import chocopy.common.astnodes.*;
-
+import java.util.*;
/** Analyzes declarations to create a top-level symbol table. */
-public class DeclarationAnalyzer extends AbstractNodeAnalyzer {
+public class DeclarationAnalyzer extends AbstractNodeAnalyzer
+{
/** Current symbol table. Changes with new declarative region. */
- private final SymbolTable sym = new SymbolTable<>();
+ private SymbolTable sym = new SymbolTable<>();
/** Global symbol table. */
private final SymbolTable globals = sym;
/** Receiver for semantic error messages. */
private final Errors errors;
-
+ private ClassVType current_class=null;
/** A new declaration analyzer sending errors to ERRORS0. */
- public DeclarationAnalyzer(Errors errors0) {
+ public DeclarationAnalyzer(Errors errors0)
+ {
errors = errors0;
+ ClassVType cvt = new ClassVType("object");
+ FuncValueType init = new FuncValueType(Type.OBJECT_TYPE);
+ init.parameters.add(Type.OBJECT_TYPE);
+ SymbolTable cvt_scope=new SymbolTable<>(sym);
+ cvt_scope.put("init",init);
+ cvt.scope=cvt_scope;
+ sym.put("object", cvt);
+ cvt = new ClassVType("int");
+ init = new FuncValueType(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);
+ cvt = new ClassVType("str");
+ init = new FuncValueType(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);
+ cvt = new ClassVType("bool");
+ init = new FuncValueType(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);
}
- public SymbolTable getGlobals() {
+ public SymbolTable getGlobals()
+ {
return globals;
}
@Override
- public Type analyze(Program program) {
- for (Declaration decl : program.declarations) {
+ public Type analyze(Program program)
+ {
+ for (Declaration decl : program.declarations)
+ {
Identifier id = decl.getIdentifier();
String name = id.name;
-
Type type = decl.dispatch(this);
-
- if (type == null) {
+
+ if (type == null)
+ {
continue;
}
- if (sym.declares(name)) {
+ if (sym.declares(name))
+ {
errors.semError(
id, "Duplicate declaration of identifier in same " + "scope: %s", name);
- } else {
+ }
+ else if (sym.get(name)!= null && sym.get(name) instanceof ClassVType)
+ {
+ errors.semError(
+ id, "Cannot shadow class name: %s", name);
+ continue;
+ }
+ else
+ {
sym.put(name, type);
}
}
-
+ // Check for return statements at top
+ for (Stmt stmt : program.statements)
+ {
+ if (stmt instanceof ReturnStmt)
+ errors.semError(
+ stmt, "Return statement cannot appear at the top level");
+ }
return null;
}
+ @Override
+ public Type analyze(FuncDef node) {
+ FuncValueType current_func=new FuncValueType((ValueType) node.returnType.dispatch(this));
+ SymbolTable current_scope=new SymbolTable<>(sym);
+ sym=current_scope;
+ for (TypedVar param : node.params)
+ {
+
+ if (sym.declares(param.identifier.name))
+ {
+ errors.semError(
+ node.name, "Duplicate declaration of identifier in same " + "scope: %s", param.identifier.name);
+ continue;
+ }
+ else if (sym.get(param.identifier.name)!= null && sym.get(param.identifier.name) instanceof ClassVType)
+ {
+ errors.semError(
+ param.identifier, "Cannot shadow class name: %s", param.identifier.name);
+ continue;
+ }
+
+ Type p = param.dispatch(this);
+ current_func.parameters.add((ValueType)p);
+ sym.put(param.identifier.name, p);
+ }
+
+ for (Declaration decl : node.declarations)
+ {
+ Identifier id = decl.getIdentifier();
+ String name = id.name;
+ Type type = decl.dispatch(this);
+
+ if (type == null)
+ {
+ continue;
+ }
+ if (sym.declares(name))
+ {
+ errors.semError(
+ id, "Duplicate declaration of identifier in same " + "scope: %s", name);
+ continue;
+ }
+ else if (sym.get(name)!= null && sym.get(name) instanceof ClassVType)
+ {
+ errors.semError(id, "Cannot shadow class name: %s", name);
+ continue;
+ }
+ else
+ {
+ sym.put(name, type);
+ }
+ }
+ /*for(String s:sym.getDeclaredSymbols())
+ System.out.println(" "+s);*/
+ sym = sym.getParent();
+ return current_func;
+ }
+ @Override
+ public Type analyze(GlobalDecl node)
+ {
+ if (globals.declares(node.variable.name)==false)
+ {
+ errors.semError(
+ node.variable, "Not a global variable: %s", node.variable.name);
+ return null;
+ }
+ return globals.get(node.variable.name);
+ }
+ public boolean compare_functions(FuncValueType fun1, FuncValueType fun2) {
+ if (fun1.returnType.equals(fun2.returnType)==false)
+ return false;
+ if (fun1.parameters.size() != fun2.parameters.size())
+ return false;
+ for (int i=1; i current_scope=new SymbolTable<>(sym);
+ sym=current_scope;
+ current_class=cvt;
+ Type super_class = sym.get(node.superClass.name);
+ cvt.super_class = (ClassVType)super_class;
+ SymbolTable super_scope=null;
+ Set super_syms=null;
+ if (super_class == null)
+ {
+ errors.semError(
+ node.name, "Super-class not defined: %s", node.superClass.name);
+ }
+ else if ((super_class instanceof ClassVType)==false)
+ {
+ errors.semError(
+ node.name, "Super-class must be a class: %s", node.superClass.name);
+ }
+ else if (node.superClass.name.equals("int") || node.superClass.name.equals("bool") || node.superClass.name.equals("str"))
+ {
+ errors.semError(
+ node.name, "Cannot extend special class: %s", node.superClass.name);
+ }
+ else
+ {
+ super_scope = cvt.super_class.scope;
+ super_syms = super_scope.getDeclaredSymbols();
+ for (Declaration decl : node.declarations)
+ {
+ Identifier id = decl.getIdentifier();
+ String name = id.name;
+ Type type = decl.dispatch(this);
+
+ if (type == null)
+ continue;
+
+ if (sym.declares(name))
+ {
+ errors.semError(
+ id, "Duplicate declaration of identifier in same " + "scope: %s", name);
+ }
+ if (type instanceof ClassVType || type instanceof ListValueType)
+ {//Check for attribute type
+ if (super_syms.contains(name))
+ {//Check for redefined superclass attribute
+ errors.semError(
+ id, "Cannot re-define attribute: %s", name);
+ }
+ else
+ sym.put(name, type);
+ }
+ else if(type instanceof FuncValueType)
+ {//For function declarations
+ List params = ((FuncValueType)type).parameters;
+ if(params.size() < 1 || (params.get(0) instanceof ClassVType==false) || ((ClassVType)params.get(0)).className.equals(current_class.className)==false)
+ errors.semError(
+ id, "First parameter of method must be of same class: %s", name);
+ if (super_syms.contains(name))
+ {
+ if ((super_scope.get(id.name) instanceof FuncValueType)==false)
+ errors.semError(id, "Cannot re-define attribute: %s" + name);
+ else
+ {
+ FuncValueType super_func = (FuncValueType) super_scope.get(id.name);
+ FuncValueType current_func = (FuncValueType) type;
+ if (compare_functions(super_func, current_func))
+ sym.put(name, type);
+ else
+ errors.semError(
+ id, "Method overridden with different type signature: %s" + name);
+ }
+ }
+ else
+ sym.put(name, type);
+ }
+ }
+ }
+ for (String super_sym : super_syms)
+ {
+ if (sym.getDeclaredSymbols().contains(super_sym)==false)
+ sym.put(super_sym, super_scope.get(super_sym));
+ }
+ sym = sym.getParent();
+ current_class=null;
+ return cvt;
+ }
+ @Override
+ public Type analyze(VarDef node)
+ {
+ Type var_type = sym.get(node.var.identifier.name);
+ if (node.var.identifier.name!=current_class.className && var_type==null)
+ errors.semError(
+ node, "Cannot re-define attribute: %s", node.var.identifier.name);
+ return ValueType.annotationToValueType(node.var.type);
+ }
@Override
- public Type analyze(VarDef varDef) {
- return ValueType.annotationToValueType(varDef.var.type);
+ public Type analyze(ListType node)
+ {
+ return ValueType.annotationToValueType(node);
}
}