Skip to content

Commit

Permalink
Completed typechecker.
Browse files Browse the repository at this point in the history
  • Loading branch information
aj-michael committed Apr 19, 2016
1 parent 660ec4b commit 22e6e55
Show file tree
Hide file tree
Showing 11 changed files with 55 additions and 44 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group 'edu.rosehulman.minijavac'
version '0.0.2'
version '0.0.3'

apply plugin: 'java'
apply plugin: 'application'
Expand Down
2 changes: 0 additions & 2 deletions src/main/cup/minijava.cup
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import edu.rosehulman.minijavac.ast.UnaryOperation.UnaryOperator;

import java_cup.runtime.*;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

parser code {:
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/rosehulman/minijavac/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public static void main(String args[]) throws Exception {
Program program = parser.parseProgram();
TypeChecker typechecker = new TypeChecker();
typechecker.isValid(program);
System.out.println(typechecker.getTypeCheckerLog());
typechecker.getTypeCheckerLog().forEach(System.out::println);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,16 @@ public List<String> typecheck(Scope scope) {
List<String> errors = new ArrayList<>();
errors.addAll(expression.typecheck(scope));
if (isDeclaration()) {
if (scope.containsLocalVariable(id)) {
errors.add("The variable " + id + " is already declared in the current scope.");
}
if (expression.getType(scope) == null) {
errors.add("Variable this is not declared.");
} else if (!expression.getType(scope).isA(type.get(), scope)) {
scope.declaredVariables.put(id, type.get());
errors.add("Cannot assign type " + expression.getType(scope) + " to variable " + id +
" of type " + type.get());
} else if (scope.containsVariable(id)) {
errors.add("The variable " + id + " is already declared in the current scope.");
scope.declaredVariables.put(id, type.get());
} else {
scope.declaredVariables.put(id, type.get());
" of type " + type.get());
}
scope.declaredVariables.put(id, type.get());
} else {
if (!scope.containsVariable(id)) {
errors.add("No variable named " + id + " exists in the current scope.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public List<String> typecheck(Scope scope) {
errors.add("The operand types, " + leftType + " and " + rightType + ", are not compatible for equality comparison");
}
} else {
System.out.println(scope.declaredVariables + " " + operator);
if (!left.getType(scope).isA(operator.operandType, scope)) {
errors.add("Left argument of type " + left.getType(scope) + " does not match expected type " +
operator.operandType + " for operator " + operator.name());
Expand Down
30 changes: 13 additions & 17 deletions src/main/java/edu/rosehulman/minijavac/ast/ClassDeclaration.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package edu.rosehulman.minijavac.ast;

import edu.rosehulman.minijavac.typechecker.Scope;
import edu.rosehulman.minijavac.typechecker.Type;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import edu.rosehulman.minijavac.typechecker.Scope;
import edu.rosehulman.minijavac.typechecker.Type;
import static java.util.stream.Collectors.toList;

public class ClassDeclaration {
public final String name;
Expand All @@ -26,27 +28,21 @@ public List<String> typecheck(Scope scope) {
for (MethodDeclaration md : methodDeclarations) {
if (scope.methods.containsKey(md.name)) {
errors.add("Cannot redeclare method " + md.name);
if (!md.canOverride(scope.getMethod(md.name))) {
errors.add("Cannot overload methods. Method " + md.name + " has different type signature than inherited method of the same name.");
}
} else if (scope.containsMethod(md.name) && !md.canOverride(scope.getMethod(md.name))) {
}
if (scope.containsMethod(md.name) && !md.canOverride(scope.getMethod(md.name))) {
errors.add("Cannot overload methods. Method " + md.name + " has different type signature than inherited method of the same name.");
} else {
scope.methods.put(md.name, md);
}
scope.methods.put(md.name, md);
}

return errors;
}

public List<String> typecheck15(Scope scope) {
List<String> errors = new ArrayList<>();
for(MethodDeclaration md : methodDeclarations) {
if (!(md instanceof MainMethodDeclaration) && !scope.containsClass(md.returnType)) {
System.out.println("$$$");
errors.add("Cannot find class named " + md.returnType);
}
}
public List<String> typecheckMore(Scope scope) {
List<String> errors = methodDeclarations.stream()
.filter(md -> !(md instanceof MainMethodDeclaration) && !scope.containsClass(md.returnType))
.map(md -> "Cannot find class named " + md.returnType)
.collect(toList());
return errors;
}

Expand All @@ -61,7 +57,7 @@ public List<String> typecheckAgain(Scope scope) {
scope.declaredVariables.put(cvd.name, new Type(cvd.type));
}
}
for (MethodDeclaration md : scope.methods.values()) {
for (MethodDeclaration md : methodDeclarations) {
errors.addAll(md.typecheck(new Scope(scope)));
}
return errors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public List<String> typecheck(Scope scope) {
errors.addAll(subject.typecheck(scope));

Scope classScope = scope.getClassScope(subject.getType(scope).type);
if(classScope == null || !classScope.containsMethod(methodName)) {
if (classScope == null || !classScope.containsMethod(methodName)) {
errors.add("No method named " + methodName + " found for class " + subject.getType(scope));
} else {
MethodDeclaration md = classScope.getMethod(methodName);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/rosehulman/minijavac/ast/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public List<String> typecheck() {
errors.addAll(cd.typecheck(classScope));
}
}
getClassDeclarations().forEach(cd -> errors.addAll(cd.typecheck15(programScope.classes.get(cd.name))));
getClassDeclarations().forEach(cd -> errors.addAll(cd.typecheckMore(programScope.classes.get(cd.name))));
getClassDeclarations().forEach(cd -> errors.addAll(cd.typecheckAgain(programScope.classes.get(cd.name))));
return errors;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class UnaryOperation implements Expression {
@Override
public List<String> typecheck(Scope scope) {
List<String> errors = new ArrayList<>();
if(!operators.isEmpty() && !operators.get(0).type.isA(expression.getType(scope), scope)) {
if (!operators.isEmpty() && !operators.get(0).type.isA(expression.getType(scope), scope)) {
errors.add("Operand type " + expression.getType(scope) + " is not compatible with expected type " + operators.get(0).type + " of operator " + operators.get(0));
}
errors.addAll(expression.typecheck(scope));
Expand All @@ -22,7 +22,11 @@ public List<String> typecheck(Scope scope) {

@Override
public Type getType(Scope scope) {
return expression.getType(scope);
if (operators.isEmpty()) {
return expression.getType(scope);
} else {
return operators.get(0).type;
}
}

public enum UnaryOperator {
Expand Down
28 changes: 22 additions & 6 deletions src/main/java/edu/rosehulman/minijavac/typechecker/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,39 @@ public class Scope {
public final Map<String, MethodDeclaration> methods = new LinkedHashMap<>();
public final Program program;
public final String className;
public final boolean isClass;

public Scope(Program program) {
this.program = program;
this.parent = Optional.empty();
this(program, Optional.empty(), null, false);
classes.put("int", null);
classes.put("boolean", null);
className = null;
}

public Scope(Scope parent) {
this(parent, parent.className);
this(parent.program, Optional.of(parent), parent.className, false);
}

public Scope(Scope parent, String className) {
this.program = parent.program;
this.parent = Optional.of(parent);
this(parent.program, Optional.of(parent), className, true);
}

private Scope(Program program, Optional<Scope> parent, String className, boolean isClass) {
this.program = program;
this.parent = parent;
this.className = className;
this.isClass = isClass;
}

public boolean containsLocalVariable(String name) {
if (isClass) {
return false;
} else if (declaredVariables.containsKey(name)) {
return true;
} else if (parent.isPresent()) {
return parent.get().containsLocalVariable(name);
} else {
return false;
}
}

public boolean containsVariable(String name) {
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/edu/rosehulman/minijavac/typechecker/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ public Type(String type) {
}

public boolean isA(Type otherType, Scope scope) {
if(isPrimitiveType() || otherType.isPrimitiveType()) {
if (isPrimitiveType() || otherType.isPrimitiveType()) {
return type.equals(otherType.type);
}

if(type.equals("null")) {
if (type.equals("null")) {
return true;
}

if(type.equals(otherType.type)) {
if (type.equals(otherType.type)) {
return true;
} else {
Scope classScope = scope.getClassScope(type);
if(classScope == null) {
if (classScope == null) {
return false;
}

Scope parentScope = classScope.parent.get();
if(parentScope.parent.isPresent()) {
if (parentScope.parent.isPresent()) {
return new Type(parentScope.className).isA(otherType, scope);
} else {
return false;
Expand Down

0 comments on commit 22e6e55

Please sign in to comment.