Merge pull request #1 from nyu-compiler-construction/apoorva/semantic
Added semantic check for duplicate local variable declaration
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
# Compiler Construction PA2 Worklog
|
||||
|
||||
## Team:
|
||||
**Apoorva Ranade**(ar6496) **Sanjar Ahmadov**(sa5640) **Yinqi Sun**(ys3540)
|
||||
<br>
|
||||
|
||||
## Passes:
|
||||
-
|
||||
## Recovery:
|
||||
-
|
||||
|
||||
## Challenges:
|
||||
-
|
||||
## Improvements:
|
||||
- Added more tests to rigorously check program flow and indentation.
|
||||
@@ -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<Type> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<ValueType> parameters;
|
||||
/** Function's return type. */
|
||||
public final ValueType returnType;
|
||||
|
||||
|
||||
/** Create a FuncType returning RETURNTYPE0, initially parameterless. */
|
||||
public FuncType(ValueType returnType0) {
|
||||
this(new ArrayList<>(), returnType0);
|
||||
|
||||
@@ -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<ValueType> 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<ValueType> 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 "<function>";
|
||||
}
|
||||
}
|
||||
@@ -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<Type> {
|
||||
public class DeclarationAnalyzer extends AbstractNodeAnalyzer<Type>
|
||||
{
|
||||
|
||||
/** Current symbol table. Changes with new declarative region. */
|
||||
private final SymbolTable<Type> sym = new SymbolTable<>();
|
||||
private SymbolTable<Type> sym = new SymbolTable<>();
|
||||
/** Global symbol table. */
|
||||
private final SymbolTable<Type> 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<Type> 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<Type> getGlobals() {
|
||||
public SymbolTable<Type> 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(VarDef varDef) {
|
||||
return ValueType.annotationToValueType(varDef.var.type);
|
||||
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<fun1.parameters.size(); i++)
|
||||
if (fun1.parameters.get(i).equals(fun2.parameters.get(i))==false)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Type analyze(ClassDef node)
|
||||
{
|
||||
ClassVType cvt=new ClassVType(node.name.name);
|
||||
SymbolTable<Type> 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<Type> super_scope=null;
|
||||
Set<String> 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<ValueType> 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(ListType node)
|
||||
{
|
||||
return ValueType.annotationToValueType(node);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user