Merge branch 'refs/heads/main' into testsuites

This commit is contained in:
JonathanFleischmann 2024-05-14 09:44:22 +02:00
commit fb7a7d8230
48 changed files with 1607 additions and 1033 deletions

View File

@ -3,7 +3,7 @@ grammar Decaf;
class : PUBLIC 'class' id '{' mainmeth? (field | meth | constructor)* '}'; class : PUBLIC 'class' id '{' mainmeth? (field | meth | constructor)* '}';
field : type id ';'; field : PUBLIC? type id ';';
localVar : type id ';'; localVar : type id ';';
assignSign : ASSIGN | ADD_ASSIGN | SUB_ASSIGN | MUL_ASSIGN; assignSign : ASSIGN | ADD_ASSIGN | SUB_ASSIGN | MUL_ASSIGN;
returntype : type | VOID; returntype : type | VOID;
@ -20,7 +20,7 @@ block : '{' (localVar | stmt)* '}';
stmt : 'if' '(' expr ')' block ('else' block)? #If stmt : 'if' '(' expr ')' block ('else' block)? #If
| 'for' '(' assign ';' expr ';' assign ')' block #For | 'for' '(' assign ';' expr ';' assign ')' block #For
| 'while' '(' expr ')' block #While | 'while' '(' expr ')' block #While
| 'do' block 'while' '(' expr ')' #DoWhile | 'do' block 'while' '(' expr ')' ';'? #DoWhile
| 'return' expr ';' #Return | 'return' expr ';' #Return
| 'return' ';' #ReturnVoid | 'return' ';' #ReturnVoid
| 'break' ';' #Break | 'break' ';' #Break

View File

@ -17,9 +17,12 @@ public class ASTGenerator {
declarations = ctx.field().stream().map(ASTGenerator::generateFieldVariable).toList(); declarations = ctx.field().stream().map(ASTGenerator::generateFieldVariable).toList();
} }
List<Constructor> constructors = new ArrayList<>(); List<Constructor> constructors = new ArrayList<>();
if (ctx.constructor() != null) { if (!ctx.constructor().isEmpty()) {
constructors = ctx.constructor().stream().map(ASTGenerator::generateConstructor).toList(); constructors = ctx.constructor().stream().map(ASTGenerator::generateConstructor).toList();
} }
else {
constructors.add(new Constructor(ctx.id().IDENTIFIER().getText(), List.of(), new Block(List.of(), List.of())));
}
List<Method> meths = new ArrayList<>(); List<Method> meths = new ArrayList<>();
if (ctx.meth() != null) { if (ctx.meth() != null) {
meths = ctx.meth().stream().map(ASTGenerator::generateMethod).toList(); meths = ctx.meth().stream().map(ASTGenerator::generateMethod).toList();

View File

@ -13,7 +13,7 @@ import java.io.IOException;
* Decaf language Compiler * Decaf language Compiler
*/ */
public class Compiler { public class Compiler {
/*
public static void main(String[] args) { public static void main(String[] args) {
generateAST(""" generateAST("""
public class ClassWithConstructorWithParameters { public class ClassWithConstructorWithParameters {
@ -32,7 +32,7 @@ public class Compiler {
} }
} }
"""); """);
} } */
public static Class generateAST(String fromSource) { public static Class generateAST(String fromSource) {
CharStream input = CharStreams.fromString(fromSource); CharStream input = CharStreams.fromString(fromSource);
@ -92,7 +92,7 @@ public class Compiler {
CodeGenUtils.writeClassfile(bytes, classname); CodeGenUtils.writeClassfile(bytes, classname);
} }
// public static void main(String[] args) { public static void main(String[] args) {
// generateByteCodeFileFromFile("src/main/resources/JavaTestfiles/ClassWithConstructor.java", "ClassWithConstructor"); generateByteCodeFileFromFile("src/main/resources/JavaTestfiles/ClassCanBeTyped.java", "ClassCanBeTyped");
// } }
} }

View File

@ -93,10 +93,12 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
recursiveOwnerChain = generateRecursiveOwnerChain(recipientList, null); recursiveOwnerChain = generateRecursiveOwnerChain(recipientList, null);
} }
List<Expression> args = new ArrayList<>(); List<Expression> args = new ArrayList<>();
if(ctx.methCall().methName().args() != null){
for (var expr : ctx.methCall().methName().args().expr()) { for (var expr : ctx.methCall().methName().args().expr()) {
Expression astExpr = expr.accept(this); Expression astExpr = expr.accept(this);
args.add(astExpr); args.add(astExpr);
} }
}
return new MethodCall(new FieldVarAccess(isField, recursiveOwnerChain, ctx.methCall().methName().id().IDENTIFIER().getText()), args); return new MethodCall(new FieldVarAccess(isField, recursiveOwnerChain, ctx.methCall().methName().id().IDENTIFIER().getText()), args);
} }
@ -115,18 +117,20 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
if (ctxList.isEmpty()) { if (ctxList.isEmpty()) {
return recipient; return recipient;
} }
DecafParser.RecipientContext ctx = ctxList.get(0); int lastElement = ctxList.size() - 1;
ctxList.remove(0); DecafParser.RecipientContext ctx = ctxList.get(lastElement);
ctxList.remove(lastElement);
if (ctx.id() != null) { if (ctx.id() != null) {
return new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText()); return new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.id().IDENTIFIER().getText());
} }
if (ctx.methName() != null) { if (ctx.methName() != null) {
List<Expression> args = new ArrayList<>(); List<Expression> args = new ArrayList<>();
if (ctx.methName().args() != null) {
for (var expr : ctx.methName().args().expr()) { for (var expr : ctx.methName().args().expr()) {
Expression astExpr = expr.accept(new ExpressionGenerator()); Expression astExpr = expr.accept(new ExpressionGenerator());
args.add(astExpr); args.add(astExpr);
} }
}
return new MethodCall(new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.methName().id().IDENTIFIER().getText()), args); return new MethodCall(new FieldVarAccess(false, generateRecursiveOwnerChain(ctxList, recipient), ctx.methName().id().IDENTIFIER().getText()), args);
} }

View File

@ -53,7 +53,7 @@ public class StatementGenerator extends DecafBaseVisitor<Statement> {
@Override @Override
public Statement visitReturnVoid(DecafParser.ReturnVoidContext ctx) { public Statement visitReturnVoid(DecafParser.ReturnVoidContext ctx) {
return new ReturnVoid(); return new Return(null);
} }
@Override @Override

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
// Generated from C:/Users/laure/Documents/Dev/Compilerbau/Projekt/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1 // Generated from C:/dev/Pressmium/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1
package de.maishai.antlr; package de.maishai.antlr;
import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.ParserRuleContext;

View File

@ -1,4 +1,4 @@
// Generated from C:/Users/laure/Documents/Dev/Compilerbau/Projekt/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1 // Generated from C:/dev/Pressmium/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1
package de.maishai.antlr; package de.maishai.antlr;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;

View File

@ -1,4 +1,4 @@
// Generated from C:/Users/laure/Documents/Dev/Compilerbau/Projekt/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1 // Generated from C:/dev/Pressmium/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1
package de.maishai.antlr; package de.maishai.antlr;
import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;

View File

@ -1,4 +1,4 @@
// Generated from C:/Users/laure/Documents/Dev/Compilerbau/Projekt/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1 // Generated from C:/dev/Pressmium/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1
package de.maishai.antlr; package de.maishai.antlr;
import org.antlr.v4.runtime.tree.ParseTreeListener; import org.antlr.v4.runtime.tree.ParseTreeListener;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Generated from C:/Users/laure/Documents/Dev/Compilerbau/Projekt/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1 // Generated from C:/dev/Pressmium/CompilerULTIMATE/src/main/antlr/Decaf.g4 by ANTLR 4.13.1
package de.maishai.antlr; package de.maishai.antlr;
import org.antlr.v4.runtime.tree.ParseTreeVisitor; import org.antlr.v4.runtime.tree.ParseTreeVisitor;

View File

@ -1,5 +0,0 @@
package de.maishai.ast.records;
public record ReturnVoid() implements Statement {
}

View File

@ -1,4 +1,4 @@
package de.maishai.ast.records; package de.maishai.ast.records;
public sealed interface Statement extends Node permits Assignment, Break, DoWhile, For, IfElse, MethodCall, New, Return, ReturnVoid, While { public sealed interface Statement extends Node permits Assignment, Break, DoWhile, For, IfElse, MethodCall, New, Return, While {
} }

View File

@ -0,0 +1,16 @@
package de.maishai.typedast;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.objectweb.asm.ClassWriter;
@Data
public class ClassContext {
private Type name;
private ClassWriter cw;
public ClassContext(String name, ClassWriter cw) {
this.name = Type.REFERENCE(name);
this.cw = cw;
}
}

View File

@ -9,6 +9,10 @@ import java.util.List;
public class CodeGenUtils { public class CodeGenUtils {
public static String generateDescriptor(List<TypedParameter> arguments, Type returnType) { public static String generateDescriptor(List<TypedParameter> arguments, Type returnType) {
if (returnType == null) {
returnType = Type.VOID;
}
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append('('); builder.append('(');
arguments.forEach(type -> builder.append(type.getType().getDescriptor())); arguments.forEach(type -> builder.append(type.getType().getDescriptor()));

View File

@ -0,0 +1,56 @@
package de.maishai.typedast.Help;
import de.maishai.ast.records.*;
import de.maishai.typedast.Type;
import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.typedclass.*;
import java.util.Map;
public class TypedExpressionHelp {
public static TypedExpression convertExpression( TypedClass clas, Expression expression) {
if (expression instanceof BoolLiteral boolLiteral) {
TypedBoolLiteral typedBoolLiteral = new TypedBoolLiteral( clas, boolLiteral);
typedBoolLiteral.typeCheck( clas);
return typedBoolLiteral;
}
else if (expression instanceof CharLiteral charLiteral) {
TypedCharLiteral typedCharLiteral = new TypedCharLiteral( clas, charLiteral);
typedCharLiteral.typeCheck( clas);
return typedCharLiteral;
}
else if (expression instanceof IntLiteral intLiteral) {
TypedIntLiteral typedIntLiteral = new TypedIntLiteral( clas, intLiteral);
typedIntLiteral.typeCheck( clas);
return typedIntLiteral;
}
else if (expression instanceof Binary binary) {
TypedBinary typedBinary = new TypedBinary( clas, binary);
typedBinary.typeCheck( clas);
return typedBinary;
}
else if (expression instanceof FieldVarAccess fieldVarAccess) {
TypedFieldVarAccess typedFieldVarAccess = new TypedFieldVarAccess( clas, fieldVarAccess);
typedFieldVarAccess.typeCheck( clas);
return typedFieldVarAccess;
}
else if (expression instanceof MethodCall methodCall) {
TypedMethodCall typedMethodCall = new TypedMethodCall( clas, methodCall);
typedMethodCall.typeCheck( clas);
return typedMethodCall;
}
else if (expression instanceof New newStmt) {
TypedNew typedNew = new TypedNew( clas, newStmt);
typedNew.typeCheck( clas);
return typedNew;
}
else if (expression instanceof Unary unary) {
TypedUnary typedUnary = new TypedUnary( clas, unary);
typedUnary.typeCheck( clas);
return typedUnary;
} else {
return null;
}
}
}

View File

@ -3,38 +3,70 @@ package de.maishai.typedast;
import lombok.*; import lombok.*;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Stack;
@Getter @Getter
@Setter
@Data
public class MethodContext { public class MethodContext {
private record LocalVariable(String name, int index, Type type) {
}
private Label startLabel; private Label startLabel;
private Label endLabel; private Label endLabel;
private MethodVisitor mv; private MethodVisitor mv;
private ClassContext classContext;
private int localVarIndex = 0; private int localVarIndex = 0;
private Map<String, Integer> variableIndex = new HashMap<>(); private final Map<String, LocalVariable> variableIndex = new HashMap<>();
private Stack<Integer> stack = new Stack<>();
private int maxStack = 0;
public MethodContext(MethodVisitor mv) { public MethodContext(ClassContext classContext, MethodVisitor mv) {
startLabel = new Label(); startLabel = new Label();
endLabel = new Label(); endLabel = new Label();
this.mv = mv; this.mv = mv;
this.classContext = classContext;
registerVariable("this", classContext.getName());
mv.visitCode(); mv.visitCode();
mv.visitLabel(startLabel); mv.visitLabel(startLabel);
} }
public int addVariable(String name) { public void registerVariable(String name, Type type) {
int index = localVarIndex; int index = localVarIndex;
localVarIndex++; localVarIndex++;
variableIndex.put(name, index); variableIndex.put(name, new LocalVariable(name, index, type));
}
public int getVariableIndex(String name) {
int index = variableIndex.get(name).index;
if (index == -1) {
throw new RuntimeException("Variable not declared");
}
return index; return index;
} }
public void pushStack(String varName) {
stack.push(localVarIndex);
if (stack.size() > maxStack) {
maxStack = stack.size();
}
LocalVariable localVariable = variableIndex.get(varName);
if (localVariable.type.getKind() == Type.Kind.REFERENCE) {
mv.visitVarInsn(Opcodes.ALOAD, localVariable.index);
} else {
mv.visitVarInsn(Opcodes.ILOAD, localVariable.index);
}
}
public void popStack() {
stack.pop();
}
public void wrapUp() { public void wrapUp() {
mv.visitLabel(endLabel); mv.visitLabel(endLabel);
mv.visitMaxs(0, 0); mv.visitMaxs(maxStack, localVarIndex);
mv.visitEnd(); mv.visitEnd();
} }
} }

View File

@ -1,4 +1,7 @@
package de.maishai.typedast; package de.maishai.typedast;
public interface TypedExpression extends TypedNode { public interface TypedExpression extends TypedNode {
public void codeGen(MethodContext ctx);
public Type getType();
} }

View File

@ -2,9 +2,6 @@ package de.maishai.typedast;
import de.maishai.typedast.typedclass.TypedClass; import de.maishai.typedast.typedclass.TypedClass;
import java.util.Map;
public interface TypedNode { public interface TypedNode {
Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes); Type typeCheck(TypedClass clas);
TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST);
} }

View File

@ -1,7 +1,6 @@
package de.maishai.typedast; package de.maishai.typedast;
import org.objectweb.asm.MethodVisitor;
public interface TypedStatement extends TypedNode { public interface TypedStatement extends TypedNode {
public void codeGen(MethodVisitor mv, MethodContext ctx); public void codeGen(MethodContext ctx);
} }

View File

@ -1,31 +1,60 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Assignment; import de.maishai.ast.records.Assignment;
import de.maishai.ast.records.Expression;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.TypedStatement; import de.maishai.typedast.TypedStatement;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
public class TypedAssignment implements TypedStatement { public class TypedAssignment implements TypedStatement {
private String varName;
private TypedExpression value; private TypedExpression value;
private TypedFieldVarAccess location;
private Type type; private Type type;
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public TypedAssignment(TypedClass clas, Assignment untyped) {
if (!localVar.containsKey(varName)) { convertToTypedAssignment(clas, untyped);
throw new RuntimeException("Variable not declared");
} }
Type typeLeft = localVar.get(varName); public void convertToTypedAssignment(TypedClass clas, Assignment untyped) {
Type typeRight = value.typeCheck(localVar, classes); value = convertExpression(clas, untyped.value());
location = new TypedFieldVarAccess(clas, untyped.location());
}
if (typeLeft.equals(typeRight) ) { @Override
public Type typeCheck(TypedClass clas) {
Type typeLeft = null;
if (clas.isThereField(location.getName())) {
typeLeft = clas.getFieldType(location.getName());
} else {
if (clas.isCurrentMethodPresent() && !clas.isCurrentConstructorPresent()) {
if (clas.getCurrentMethod().isLocalVariableInMethod(location.getName())) {
typeLeft = clas.getCurrentMethod().getLocalVariableType(location.getName());
} else {
throw new RuntimeException("Variable " + location.getName() + " not declared in method");
}
}
if (!clas.isCurrentMethodPresent() && clas.isCurrentConstructorPresent()) {
if (clas.getCurrentConstructor().isLocalVariableInConstructor(location.getName())) {
typeLeft = clas.getCurrentConstructor().getLocalVariableType(location.getName());
} else {
throw new RuntimeException("Variable " + location.getName() + " not declared in constructor");
}
}
}
Type typeRight = value.typeCheck(clas);
if (typeLeft.equals(typeRight)) {
type = typeLeft; type = typeLeft;
return typeLeft; return typeLeft;
} }
@ -33,16 +62,10 @@ public class TypedAssignment implements TypedStatement {
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
Assignment untyped = (Assignment) unTypedAST; if (value instanceof TypedIntLiteral) {
TypedAssignment typedAssignment = new TypedAssignment(); ctx.getMv().visitIntInsn(Opcodes.BIPUSH, ((TypedIntLiteral) value).getValue());
typedAssignment.setVarName(untyped.location().id()); ctx.getMv().visitVarInsn(Opcodes.ISTORE, ctx.getLocalVarIndex());
typedAssignment.setValue((TypedExpression) value.convertToTypedAST(localVar, classes, untyped.value()));
return typedAssignment;
} }
@Override
public void codeGen(MethodVisitor mv, MethodContext ctx) {
} }
} }

View File

@ -2,59 +2,72 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.Operator; import de.maishai.ast.Operator;
import de.maishai.ast.records.Binary; import de.maishai.ast.records.Binary;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
@NoArgsConstructor
public class TypedBinary implements TypedExpression { public class TypedBinary implements TypedExpression {
private TypedExpression left; private TypedExpression left;
private Operator op; private Operator op;
private TypedExpression right; private TypedExpression right;
private Type type; private Type type;
public TypedBinary(TypedClass clas, Binary unTypedBinary) {
convertToTypedBinary(clas, unTypedBinary);
}
public void convertToTypedBinary(TypedClass clas, Binary unTypedBinary) {
left = convertExpression(clas, unTypedBinary.left());
right = convertExpression(clas, unTypedBinary.right());
op = unTypedBinary.op();
}
@Override @Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public Type typeCheck(TypedClass clas) {
if(op == Operator.ADD || op == Operator.SUB || op == Operator.MUL) { Type leftType = left.typeCheck(clas);
if (left.typeCheck(localVar, classes) == Type.INT && Type rightType = right.typeCheck(clas);
right.typeCheck(localVar, classes) == Type.INT) {
if (op == Operator.ADD || op == Operator.SUB || op == Operator.MUL) {
if (leftType == Type.INT && rightType == Type.INT) {
type = Type.INT; type = Type.INT;
return Type.INT; return Type.INT;
} else { } else {
throw new RuntimeException("Type mismatch"); throw new RuntimeException("Type mismatch in " + op);
} }
}else if(op == Operator.GT || op == Operator.LT || op == Operator.GE || op == Operator.LE || op == Operator.EQ || op == Operator.NE || op == Operator.AND || op == Operator.OR) { } else if (op == Operator.GT || op == Operator.LT || op == Operator.GE || op == Operator.LE) {
if (left.typeCheck(localVar, classes) == Type.INT && if (leftType == Type.INT && rightType == Type.INT) {
right.typeCheck(localVar, classes) == Type.INT) {
type = Type.BOOL; type = Type.BOOL;
return Type.BOOL; return Type.BOOL;
} else { } else {
throw new RuntimeException("Type mismatch"); throw new RuntimeException("Type mismatch in " + op);
} }
} else if (op == Operator.AND || op == Operator.OR) { } else if (op == Operator.AND || op == Operator.OR) {
if (left.typeCheck(localVar, classes) == Type.BOOL && if (leftType == Type.BOOL && rightType == Type.BOOL) {
right.typeCheck(localVar, classes) == Type.BOOL) {
type = Type.BOOL; type = Type.BOOL;
return Type.BOOL; return Type.BOOL;
} else { } else {
throw new RuntimeException("Type mismatch"); throw new RuntimeException("Type mismatch in " + op);
} }
} else {
throw new RuntimeException("Invalid operator");
} }
if (leftType == rightType && leftType != Type.VOID) {
type = rightType;
return type;
}
throw new RuntimeException("Void can not be compared with Void");
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
Binary binary = (Binary) unTypedAST;
TypedBinary typedBinary = new TypedBinary();
typedBinary.setLeft((TypedExpression) this.left.convertToTypedAST(localVar, classes, binary.left()));
typedBinary.setOp(binary.op());
typedBinary.setRight((TypedExpression) this.right.convertToTypedAST(localVar, classes, binary.right()));
return typedBinary;
} }
} }

View File

@ -1,159 +1,128 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.*; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.Type;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.TypedStatement;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@NoArgsConstructor
@AllArgsConstructor
@Data @Data
public class TypedBlock implements TypedNode { public class TypedBlock implements TypedNode {
private List<TypedLocalVariable> vars; private List<TypedLocalVariable> vars = new ArrayList<>();
private List<TypedStatement> stmts; private List<TypedStatement> stmts = new ArrayList<>();
private Type type;
public TypedBlock(TypedClass clas, Block unTypedBlock) {
public TypedBlock unTypedBlockToTypedBlock(Block unTypedBlock) { convertToTypedBlock(clas, unTypedBlock);
TypedBlock typedBlock = new TypedBlock();
typedBlock.setStmts(new ArrayList<>());
typedBlock.setVars(new ArrayList<>());
if(unTypedBlock.localVariables().isEmpty()){
typedBlock.setVars(List.of());
} }
if(unTypedBlock.stmts().isEmpty()){ public TypedBlock(List<TypedLocalVariable> vars, List<TypedStatement> stmts) {
typedBlock.setStmts(List.of()); this.vars = vars;
this.stmts = stmts;
}
public void convertToTypedBlock(TypedClass clas, Block unTypedBlock) {
if (unTypedBlock == null) {
return;
} }
for (Declaration var : unTypedBlock.localVariables()) { for (Declaration var : unTypedBlock.localVariables()) {
TypedLocalVariable typedVar = new TypedLocalVariable(); vars.add(new TypedLocalVariable(clas, var));
typedVar.setName(var.name());
typedVar.setType(var.type());
typedBlock.getVars().add(typedVar);
} }
for(var stmt : unTypedBlock.stmts()){ for (var stmt : unTypedBlock.stmts()) {
if (stmt instanceof Assignment assignment) {
if(stmt instanceof Assignment assignment){ TypedAssignment typedAssignment = new TypedAssignment(clas, assignment);
TypedAssignment typedAssignment = new TypedAssignment(); typedAssignment.typeCheck(clas);
typedAssignment.setVarName(assignment.location().id()); stmts.add(typedAssignment);
typedAssignment.setValue(null);
typedBlock.getStmts().add(typedAssignment);
continue; continue;
} }
if(stmt instanceof For forStmt){ if (stmt instanceof For forStmt) {
TypedFor typedFor = new TypedFor(); TypedFor typedFor = new TypedFor(clas, forStmt);
TypedBlock typedBlock1 = new TypedBlock(); typedFor.typeCheck(clas);
typedFor.setTypedBlock(typedBlock1.unTypedBlockToTypedBlock((forStmt.block()))); stmts.add(typedFor);
typedFor.setAssign(null);
typedFor.setCond(null);
typedFor.setInc(null);
typedBlock.getStmts().add(typedFor);
continue; continue;
} }
if(stmt instanceof IfElse ifElse){ if (stmt instanceof IfElse ifElse) {
TypedIfElse typedIfElse = new TypedIfElse(); TypedIfElse typedIfElse = new TypedIfElse(clas, ifElse);
TypedBlock typedBlockIf = new TypedBlock(); typedIfElse.typeCheck(clas);
TypedBlock typedBlockElse = new TypedBlock(); stmts.add(typedIfElse);
typedIfElse.setIfTypedBlock(typedBlockIf.unTypedBlockToTypedBlock(ifElse.ifBlock()));
typedIfElse.setElseTypedBlock(typedBlockElse.unTypedBlockToTypedBlock(ifElse.elseBlock()));
typedIfElse.setTypedCon(null);
typedBlock.getStmts().add(typedIfElse);
continue; continue;
} }
if(stmt instanceof MethodCall methodCall){ if (stmt instanceof While whileStmt) {
TypedMethodCall typedMethodCall = new TypedMethodCall(); TypedWhile typedWhile = new TypedWhile(clas, whileStmt);
typedMethodCall.setArgs(null); typedWhile.typeCheck(clas);
typedMethodCall.setRecipient(null); stmts.add(typedWhile);
typedBlock.getStmts().add(typedMethodCall);
continue; continue;
} }
if(stmt instanceof New newStmt){ if (stmt instanceof DoWhile doWhile) {
TypedNew typedNew = new TypedNew(); TypedDoWhile typedDoWhile = new TypedDoWhile(clas, doWhile);
typedNew.setArgs(null); typedDoWhile.typeCheck(clas);
typedNew.setType(newStmt.type()); stmts.add(typedDoWhile);
typedBlock.getStmts().add(typedNew);
continue; continue;
} }
if(stmt instanceof Return returnStmt){ if (stmt instanceof Return returnStmt) {
TypedReturn typedReturn = new TypedReturn(); TypedReturn typedReturn = new TypedReturn(clas, returnStmt);
typedReturn.setRet(null); typedReturn.typeCheck(clas);
typedBlock.getStmts().add(typedReturn); stmts.add(typedReturn);
continue; continue;
} }
if(stmt instanceof While whileStmt){ if (stmt instanceof New newStmt) {
TypedWhile typedWhile = new TypedWhile(); TypedNew typedNew = new TypedNew(clas, newStmt);
TypedBlock typedBlock1 = new TypedBlock(); typedNew.typeCheck(clas);
typedWhile.setTypedBlock(typedBlock1.unTypedBlockToTypedBlock(whileStmt.block())); stmts.add(typedNew);
typedWhile.setCond(null);
typedBlock.getStmts().add(typedWhile);
continue; continue;
} }
if(stmt instanceof DoWhile doWhile){
TypedDoWhile typedDoWhile = new TypedDoWhile();
TypedBlock typedBlock1 = new TypedBlock();
typedDoWhile.setTypedBlock(typedBlock1.unTypedBlockToTypedBlock(doWhile.block()));
typedDoWhile.setCond(null);
typedBlock.getStmts().add(typedDoWhile);
continue;
}
if(stmt instanceof Break){
TypedBreak typedBreak = new TypedBreak();
typedBlock.getStmts().add(typedBreak);
}
} if (stmt instanceof Break) {
//System.out.println("stmts:" + typedBlock.getStmts().toString()); stmts.add(new TypedBreak());
continue;
return typedBlock;
}
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
Type typeOfLastStmt = Type.VOID;
for (TypedLocalVariable var : vars) {
var.typeCheck(localVar, classes);
}
for (TypedStatement stmt : stmts) {
stmt.typeCheck(localVar, classes);
typeOfLastStmt = stmt.typeCheck(localVar, classes);
} }
return typeOfLastStmt; if (stmt instanceof MethodCall methodCall) {
TypedMethodCall typedMethodCall = new TypedMethodCall(clas, methodCall);
typedMethodCall.typeCheck(clas);
stmts.add(typedMethodCall);
}
}
this.typeCheck(clas);
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
Block untyped = (Block) unTypedAST; Type chekType = null;
TypedBlock typedBlock = new TypedBlock(); for (TypedStatement stmt : stmts) {
typedBlock.setStmts(new ArrayList<>()); stmt.typeCheck(clas);
typedBlock.setVars(new ArrayList<>()); if(stmt instanceof TypedReturn returnStmt) {
chekType = returnStmt.getType();
for (Declaration var : untyped.localVariables()) {
TypedLocalVariable typedVar = new TypedLocalVariable();
typedVar.setName(var.name());
typedVar.setType(var.type());
typedBlock.getVars().add(typedVar);
} }
typedBlock.getStmts().add((TypedStatement) untyped.stmts());
int i = 0;
for(var stmt : untyped.stmts()){
System.out.println(i++ +" :" + stmt);
} }
return typedBlock; if(chekType == null) {
chekType = Type.VOID;
}
type = chekType;
return type;
} }
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodContext ctx) {
for (TypedLocalVariable var : vars) { for (TypedLocalVariable var : vars) {
var.codeGen(mv, ctx); //var.codeGen(ctx);
} }
for (TypedStatement stmt : stmts) { for (TypedStatement stmt : stmts) {
stmt.codeGen(mv, ctx); stmt.codeGen(ctx);
} }
} }
} }

View File

@ -1,29 +1,46 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.BoolLiteral; import de.maishai.ast.records.BoolLiteral;
import de.maishai.ast.records.Node;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Map; import java.util.Map;
@Data @Data
@NoArgsConstructor
public class TypedBoolLiteral implements TypedExpression { public class TypedBoolLiteral implements TypedExpression {
private Boolean value; private Boolean value;
private Type type; private Type type;
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
public TypedBoolLiteral(TypedClass clas, BoolLiteral unTypedBoolLiteral) {
convertToTypedBoolLiteral(clas, unTypedBoolLiteral);
}
public void convertToTypedBoolLiteral(TypedClass clas, BoolLiteral unTypedBoolLiteral) {
value = unTypedBoolLiteral.value();
type = Type.BOOL; type = Type.BOOL;
return Type.BOOL;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
BoolLiteral untyped = (BoolLiteral) unTypedAST; return type;
TypedBoolLiteral typedBoolLiteral = new TypedBoolLiteral();
typedBoolLiteral.setValue(untyped.value());
return typedBoolLiteral;
} }
@Override
public void codeGen(MethodContext ctx) {
if(value){
ctx.getMv().visitInsn(Opcodes.ICONST_1);
}else{
ctx.getMv().visitInsn(Opcodes.ICONST_0);
}
}
} }

View File

@ -1,6 +1,7 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Break; import de.maishai.ast.records.Break;
import de.maishai.ast.records.Node;
import de.maishai.typedast.MethodContext; import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import de.maishai.typedast.TypedStatement; import de.maishai.typedast.TypedStatement;
@ -9,24 +10,22 @@ import lombok.Data;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
@Data @Data
public class TypedBreak implements TypedStatement { public class TypedBreak implements TypedStatement {
@Override private Type type = Type.VOID;
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
return Type.VOID; public TypedBreak convertToTypedBreak(TypedClass clas, Break unTypedBreak) {
return this;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
Break untyped = (Break) unTypedAST; return type;
if(untyped == null) {
throw new RuntimeException("Break not found");
}
return new TypedBreak();
} }
@Override @Override
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodContext ctx) {
} }
} }

View File

@ -1,25 +1,38 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.CharLiteral; import de.maishai.ast.records.CharLiteral;
import de.maishai.ast.records.Node;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
@Data @Data
public class TypedCharLiteral implements TypedExpression { public class TypedCharLiteral implements TypedExpression {
private char value; private char value;
@Override private Type type;
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
return Type.CHAR; public TypedCharLiteral(TypedClass clas, CharLiteral unTypedCharLiteral) {
convertToCharLiteral(clas, unTypedCharLiteral);
}
public void convertToCharLiteral(TypedClass clas, CharLiteral unTypedCharLiteral) {
value = unTypedCharLiteral.value();
type = Type.CHAR;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
CharLiteral untyped = (CharLiteral) unTypedAST; return type;
TypedCharLiteral typedCharLiteral = new TypedCharLiteral(); }
typedCharLiteral.setValue(untyped.value());
return typedCharLiteral;
@Override
public void codeGen(MethodContext ctx) {
ctx.getMv().visitLdcInsn(value);
} }
} }

View File

@ -1,9 +1,9 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.Operator;
import de.maishai.ast.records.*;
import de.maishai.ast.records.Class; import de.maishai.ast.records.Class;
import de.maishai.ast.records.Constructor; import de.maishai.typedast.ClassContext;
import de.maishai.ast.records.Declaration;
import de.maishai.ast.records.Method;
import de.maishai.typedast.CodeGenUtils; import de.maishai.typedast.CodeGenUtils;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -23,77 +23,196 @@ import java.util.Map;
@NoArgsConstructor @NoArgsConstructor
public class TypedClass implements TypedNode { public class TypedClass implements TypedNode {
private String className; private String className;
private List<TypedField> typedFields; private List<TypedDeclaration> typedDeclarations = new ArrayList<>();
private List<TypedMethod> typedMethods; private List<TypedMethod> typedMethods = new ArrayList<>();
private List<TypedConstructor> typedConstructors; private List<TypedConstructor> typedConstructors = new ArrayList<>();
private TypedMethod currentMethod;
private TypedConstructor currentConstructor;
private Type type;
@Override public TypedClass(Class c) {
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { convertToTypedClass(c);
if (classes.containsKey(className)) {
throw new RuntimeException("Class " + className + " already exists");
}
classes.put(className, this);
for (TypedField field : typedFields) {
field.typeCheck(localVar, classes);
}
for(TypedConstructor constructor : typedConstructors) {
constructor.typeCheck(localVar, classes);
}
for (TypedMethod typedMethod : typedMethods) {
typedMethod.typeCheck(localVar, classes);
}
return Type.REFERENCE(className);
} }
public TypedNode startConversion(de.maishai.ast.records.Class c) { public void enterCurrentMethod(TypedMethod method) {
Map<String, Type> local = new HashMap<>(); currentMethod = method;
Map<String, TypedClass> classMap = new HashMap<>();
return convertToTypedAST(local, classMap, c);
} }
@Override public void exitCurrentMethod() {
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { currentMethod = null;
TypedClass typedClass = new TypedClass();
Class c = (Class) unTypedAST;
typedClass.setClassName(c.classname());
typedClass.setTypedFields(new ArrayList<>());
typedClass.setTypedMethods(new ArrayList<>());
typedClass.setTypedConstructors(new ArrayList<>());
for (Declaration field : c.fieldDeclarations()) {
TypedField typedField = new TypedField();
typedClass.getTypedFields().add(typedField.unTypedFieldToTypedField(field));
} }
public void enterCurrentConstructor(TypedConstructor constructor) {
currentConstructor = constructor;
}
public void exitCurrentConstructor() {
currentConstructor = null;
}
public boolean isCurrentMethodPresent() {
return currentMethod != null;
}
public boolean isCurrentConstructorPresent() {
return currentConstructor != null;
}
public boolean isParameterNameInCurrentMethod(String parameterName) {
if (currentMethod == null) {
return false;
}
for (TypedParameter p : currentMethod.getTypedParameters()) {
if (p.getParaName().equals(parameterName)) {
return true;
}
}
return false;
}
public boolean isParameterNameInCurrentConstructor(String parameterName) {
if (currentConstructor == null) {
return false;
}
for (TypedParameter p : currentConstructor.getTypedParameters()) {
if (p.getParaName().equals(parameterName)) {
return true;
}
}
return false;
}
public void convertToTypedClass(Class c) {
className = c.classname();
type = Type.REFERENCE(className);
// Am Anfang werden die Attribute, die Konstruktoren und Methoden in die jeweilige Liste eingefügt.
// damit die Methoden verwendet werden können, bevor deren Blöcke ausgeführt werden
for (Declaration declaration : c.fieldDeclarations()) {
typedDeclarations.add(new TypedDeclaration(this, declaration));
}
for (Constructor constructor : c.constructors()) {
typedConstructors.add(new TypedConstructor(this, constructor));
}
for (Method method : c.methods()) { for (Method method : c.methods()) {
TypedMethod typedMethod = new TypedMethod(); typedMethods.add(new TypedMethod(this, method));
typedClass.getTypedMethods().add(typedMethod.unTypedMethodToTypedMethod(method));
} }
// Hier werden die Blöcke der Konstruktoren ausgeführt
int i = 0;
for (Constructor constructor : c.constructors()) { for (Constructor constructor : c.constructors()) {
TypedConstructor typedConstructor = new TypedConstructor(); enterCurrentConstructor(typedConstructors.get(i));
typedClass.getTypedConstructors().add(typedConstructor.unTypedContructorToTypedConstructor(constructor)); typedConstructors.get(i).convertToBlock(this, constructor);
exitCurrentConstructor();
i++;
}
// Hier werden die Blöcke der Methoden ausgeführt
int j = 0;
for (Method method : c.methods()) {
enterCurrentMethod(typedMethods.get(j));
typedMethods.get(j).convertToTypedBlock(this, method);
exitCurrentMethod();
j++;
} }
return typedClass;
} }
@Override
public Type typeCheck(TypedClass clas) {
return type;
}
public TypedNode startConversion(Class c) {
Map<String, Type> local = new HashMap<>();
return new TypedClass(c);
}
public boolean isParameterWitNameInMethod(String parameterName) {
for (TypedMethod m : typedMethods) {
for (TypedParameter p : m.getTypedParameters()) {
if (p.getParaName().equals(parameterName)) {
return true;
}
}
}
return false;
}
public boolean isParameterWitNameInConstructor(String parameterName) {
for (TypedConstructor c : typedConstructors) {
for (TypedParameter p : c.getTypedParameters()) {
if (p.getParaName().equals(parameterName)) {
return true;
}
}
}
return false;
}
public Type getParameterTypeInCurrentMethod(String parameterName) {
for (TypedMethod m : typedMethods) {
for (TypedParameter p : m.getTypedParameters()) {
if (p.getParaName().equals(parameterName)) {
return p.getType();
}
}
}
return null;
}
public Type getParameterTypeInCurrentConstructor(String parameterName) {
for (TypedParameter p : currentConstructor.getTypedParameters()) {
if (p.getParaName().equals(parameterName)) {
return p.getType();
}
}
return null;
}
public boolean isThereField(String fieldName) {
for (TypedDeclaration f : typedDeclarations) {
if (f.getName().equals(fieldName)) {
return true;
}
}
return false;
}
public Type getFieldType(String fieldName) {
for (TypedDeclaration f : typedDeclarations) {
if (f.getName().equals(fieldName)) {
return f.getType();
}
}
return null;
}
public Type getMethodType(String methodName) {
for (TypedMethod m : typedMethods) {
if (m.getName().equals(methodName)) {
return m.getReturnType();
}
}
return null;
}
public byte[] codeGen() { public byte[] codeGen() {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassContext ctx = new ClassContext(className, cw);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null); cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
for (TypedField field : typedFields) { for (TypedDeclaration declaration : typedDeclarations) {
field.codeGen(cw); declaration.codeGen(cw);
} }
for (TypedConstructor constructor : typedConstructors) { for (TypedConstructor constructor : typedConstructors) {
constructor.codeGen(cw); constructor.codeGen(ctx);
} }
for (TypedMethod m : typedMethods) { for (TypedMethod m : typedMethods) {
//m.codeGen(cw); m.codeGen(ctx);
} }
return cw.toByteArray(); return cw.toByteArray();
@ -105,16 +224,28 @@ public class TypedClass implements TypedNode {
c.setClassName("SomeClass"); c.setClassName("SomeClass");
//Fields //Fields
TypedField f1 = new TypedField("someNumber", Type.INT); TypedDeclaration f1 = new TypedDeclaration("someNumber", Type.INT);
TypedField f2 = new TypedField("someChar", Type.CHAR); TypedDeclaration f2 = new TypedDeclaration("someChar", Type.CHAR);
c.typedFields = List.of(f1, f2); c.typedDeclarations = List.of(f1, f2);
//Constructors //Constructors
TypedConstructor constructor = new TypedConstructor( "SomeClass", List.of(new TypedParameter("test", Type.INT)), new TypedBlock()); TypedConstructor constructor = new TypedConstructor("SomeClass", List.of(new TypedParameter("test", Type.INT)), new TypedBlock(new ArrayList<>(), new ArrayList<>()));
c.typedConstructors = List.of(constructor); c.typedConstructors = List.of(constructor);
//Methods //Methods
c.typedMethods = new ArrayList<>(); c.typedMethods = new ArrayList<>();
TypedMethod m = new TypedMethod();
m.setName("someMethod");
m.setReturnType(Type.INT);
m.setTypedParameters(List.of(new TypedParameter("test", Type.INT)));
TypedIfElse ifs = new TypedIfElse();
TypedBinary cond = new TypedBinary();
cond.setOp(Operator.GT);
//cond.setLeft(??);
cond.setRight(new TypedIntLiteral(12));
ifs.setTypedCon(cond);
m.setTypedBlock(new TypedBlock(List.of(), List.of(ifs, new TypedReturn())));
c.typedMethods.add(m);
//codeGen //codeGen
byte[] code = c.codeGen(); byte[] code = c.codeGen();

View File

@ -1,22 +1,16 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Block;
import de.maishai.ast.records.Constructor; import de.maishai.ast.records.Constructor;
import de.maishai.ast.records.Parameter; import de.maishai.ast.records.Parameter;
import de.maishai.typedast.CodeGenUtils; import de.maishai.typedast.*;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
@RequiredArgsConstructor @RequiredArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@ -24,82 +18,75 @@ import java.util.Map;
public class TypedConstructor implements TypedNode { public class TypedConstructor implements TypedNode {
private String name; private String name;
private List<TypedParameter> typedParameters; private List<TypedParameter> typedParameters = new ArrayList<>();
private TypedBlock typedBlock; private TypedBlock typedBlock;
private Type type;
private List<TypedLocalVariable> localVariables = new ArrayList<>();
@Override public TypedConstructor(String name, List<TypedParameter> typedParameters, TypedBlock typedBlock) {
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { this.name = name;
if (localVar.containsKey(name)) { this.typedParameters = typedParameters;
throw new RuntimeException("constructor already declared"); this.typedBlock = typedBlock;
}
localVar.put(name, Type.VOID);
if (typedParameters != null) {
for (TypedParameter param : typedParameters) {
param.typeCheck(localVar, classes);
}
}
typedBlock.typeCheck(localVar, classes);
return Type.VOID;
} }
public TypedConstructor unTypedContructorToTypedConstructor(de.maishai.ast.records.Constructor unTypedConstructor) { public TypedConstructor(TypedClass clas, Constructor unTypedConstructor) {
TypedConstructor typedConstructor = new TypedConstructor(); convertToTypedConstructor(clas, unTypedConstructor);
typedConstructor.setName(unTypedConstructor.className()); }
typedConstructor.setTypedParameters(new ArrayList<>());
if (unTypedConstructor.params().isEmpty()) { public boolean isLocalVariablePresent(String localVarName) {
typedConstructor.setTypedParameters(List.of()); return localVariables.stream().anyMatch(localVariable -> localVariable.getName().equals(localVarName));
} else { }
public boolean isParameterPresent(String parameterName) {
return typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(parameterName));
}
public boolean isLocalVariableInConstructor(String localVarName) {
return isLocalVariablePresent(localVarName) || isParameterPresent(localVarName);
}
public Type getLocalVariableType(String localVarName) {
return localVariables.stream().filter(localVariable -> localVariable.getName().equals(localVarName)).findFirst().get().getType();
}
public void convertToTypedConstructor(TypedClass clas, Constructor unTypedConstructor) {
name = unTypedConstructor.className();
for (Parameter param : unTypedConstructor.params()) { for (Parameter param : unTypedConstructor.params()) {
TypedParameter typedParam = new TypedParameter(); typedParameters.add(new TypedParameter(clas, param));
typedParam.setParaName(param.name()); }
typedParam.setType(param.type()); type = Type.VOID;
typedConstructor.getTypedParameters().add(typedParam);
} }
} public void convertToBlock(TypedClass clas, Constructor unTypedConstructor) {
TypedBlock typedBlock = new TypedBlock(); this.typedBlock = new TypedBlock(clas, unTypedConstructor.block());
typedConstructor.setTypedBlock(typedBlock.unTypedBlockToTypedBlock(unTypedConstructor.block())); typeCheck(clas);
return typedConstructor;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
Constructor untyped = (Constructor) unTypedAST; type = typedBlock.typeCheck(clas);
TypedConstructor typedConstructor = new TypedConstructor(); if (type != Type.VOID) {
typedConstructor.setName(untyped.className()); throw new RuntimeException("Constructor must not habe a return statement");
typedConstructor.setTypedParameters(new ArrayList<>());
if (untyped.params().isEmpty()) {
typedConstructor.setTypedParameters(null);
} else {
for (Parameter param : untyped.params()) {
TypedParameter typedParam = new TypedParameter();
typedParam.setType(param.type());
typedParam.setParaName(param.name());
typedConstructor.getTypedParameters().add(typedParam);
} }
} return type;
TypedBlock typedBlock = new TypedBlock();
typedConstructor.setTypedBlock(typedBlock.unTypedBlockToTypedBlock(untyped.block()));
return typedConstructor;
} }
public void codeGen(ClassWriter cw) {
public void codeGen(ClassContext ctx) {
int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok
MethodVisitor mv = cw.visitMethod(accessModifier, "<init>", CodeGenUtils.generateDescriptor(typedParameters, Type.VOID), null, null); MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, "<init>", CodeGenUtils.generateDescriptor(typedParameters, Type.VOID), null, null);
MethodContext context = new MethodContext(mv); MethodContext mctx = new MethodContext(ctx, mv);
typedParameters.forEach(param -> mctx.registerVariable(param.getParaName(), param.getType()));
//super(); //super();
mv.visitVarInsn(Opcodes.ALOAD, 0); mctx.pushStack("this");
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
typedBlock.codeGen(mv, context); typedBlock.codeGen(mctx);
mv.visitInsn(Opcodes.RETURN); mv.visitInsn(Opcodes.RETURN);
context.wrapUp(); mctx.wrapUp();
} }
} }

View File

@ -1,28 +0,0 @@
package de.maishai.typedast.typedclass;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.TypedStatement;
import de.maishai.typedast.Type;
import lombok.Data;
import org.objectweb.asm.MethodVisitor;
import java.util.Map;
@Data
public class TypedContinue implements TypedStatement {
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
return Type.VOID;
}
@Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
return new TypedContinue();
}
@Override
public void codeGen(MethodVisitor mv, MethodContext ctx) {
}
}

View File

@ -0,0 +1,62 @@
package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Declaration;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Map;
import static de.maishai.typedast.Type.Kind.REFERENCE;
@Data
@AllArgsConstructor
@NoArgsConstructor
public final class TypedDeclaration implements TypedNode {
private String name;
private Type type;
public TypedDeclaration(TypedClass clas, Declaration declaration) {
convertToTypedDeclaration(clas, declaration);
}
public void convertToTypedDeclaration(TypedClass clas, Declaration declaration) {
name = declaration.name();
type = declaration.type();
typeCheck(clas);
}
@Override
public Type typeCheck(TypedClass clas) {
if (clas.isThereField(name)) {
throw new RuntimeException("Field " + name + " already declared");
}
if (type.getKind() == REFERENCE) {
if (!type.getReference().equals(clas.getClassName())) {
throw new RuntimeException("Field " + name + " has wrong type");
}
}
return type;
}
/*
public void codeGen(MethodVisitor mv, MethodContext ctx) {
System.out.println("Generating code for local variable " + name);
int index = ctx.addVariable(name);
mv.visitLocalVariable(name, type.getDescriptor(), null, ctx.getStartLabel(), ctx.getEndLabel(), index);
}
*/
public void codeGen(ClassWriter cw) {
int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind
cw.visitField(access, name, type.getDescriptor(), null, null).visitEnd();
}
}

View File

@ -1,38 +1,41 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.DoWhile; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
public class TypedDoWhile implements TypedStatement { public class TypedDoWhile implements TypedStatement {
private TypedBlock typedBlock; private TypedBlock typedBlock;
private TypedExpression cond; private TypedExpression cond;
private Type type;
public TypedDoWhile(TypedClass clas, DoWhile unTypedDoWhile) {
convertToTypedDoWhile(clas, unTypedDoWhile);
}
public void convertToTypedDoWhile(TypedClass clas, DoWhile unTypedDoWhile) {
typedBlock = new TypedBlock(clas, unTypedDoWhile.block());
cond = convertExpression(clas, unTypedDoWhile.cond());
}
@Override @Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public Type typeCheck(TypedClass clas) {
if(cond.typeCheck(localVar, classes) != Type.BOOL){ if (cond.typeCheck(clas) != Type.BOOL) {
throw new RuntimeException("Condition must be boolean"); throw new RuntimeException("Condition must be boolean");
} }
typedBlock.typeCheck(localVar, classes); typedBlock.typeCheck(clas);
this.type = Type.VOID;
return Type.VOID; return Type.VOID;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
DoWhile untyped = (DoWhile) unTypedAST;
TypedDoWhile typedDoWhile = new TypedDoWhile();
TypedBlock typedBlock = new TypedBlock();
typedDoWhile.setTypedBlock(typedBlock.unTypedBlockToTypedBlock(untyped.block()));
typedDoWhile.setCond((TypedExpression) cond.convertToTypedAST(localVar, classes, untyped.cond()));
return typedDoWhile;
}
@Override
public void codeGen(MethodVisitor mv, MethodContext ctx) {
} }
} }

View File

@ -1,53 +0,0 @@
package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Declaration;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import java.util.Map;
@AllArgsConstructor
@RequiredArgsConstructor
@Data
public class TypedField implements TypedNode {
private String varName;
private Type type;
public TypedField unTypedFieldToTypedField(Declaration declaration){
TypedField typedField = new TypedField();
typedField.setType(declaration.type());
typedField.setVarName(declaration.name());
return typedField;
}
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
if (localVar.containsKey(varName)) {
throw new RuntimeException("Variable " + varName + " already declared");
}
localVar.put(varName, type);
return type;
}
@Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
Declaration untypedDeclaration = (Declaration) unTypedAST;
TypedField typedField = new TypedField();
typedField.setType(untypedDeclaration.type());
typedField.setVarName(untypedDeclaration.name());
return typedField;
}
public void codeGen(ClassWriter cw) {
int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind
cw.visitField(access, varName, type.getDescriptor(), null, null).visitEnd();
}
}

View File

@ -1,35 +0,0 @@
package de.maishai.typedast.typedclass;
import de.maishai.ast.records.FieldVarAccess;
import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type;
import lombok.Data;
import java.util.Map;
@Data
public class TypedFieldId implements TypedExpression {
private Boolean field;
private TypedExpression recipient;
private String name;
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
//TODO: Implement typeCheck for FieldVarAccess
if(field){
return null;
}else{
return null;
}
}
@Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
FieldVarAccess untypedFieldVarAccess = (FieldVarAccess) unTypedAST;
TypedFieldId typedFieldId = new TypedFieldId();
typedFieldId.setField(untypedFieldVarAccess.field());
typedFieldId.setRecipient((TypedExpression) recipient.convertToTypedAST(localVar, classes, untypedFieldVarAccess.recursiveOwnerChain()));
typedFieldId.setName(untypedFieldVarAccess.id());
return typedFieldId;
}
}

View File

@ -0,0 +1,81 @@
package de.maishai.typedast.typedclass;
import de.maishai.ast.records.*;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.Type;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor;
import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data
@NoArgsConstructor
public class TypedFieldVarAccess implements TypedExpression {
private Boolean field;
private TypedExpression recursiveOwnerChain;
private String name;
private Type type;
public TypedFieldVarAccess(TypedClass clas, FieldVarAccess unTypedFieldVarAccess) {
convertToTypedFieldVarAccess(clas, unTypedFieldVarAccess);
}
public void convertToTypedFieldVarAccess(TypedClass clas, FieldVarAccess unTypedFieldVarAccess) {
field = unTypedFieldVarAccess.field();
recursiveOwnerChain = convertExpression(clas, unTypedFieldVarAccess.recursiveOwnerChain());
name = unTypedFieldVarAccess.id();
}
@Override
public Type typeCheck(TypedClass clas) {
if (field) {
if (clas.isThereField(name)) {
type = clas.getFieldType(name);
return clas.getFieldType(name);
}else{
throw new RuntimeException("Field " + name + " not declared ");
}
} else {
if (clas.isCurrentConstructorPresent()) {
if (clas.isParameterNameInCurrentConstructor(name)) {
type = clas.getParameterTypeInCurrentConstructor(name);
return type;
} else if (clas.getCurrentConstructor().isLocalVariablePresent(name)) {
type = clas.getCurrentConstructor().getLocalVariableType(name);
return type;
} else if(clas.isThereField(name)){
type = clas.getFieldType(name);
return type;
}
else {
throw new RuntimeException("Variable " + name + " not declared in constructor");
}
} else if (clas.isCurrentMethodPresent()) {
if (clas.isParameterWitNameInMethod(name)) {
type = clas.getParameterTypeInCurrentMethod(name);
return type;
} else if (clas.getCurrentMethod().isLocalVariablePresent(name)) {
type = clas.getCurrentMethod().getLocalVariableType(name);
return type;
} else if(clas.isThereField(name)){
type = clas.getFieldType(name);
return type;
}
else {
throw new RuntimeException("Variable " + name + " not declared in method");
}
}
throw new RuntimeException("Variable " + name + " not declared ");
}
}
@Override
public void codeGen(MethodContext ctx) {
}
}

View File

@ -1,6 +1,6 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.For; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -9,40 +9,42 @@ import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class TypedFor implements TypedStatement { public class TypedFor implements TypedStatement {
private TypedExpression assign; private TypedAssignment assign;
private TypedExpression cond; private TypedExpression cond;
private TypedExpression inc; private TypedAssignment inc;
private TypedBlock typedBlock; private TypedBlock typedBlock;
private Type type;
public TypedFor(TypedClass clas, For unTypedFor) {
convertToTypedFor(clas, unTypedFor);
}
public void convertToTypedFor(TypedClass clas, For unTypedFor) {
assign = new TypedAssignment(clas, unTypedFor.assign());
cond = convertExpression(clas, unTypedFor.cond());
inc = new TypedAssignment(clas, unTypedFor.inc());
typedBlock = new TypedBlock(clas, unTypedFor.block());
}
@Override @Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public Type typeCheck(TypedClass clas) {
assign.typeCheck(localVar, classes); assign.typeCheck(clas);
if(!cond.typeCheck(localVar, classes).equals(Type.BOOL)) { if (!cond.typeCheck(clas).equals(Type.BOOL)) {
throw new RuntimeException("Condition must be a boolean"); throw new RuntimeException("Condition must be a boolean");
} }
inc.typeCheck(localVar, classes); inc.typeCheck(clas);
return typedBlock.typeCheck(localVar, classes); type = typedBlock.typeCheck(clas);
return type;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
For untyped = (For) unTypedAST;
TypedFor typedFor = new TypedFor();
typedFor.setAssign((TypedExpression) assign.convertToTypedAST(localVar, classes, untyped.assign()));
typedFor.setCond((TypedExpression) cond.convertToTypedAST(localVar, classes, untyped.cond()));
typedFor.setInc((TypedExpression) inc.convertToTypedAST(localVar, classes, untyped.inc()));
TypedBlock typedBlock = new TypedBlock();
typedFor.setTypedBlock(typedBlock.unTypedBlockToTypedBlock(untyped.block()));
return typedFor;
}
@Override
public void codeGen(MethodVisitor mv, MethodContext ctx) {
} }
} }

View File

@ -1,48 +1,72 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.IfElse; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
@NoArgsConstructor
public class TypedIfElse implements TypedStatement { public class TypedIfElse implements TypedStatement {
private TypedExpression typedCon; private TypedExpression typedCon;
private TypedBlock ifTypedBlock; private TypedBlock ifTypedBlock;
private TypedBlock elseTypedBlock; private TypedBlock elseTypedBlock;
private Type type;
public TypedIfElse(TypedClass clas, IfElse unTypedIfElse) {
convertToTypedIfElse(clas, unTypedIfElse);
}
public void convertToTypedIfElse(TypedClass clas, IfElse unTypedIfElse) {
ifTypedBlock = new TypedBlock(clas, unTypedIfElse.ifBlock());
elseTypedBlock = new TypedBlock(clas, unTypedIfElse.elseBlock());
typedCon = convertExpression(clas, unTypedIfElse.cond());
}
@Override @Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public Type typeCheck(TypedClass clas) {
// condition must be a boolean /*
if (typedCon.typeCheck(localVar, classes) != Type.BOOL) { if (typedCon.typeCheck(clas) != Type.BOOL) {
throw new RuntimeException("If condition must be a boolean"); throw new RuntimeException("If condition must be a boolean");
} }
//Statement1 and Statement2 must be of type void if (ifTypedBlock.typeCheck(clas) != Type.VOID) {
if (ifTypedBlock.typeCheck(localVar, classes) != Type.VOID) {
throw new RuntimeException("If block must be of type void"); throw new RuntimeException("If block must be of type void");
} }
return Type.VOID; */
//TODO: it still not catching the all cases when return is used
if (ifTypedBlock.typeCheck(clas) == elseTypedBlock.typeCheck(clas)) {
type = ifTypedBlock.typeCheck(clas);
}
if (elseTypedBlock.typeCheck(clas) == Type.VOID) {
type = ifTypedBlock.typeCheck(clas);
}
if (ifTypedBlock.typeCheck(clas) == Type.VOID) {
type = elseTypedBlock.typeCheck(clas);
}
return type;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
IfElse ifElse = (IfElse) unTypedAST; Label falseLabel = new Label();
Label end = new Label();
typedCon.codeGen(ctx);
ctx.getMv().visitJumpInsn(Opcodes.IFEQ, falseLabel);
ifTypedBlock.codeGen(ctx);
ctx.getMv().visitJumpInsn(Opcodes.GOTO, end);
TypedIfElse typedIfElse = new TypedIfElse(); ctx.getMv().visitLabel(falseLabel);
typedIfElse.setTypedCon((TypedExpression) typedCon.convertToTypedAST(localVar, classes, ifElse.cond())); if (elseTypedBlock != null) {
elseTypedBlock.codeGen(ctx);
TypedBlock ifTypedBlock = new TypedBlock();
TypedBlock elseTypedBlock = new TypedBlock();
typedIfElse.setIfTypedBlock(ifTypedBlock.unTypedBlockToTypedBlock(ifElse.ifBlock()));
typedIfElse.setElseTypedBlock(elseTypedBlock.unTypedBlockToTypedBlock(ifElse.elseBlock()));
return typedIfElse;
} }
ctx.getMv().visitLabel(end);
@Override
public void codeGen(MethodVisitor mv, MethodContext ctx) {
} }
} }

View File

@ -1,28 +1,46 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.IntLiteral; import de.maishai.ast.records.IntLiteral;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode; import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor;
import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @RequiredArgsConstructor
public class TypedIntLiteral implements TypedExpression { public class TypedIntLiteral implements TypedExpression {
private Integer value; private Integer value;
@Override private Type type;
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
return Type.INT;
public TypedIntLiteral(TypedClass clas, IntLiteral unTypedIntLiteral) {
convertToTypedIntLiteral(clas, unTypedIntLiteral);
}
public void convertToTypedIntLiteral(TypedClass clas, IntLiteral unTypedIntLiteral) {
value = unTypedIntLiteral.value();
type = Type.INT;
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
IntLiteral untyped = (IntLiteral) unTypedAST; return type;
return new TypedIntLiteral(untyped.value()); }
public TypedIntLiteral(Integer value) {
this.value = value;
}
@Override
public void codeGen(MethodContext ctx) {
ctx.getMv().visitLdcInsn(value);
} }
} }

View File

@ -9,7 +9,6 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.Map;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ -17,29 +16,36 @@ public final class TypedLocalVariable implements TypedNode {
private String name; private String name;
private Type type; private Type type;
@Override public TypedLocalVariable(TypedClass clas, Declaration declaration) {
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { convertToTypedLocalVariable(clas, declaration);
if(localVar.containsKey(name)) {
throw new RuntimeException("Variable " + name + " already exists");
} }
localVar.put(name, type);
public void convertToTypedLocalVariable(TypedClass clas, Declaration declaration) {
name = declaration.name();
type = declaration.type();
typeCheck(clas);
}
@Override
public Type typeCheck(TypedClass clas) {
if (clas.isCurrentMethodPresent() && !clas.isCurrentConstructorPresent()) {
if (clas.getCurrentMethod().isLocalVariableInMethod(name)) {
throw new RuntimeException("Variable " + name + " already declared");
}
clas.getCurrentMethod().getLocalVariables().add(this);
return type; return type;
} }
if (!clas.isCurrentMethodPresent() && clas.isCurrentConstructorPresent()) {
@Override if (clas.getCurrentConstructor().isLocalVariableInConstructor(name)) {
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { throw new RuntimeException("Variable " + name + " already declared");
Declaration untypedLocalVariable = (Declaration) unTypedAST; }
TypedLocalVariable typedLocalVariable = new TypedLocalVariable(); clas.getCurrentConstructor().getLocalVariables().add(this);
return type;
typedLocalVariable.setName(untypedLocalVariable.name()); }
typedLocalVariable.setType(untypedLocalVariable.type()); throw new RuntimeException("not found method or constructor in class");
return typedLocalVariable;
} }
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodVisitor mv, MethodContext ctx) {
int index = ctx.addVariable(name); ctx.registerVariable(name, type);
mv.visitLocalVariable(name, type.getDescriptor(), null, ctx.getStartLabel(), ctx.getEndLabel(), index);
} }
} }

View File

@ -1,101 +1,121 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.IfElse;
import de.maishai.ast.records.Method; import de.maishai.ast.records.Method;
import de.maishai.ast.records.Parameter;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.ClassWriter; import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
@Data @Data
@NoArgsConstructor
public class TypedMethod implements TypedNode { public class TypedMethod implements TypedNode {
private String name; private String name;
private Type returnType; private Type returnType;
private List<TypedParameter> typedParameters; private List<TypedParameter> typedParameters = new ArrayList<>();
private List<TypedLocalVariable> localVariables = new ArrayList<>();
private TypedBlock typedBlock; private TypedBlock typedBlock;
public TypedMethod unTypedMethodToTypedMethod(Method unTypedMethod) { public TypedMethod(TypedClass clas, Method unTypedMethod) {
TypedMethod typedMethod = new TypedMethod(); convertToTypedMethod(clas, unTypedMethod);
typedMethod.setName(unTypedMethod.methodName()); }
typedMethod.setTypedParameters(new ArrayList<>());
if(unTypedMethod.params().isEmpty()){ public void convertToTypedMethod(TypedClass clas, Method unTypedMethod) {
typedMethod.setTypedParameters(List.of());
}else { name = unTypedMethod.methodName();
for (Parameter parameter : unTypedMethod.params()) { returnType = unTypedMethod.type();
TypedParameter typedParameter = new TypedParameter(); for (var parameter : unTypedMethod.params()) {
typedParameter.setParaName(parameter.name()); typedParameters.add(new TypedParameter(clas, parameter));
typedParameter.setType(parameter.type());
typedParameters.add(typedParameter);
} }
}
TypedBlock block = new TypedBlock(); clas.getTypedMethods().stream().filter(method -> method.equals(this)).findFirst().ifPresentOrElse(
typedMethod.setTypedBlock(block.unTypedBlockToTypedBlock(unTypedMethod.block())); method -> {
return typedMethod;
}
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
if(localVar.containsKey(name)) {
throw new RuntimeException("Method " + name + " already exists"); throw new RuntimeException("Method " + name + " already exists");
}, () -> {
});
} }
localVar.put(name, returnType);
for(TypedParameter typedParameter : typedParameters) { public void convertToTypedBlock(TypedClass clas, Method unTypedMethod) {
typedParameter.typeCheck(localVar, classes); typedBlock = new TypedBlock(clas, unTypedMethod.block());
typeCheck(clas);
}
public boolean isLocalVariablePresent(String localVarName) {
return localVariables.stream().anyMatch(localVariable -> localVariable.getName().equals(localVarName));
}
public boolean isParameterPresent(String parameterName) {
return typedParameters.stream().anyMatch(parameter -> parameter.getParaName().equals(parameterName));
}
public boolean isLocalVariableInMethod(String localVarName) {
return isLocalVariablePresent(localVarName) || isParameterPresent(localVarName);
}
public Type getLocalVariableType(String localVarName) {
return localVariables.stream().filter(localVariable -> localVariable.getName().equals(localVarName)).findFirst().get().getType();
}
private boolean hasEvenReturnsInIfElseBlocks() {
List<TypedIfElse> typedIfElses = new ArrayList<>();
for (var stmt : typedBlock.getStmts()) {
if (stmt instanceof TypedIfElse ifElse) {
for (var stmt2 : ifElse.getIfTypedBlock().getStmts()) {
if (stmt2 instanceof TypedReturn) {
typedIfElses.add(ifElse);
}
}
for (var stmt2 : ifElse.getElseTypedBlock().getStmts()) {
if (stmt2 instanceof TypedReturn) {
typedIfElses.add(ifElse);
}
}
}
}
if (typedIfElses.size() % 2 == 0) {
return true;
} else {
return false;
} }
return typedBlock.typeCheck(localVar, classes);
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
Method untypedMethod = (Method) unTypedAST; if (returnType != Type.VOID && !hasEvenReturnsInIfElseBlocks()) {
TypedMethod typedMethod = new TypedMethod(); if (typedBlock.typeCheck(clas).getKind() != returnType.getKind()) {
if (hasEvenReturnsInIfElseBlocks()) {
typedMethod.setTypedParameters(new ArrayList<>()); throw new RuntimeException("Method " + name + " must have even returns in if else blocks");
typedMethod.setName(untypedMethod.methodName()); } else {
typedMethod.setReturnType(untypedMethod.type()); throw new RuntimeException("Method " + name + " must return " + returnType.getKind());
}
for(Parameter parameter : untypedMethod.params()) { }
TypedParameter typedParameter = new TypedParameter(); }
typedParameter.setParaName(parameter.name()); return returnType;
typedParameter.setType(parameter.type());
typedMethod.getTypedParameters().add(typedParameter);
} }
TypedBlock typedBlock = new TypedBlock(); @Override
typedMethod.setTypedBlock(typedBlock.unTypedBlockToTypedBlock(untypedMethod.block())); public boolean equals(Object obj) {
if (obj instanceof TypedMethod) {
return typedMethod; TypedMethod other = (TypedMethod) obj;
return name.equals(other.name) && returnType.equals(other.returnType) && typedParameters.equals(other.typedParameters);
}
return false;
} }
private TypedParameter getTypedParameter(Parameter parameter) {
TypedParameter typedParameter = new TypedParameter();
typedParameter.setParaName(parameter.name());
if(parameter.type() == Type.CHAR){ public void codeGen(ClassContext ctx) {
typedParameter.setType(Type.CHAR);
}
if(parameter.type() == Type.BOOL){
typedParameter.setType(Type.BOOL);
}
if(parameter.type() == Type.INT){
typedParameter.setType(Type.INT);
}
return typedParameter;
}
public void codeGen(ClassWriter cw) {
int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok
MethodVisitor mv = cw.visitMethod(accessModifier, name, MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, name,
CodeGenUtils.generateDescriptor(typedParameters, returnType), null, null); CodeGenUtils.generateDescriptor(typedParameters, returnType), null, null);
MethodContext context = new MethodContext(mv); MethodContext context = new MethodContext(ctx, mv);
typedParameters.forEach(param -> context.registerVariable(param.getParaName(), param.getType()));
typedBlock.codeGen(mv, context); typedBlock.codeGen(context);
context.wrapUp();
} }
} }

View File

@ -1,31 +1,66 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Expression;
import de.maishai.ast.records.MethodCall;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor; import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
//TODO: test this after fixing error from parser
@Data @Data
@NoArgsConstructor
public class TypedMethodCall implements TypedExpression, TypedStatement { public class TypedMethodCall implements TypedExpression, TypedStatement {
private TypedExpression recipient; private TypedFieldVarAccess recipient;
private List<TypedExpression> args; private List<TypedExpression> args = new ArrayList<>();
private Type type;
@Override public TypedMethodCall(TypedClass clas, MethodCall unTypedMethodCall) {
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { convertToTypedMethodCall(clas, unTypedMethodCall);
//TODO: Implement typeCheck for MethodCall }
return null;
public void convertToTypedMethodCall(TypedClass clas, MethodCall unTypedMethodCall) {
recipient = new TypedFieldVarAccess(clas, unTypedMethodCall.recipient());
for (Expression arg : unTypedMethodCall.args()) {
args.add(convertExpression(clas, arg));
}
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
//TODO: Implement this if (clas.isCurrentMethodPresent() || clas.isCurrentConstructorPresent()) {
return null;
List<TypedMethod> methods = clas.getTypedMethods().stream()
.filter(method -> method.getName().equals(recipient.getName()))
.toList();
for (TypedMethod method : methods) {
if (method.getTypedParameters().size() == args.size()) {
boolean allMatch = true;
for (int i = 0; i < args.size(); i++) {
if (!args.get(i).typeCheck(clas).equals(method.getTypedParameters().get(i).getType())) {
allMatch = false;
break;
}
}
if (allMatch) {
type = method.getReturnType();
return type;
}
}
}
}
throw new RuntimeException("Method not found");
} }
@Override @Override
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodContext ctx) {
} }
} }

View File

@ -1,56 +1,55 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Expression;
import de.maishai.ast.records.New; import de.maishai.ast.records.New;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
public class TypedNew implements TypedExpression, TypedStatement { public class TypedNew implements TypedExpression, TypedStatement {
private Type type; private Type type;
private List<TypedExpression> args; private List<TypedExpression> args = new ArrayList<>();
@Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public TypedNew(TypedClass clas, New unTypedNew) {
// new A(1, 2, 3) convertToTypedNew(clas, unTypedNew);
if (!classes.containsKey(this.type.getReference())) {
throw new RuntimeException("Class " + this.type.getReference() + " not found");
} }
TypedClass klasse = classes.get(this.type.getReference()); public void convertToTypedNew(TypedClass clas, New unTypedNew) {
if (klasse.getTypedFields().size() != args.size()) { type = unTypedNew.type();
throw new RuntimeException("number of arguments is invalid for class" + this.type.getReference()); for (Expression arg : unTypedNew.args()) {
args.add(convertExpression(clas, arg));
} }
// compare the types of the arguments }
@Override
public Type typeCheck(TypedClass clas) {
for (var constructor : clas.getTypedConstructors()) {
if (constructor.getTypedParameters().size() == args.size()) {
boolean valid = true;
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
Type type = args.get(i).typeCheck(localVar, classes); if (!constructor.getTypedParameters().get(i).getType().equals(args.get(i).typeCheck(clas))) {
if (!type.equals(klasse.getTypedFields().get(i).getType())) { valid = false;
throw new RuntimeException("False type for argument " + i + " in class " + type.getKind()); break;
} }
} }
return Type.VOID; if (valid) {
return Type.REFERENCE(clas.getClassName());
} }
}
}
throw new RuntimeException("No matching constructor found");
}
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
New untyped = (New) unTypedAST;
TypedNew typedNew = new TypedNew();
typedNew.setType(untyped.type());
if(untyped.args().isEmpty()){
//TODO: Implement this
}
for(de.maishai.ast.records.Expression arg : untyped.args()) {
//TODO: Implement this
}
return typedNew;
}
@Override
public void codeGen(MethodVisitor mv, MethodContext ctx) {
} }
} }

View File

@ -1,37 +1,52 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Parameter; import de.maishai.ast.records.Parameter;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import de.maishai.typedast.TypedNode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import java.util.Map; import java.util.Map;
@AllArgsConstructor @AllArgsConstructor
@RequiredArgsConstructor
@Data @Data
public class TypedParameter implements TypedNode { public class TypedParameter implements TypedNode {
private String paraName; private String paraName;
private Type type; private Type type;
public TypedParameter(TypedClass clas, Parameter unTypedParameter) {
convertToTypedParameter(clas, unTypedParameter);
}
public void convertToTypedParameter(TypedClass clas, Parameter unTypedParameter) {
paraName = unTypedParameter.name();
type = unTypedParameter.type();
}
@Override @Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public boolean equals(Object obj) {
if (localVar.containsKey(paraName)) { if (obj instanceof TypedParameter) {
TypedParameter other = (TypedParameter) obj;
return paraName.equals(other.paraName) && type.equals(other.type);
}
return false;
}
@Override
public Type typeCheck(TypedClass clas) {
if (clas.isCurrentMethodPresent()) {
if (clas.isParameterWitNameInMethod(paraName)) {
throw new RuntimeException("Parameter " + paraName + " already exists"); throw new RuntimeException("Parameter " + paraName + " already exists");
} }
localVar.put(paraName, type); } else if (clas.isCurrentConstructorPresent()) {
return type; if (clas.isParameterWitNameInConstructor(paraName)) {
throw new RuntimeException("Parameter " + paraName + " already exists");
} }
@Override }
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
Parameter untyped = (Parameter) unTypedAST; return type;
TypedParameter typedParameter = new TypedParameter();
typedParameter.setParaName(untyped.name());
typedParameter.setType(untyped.type());
return typedParameter;
} }

View File

@ -1,31 +1,63 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.Return; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
@NoArgsConstructor
public class TypedReturn implements TypedStatement { public class TypedReturn implements TypedStatement {
private TypedExpression ret; private TypedExpression ret;
private Type type;
@Override public TypedReturn(TypedClass clas, Return unTypedReturn) {
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { convertToTypedReturn(clas, unTypedReturn);
return ret.typeCheck(localVar, classes); }
public void convertToTypedReturn(TypedClass clas, Return unTypedReturn) {
ret = convertExpression(clas, unTypedReturn.ret());
if(ret == null){
type = Type.VOID;
}else{
type = ret.getType();
}
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public Type typeCheck(TypedClass clas) {
Return untyped = (Return) unTypedAST; if (clas.isCurrentMethodPresent()) {
TypedReturn typedReturn = new TypedReturn(); if (clas.getCurrentMethod().getReturnType().getKind() != this.type.getKind()) {
typedReturn.setRet((TypedExpression) ret.convertToTypedAST(localVar, classes, untyped.ret())); StringBuilder exp = new StringBuilder();
return typedReturn; exp.append("\nMismatched return type: ");
exp.append("\nExpected: ").append(clas.getCurrentMethod().getReturnType().getKind());
exp.append("\nActual: ").append(this.type.getKind());
exp.append("\nMethod name: ").append(clas.getCurrentMethod().getName());
throw new RuntimeException(exp.toString());
}
}
return type;
} }
@Override @Override
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodContext ctx) {
if (ret == null) {
ctx.getMv().visitInsn(Opcodes.RETURN);
} else {
ret.codeGen(ctx);
if (ret.getType().getKind() != Type.Kind.REFERENCE) {
ctx.getMv().visitInsn(Opcodes.IRETURN);
} else {
ctx.getMv().visitInsn(Opcodes.ARETURN);
}
}
} }
} }

View File

@ -2,28 +2,44 @@ package de.maishai.typedast.typedclass;
import de.maishai.ast.UnaryOperator; import de.maishai.ast.UnaryOperator;
import de.maishai.ast.records.Unary; import de.maishai.ast.records.Unary;
import de.maishai.typedast.MethodContext;
import de.maishai.typedast.TypedExpression; import de.maishai.typedast.TypedExpression;
import de.maishai.typedast.TypedNode;
import de.maishai.typedast.Type; import de.maishai.typedast.Type;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
public class TypedUnary implements TypedExpression { public class TypedUnary implements TypedExpression {
private UnaryOperator op; private UnaryOperator op;
private TypedExpression right; private TypedExpression right;
@Override private Type type;
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
if(op == UnaryOperator.NOT){ public TypedUnary(TypedClass clas, Unary unTypedUnary) {
if(right.typeCheck(localVar, classes) != Type.BOOL){ convertToTypedUnary(clas, unTypedUnary);
}
public void convertToTypedUnary(TypedClass clas, Unary unTypedUnary) {
op = unTypedUnary.op();
right = convertExpression(clas, unTypedUnary.right());
}
@Override
public Type typeCheck(TypedClass clas) {
if (op == UnaryOperator.NOT) {
if (right.typeCheck(clas) != Type.BOOL) {
throw new RuntimeException("Not operator must be applied to boolean"); throw new RuntimeException("Not operator must be applied to boolean");
} }
return Type.BOOL; return Type.BOOL;
} }
if(op == UnaryOperator.SUB){ if (op == UnaryOperator.SUB) {
if(right.typeCheck(localVar, classes) != Type.INT){ if (right.typeCheck(clas) != Type.INT) {
throw new RuntimeException("Minus operator must be applied to int"); throw new RuntimeException("Minus operator must be applied to int");
} }
return Type.INT; return Type.INT;
@ -32,11 +48,14 @@ public class TypedUnary implements TypedExpression {
} }
@Override @Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) { public void codeGen(MethodContext ctx) {
Unary untyped = (Unary) unTypedAST; right.codeGen(ctx);
TypedUnary typedUnary = new TypedUnary(); if(op == UnaryOperator.NOT){
typedUnary.setOp(untyped.op()); ctx.getMv().visitInsn(Opcodes.ICONST_1);
typedUnary.setRight((TypedExpression) right.convertToTypedAST(localVar, classes, untyped.right())); ctx.getMv().visitInsn(Opcodes.IXOR);
return typedUnary; }
if(op == UnaryOperator.SUB){
ctx.getMv().visitInsn(Opcodes.INEG);
}
} }
} }

View File

@ -1,36 +1,41 @@
package de.maishai.typedast.typedclass; package de.maishai.typedast.typedclass;
import de.maishai.ast.records.While; import de.maishai.ast.records.*;
import de.maishai.typedast.*; import de.maishai.typedast.*;
import lombok.Data; import lombok.Data;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
@Data @Data
public class TypedWhile implements TypedStatement { public class TypedWhile implements TypedStatement {
private TypedExpression cond; private TypedExpression cond;
private TypedBlock typedBlock; private TypedBlock typedBlock;
private Type type;
public TypedWhile(TypedClass clas, While unTypedWhile) {
convertToTypedWhile(clas, unTypedWhile);
}
public void convertToTypedWhile(TypedClass clas, While unTypedWhile) {
cond = convertExpression(clas, unTypedWhile.cond());
typedBlock = new TypedBlock(clas, unTypedWhile.block());
}
@Override @Override
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) { public Type typeCheck(TypedClass clas) {
if(cond.typeCheck(localVar, classes) != Type.BOOL){ if (cond.typeCheck(clas) != Type.BOOL) {
throw new RuntimeException("While condition must be a boolean"); throw new RuntimeException("While condition must be a boolean");
} }
return typedBlock.typeCheck(localVar, classes); type = typedBlock.typeCheck(clas);
return type;
} }
@Override
public TypedNode convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
While untyped = (While) unTypedAST;
TypedWhile typedWhile = new TypedWhile();
typedWhile.setCond((TypedExpression) cond.convertToTypedAST(localVar, classes, untyped.cond()));
TypedBlock typedBlock = new TypedBlock();
typedWhile.setTypedBlock(typedBlock.unTypedBlockToTypedBlock(untyped.block()));
return typedWhile;
}
@Override @Override
public void codeGen(MethodVisitor mv, MethodContext ctx) { public void codeGen(MethodContext ctx) {
} }
} }

View File

@ -0,0 +1,81 @@
public class ClassCanBeTyped {
int x;
int y;
ClassCanBeTyped b;
ClassCanBeTyped c;
public ClassCanBeTyped(int x) {
this.x = x;
}
public ClassCanBeTyped(int x, int y) {
this.x = x;
this.y = y;
}
public ClassCanBeTyped initClassCanBeTyped(int x) {
int a;
a = 10;
b = new ClassCanBeTyped(x);
b.x = 10 + a;
b.y = 20;
b.c.x = 20 + a;
b.c.b.y = b.x;
return b;
}
public ClassCanBeTyped init(int x, int y) {
return new ClassCanBeTyped(x, y);
}
public ClassCanBeTyped(int x) {
this.x = x;
int i;
b = b.getX().c.getC();
i = b.getX().c.getX();
}
public ClassCanBeTyped() {
this.x = 10;
int i;
for (i = 0; i < (x + 1); i = i + 1) {
int j;
for (j = 0; j < this.x; j += 1) {
this.x = this.x * this.x;
break;
}
}
do {
this.y = this.y + 1;
} while (this.y < 10);
int k;
k = 0;
for (k = 0; k < 10; k = k + 1) {
if (k == 5) {
return;
}
}
}
public ClassCanBeTyped(int x, int y, char z) {
this.x = x;
this.y = y;
}
public int getX(char z) {
return this.x;
}
public ClassCanBeTyped getC() {
return c;
}
public int getX() {
return x;
}
public boolean methodCall() {
return false;
}
}