Implemented TypeCheck

This commit is contained in:
ahmad 2024-05-01 11:01:37 +02:00
parent deeea62737
commit 5fa439ec90
25 changed files with 283 additions and 16 deletions

View File

@ -1,4 +1,11 @@
package de.maishai.ast; package de.maishai.ast;
import de.maishai.typedast.Type;
import de.maishai.ast.records.Class;
import java.util.Map;
public interface Node { public interface Node {
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes);
} }

View File

@ -1,3 +1,4 @@
package de.maishai.ast; package de.maishai.ast;
public interface Statement extends Node { public interface Statement extends Node {
} }

View File

@ -1,7 +0,0 @@
package de.maishai.ast;
public enum Type {
INT,
BOOL,
CHAR
}

View File

@ -3,6 +3,20 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record Assignment(Id loc, Expression value) implements Statement, Expression { public record Assignment(Id loc, Expression value) implements Statement, Expression {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
if (localVars.get(loc.name()) == null) {
throw new RuntimeException("Variable " + loc.name() + " not declared");
}
if (!localVars.get(loc.name()).equals(value.typeCheck(localVars, classes))) {
throw new RuntimeException("Type mismatch in assignment to " + loc.name());
}
return loc.typeCheck(localVars, classes);
}
} }

View File

@ -3,6 +3,17 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Operator; import de.maishai.ast.Operator;
import de.maishai.typedast.Type;
import java.util.Map;
public record Binary(Expression left, Operator op, Expression right) implements Expression { public record Binary(Expression left, Operator op, Expression right) implements Expression {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
// x = y + z -> y, z : int
if(left.typeCheck(localVars, classes) != Type.INT && right.typeCheck(localVars, classes) != Type.INT) {
throw new RuntimeException("Binary operation on non-integers");
}
return Type.INT;
}
} }

View File

@ -4,8 +4,23 @@ package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
public record Block(List<Variable> vars, List<Statement> stmts) implements Node { public record Block(List<Variable> vars, List<Statement> stmts) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
// Add the variables to the local variables
for (Variable var : vars) {
localVars.put(var.name(), var.type());
}
// Type check the statements
for (Statement stmt : stmts) {
stmt.typeCheck(localVars, classes);
}
// Return the type of the last statement
return stmts.get(stmts.size() - 1).typeCheck(localVars, classes);
}
} }

View File

@ -2,6 +2,13 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.typedast.Type;
import java.util.Map;
public record BoolConstant(Boolean value) implements Expression { public record BoolConstant(Boolean value) implements Expression {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return Type.BOOL;
}
} }

View File

@ -2,6 +2,13 @@ package de.maishai.ast.records;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record Break() implements Statement { public record Break() implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return Type.VOID;
}
} }

View File

@ -2,6 +2,13 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.typedast.Type;
import java.util.Map;
public record CharConstant(char value) implements Expression { public record CharConstant(char value) implements Expression {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return Type.CHAR;
}
} }

View File

@ -1,8 +1,25 @@
package de.maishai.ast.records; package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
public record Class(Id id ,List<Variable> variables, List<Method> methods) implements Node { public record Class(Id id ,List<Variable> variables, List<Method> methods) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
if(classes.containsKey(id.name())) {
throw new RuntimeException("Class " + id.name() + " already declared");
}
classes.put(id.name(), this);
for(Variable variable : variables) {
variable.typeCheck(localVars, classes);
}
for(Method method : methods) {
method.typeCheck(localVars, classes);
}
return Type.VOID;
}
} }

View File

@ -2,6 +2,13 @@ package de.maishai.ast.records;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record Continue() implements Statement { public record Continue() implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return Type.VOID;
}
} }

View File

@ -3,6 +3,21 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record For(Expression assign, Expression cond, Expression inc, Block block) implements Statement { public record For(Expression assign, Expression cond, Expression inc, Block block) implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
// like int i = 0
assign.typeCheck(localVars, classes);
// like i < 10 -> bool
if (cond.typeCheck(localVars, classes) != Type.BOOL) {
throw new RuntimeException("Condition must be of type bool");
}
// like i++
inc.typeCheck(localVars, classes);
return block.typeCheck(localVars, classes);
}
} }

View File

@ -2,6 +2,16 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.typedast.Type;
public record Id(String name) implements Expression { import java.util.Map;
}
public record Id(String name) implements Expression {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
if(!localVars.containsKey(name)) {
throw new RuntimeException("Variable " + name + " not declared");
}
return localVars.get(name);
}
}

View File

@ -2,5 +2,21 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record IfElse(Expression cond, Block ifBlock, Block elseBlock) implements Statement { public record IfElse(Expression cond, Block ifBlock, Block elseBlock) implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
// Con must be type bool and both blocks must have the same type
if(cond.typeCheck(localVars, classes).equals(Type.BOOL)
&& ifBlock.typeCheck(localVars, classes).equals(elseBlock.typeCheck(localVars, classes))) {
return ifBlock.typeCheck(localVars, classes);
}
throw new RuntimeException("IfElse statement type check failed");
}
} }

View File

@ -2,6 +2,13 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.typedast.Type;
import java.util.Map;
public record IntConstant(Integer value) implements Expression { public record IntConstant(Integer value) implements Expression {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return Type.INT;
}
} }

View File

@ -4,8 +4,15 @@ package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.ast.ReturnType; import de.maishai.ast.ReturnType;
import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
public record MainMethod(ReturnType type, Id id, List<Parameter> params, Block block) implements Node { public record MainMethod(ReturnType type, Id id, List<Parameter> params, Block block) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return null;
}
} }

View File

@ -1,11 +1,32 @@
package de.maishai.ast.records; package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.ast.ReturnType; import de.maishai.ast.ReturnType;
import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
public record Method(ReturnType type, Id id, List<Parameter> params, Block block) implements Node { public record Method(Type type, Id id, List<Parameter> params, Block block) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
if (localVars.containsKey(id.name())) {
throw new RuntimeException("Variable " + id.name() + " already declared");
}
localVars.put(id.name(), type);
for (Parameter parameter : params) {
parameter.typeCheck(localVars, classes);
}
Type returnType = block.typeCheck(localVars, classes);
if (!returnType.equals(type)) {
throw new RuntimeException("Return type mismatch");
}
return returnType;
}
} }

View File

@ -4,8 +4,49 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
public record MethodCall(Optional<String> receiver, String name, List<Expression> args) implements Expression, Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
Type returnType = null;
if(receiver.isPresent()) {
// check if receiver is a local variable
if(!localVars.containsKey(receiver.get())){
throw new RuntimeException("Variable " + receiver.get() + " not found");
}
}
// check if method exists in class
if(localVars.get(name) == null) {
throw new RuntimeException("Variable " + name + " not found");
}
Type type = localVars.get(name);
Class class1 = classes.get(type.name());
if(class1 == null) {
throw new RuntimeException("Class " + type + " not found");
}
for(Method method : class1.methods()){
if(method.id().name().equals(name)){
for(int i = 0; i < method.params().size(); i++){
if(!method.params().get(i).type().equals(args.get(i).typeCheck(localVars, classes))){
throw new RuntimeException("Type mismatch in method call " + name);
}
}
returnType = method.type();
break;
}else{
throw new RuntimeException("Method " + name + " not found in class " + type);
}
}
return returnType;
}
public record MethodCall(String name, List<Expression> args) implements Expression, Statement {
} }

View File

@ -1,12 +1,18 @@
package de.maishai.ast.records; package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.ast.Type; import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
public record New(Type type, List<Expression> args) implements Expression, Statement { public record New(Type type, List<Expression> args) implements Expression, Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return type;
}
} }

View File

@ -2,7 +2,18 @@ package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.ast.Type; import de.maishai.typedast.Type;
import java.util.Map;
public record Parameter(String name, Type type) implements Node { public record Parameter(String name, Type type) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
if (localVars.containsKey(name)) {
throw new RuntimeException("Variable " + name + " already declared");
}
localVars.put(name, type);
return type;
}
} }

View File

@ -2,8 +2,14 @@ package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.typedast.Type;
import java.util.List; import java.util.List;
import java.util.Map;
public record Program(List<Class> variables) implements Node { public record Program(List<Class> variables) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return null;
}
} }

View File

@ -3,6 +3,15 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record Return(Expression ret) implements Statement { public record Return(Expression ret) implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return ret.typeCheck(localVars, classes);
}
} }

View File

@ -2,6 +2,14 @@ package de.maishai.ast.records;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
// Why does ReturnVoid not have statements
public record ReturnVoid() implements Statement { public record ReturnVoid() implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
return Type.VOID;
}
} }

View File

@ -2,7 +2,18 @@ package de.maishai.ast.records;
import de.maishai.ast.Node; import de.maishai.ast.Node;
import de.maishai.ast.Type; import de.maishai.typedast.Type;
import java.util.Map;
public record Variable(String name, Type type) implements Node { public record Variable(String name, Type type) implements Node {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
if (localVars.containsKey(name)) {
throw new RuntimeException("Variable " + name + " already declared");
}
localVars.put(name, type);
return type;
}
} }

View File

@ -3,6 +3,19 @@ package de.maishai.ast.records;
import de.maishai.ast.Expression; import de.maishai.ast.Expression;
import de.maishai.ast.Statement; import de.maishai.ast.Statement;
import de.maishai.typedast.Type;
import java.util.Map;
public record While(Expression cond, Block block) implements Statement { public record While(Expression cond, Block block) implements Statement {
@Override
public Type typeCheck(Map<String, Type> localVars, Map<String, Class> classes) {
Type condType = cond.typeCheck(localVars, classes);
if (condType != Type.BOOL) {
throw new RuntimeException("Condition must be of type bool");
}
return block.typeCheck(localVars, classes);
}
} }