Start testing

This commit is contained in:
Victorious3 2022-05-15 18:45:49 +02:00
parent 590a4f04ae
commit 8666bfdf17
24 changed files with 581 additions and 36 deletions

View File

@ -4,17 +4,17 @@ import de.dhbwstuttgart.target.tree.TargetClass;
import de.dhbwstuttgart.target.tree.TargetConstructor;
import de.dhbwstuttgart.target.tree.TargetField;
import de.dhbwstuttgart.target.tree.TargetMethod;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.expression.TargetExpression;
import de.dhbwstuttgart.target.tree.expression.TargetVarDecl;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import javassist.compiler.CodeGen;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import java.util.Map;
import static org.objectweb.asm.Opcodes.*;
import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*;
public class Codegen {
private TargetClass clazz;
@ -25,9 +25,9 @@ public class Codegen {
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
}
private record LocalVar(int index, String name, TargetType type) {}
private static record LocalVar(int index, String name, TargetType type) {}
private class Scope {
private static class Scope {
Scope parent;
Map<String, LocalVar> locals;
@ -51,7 +51,7 @@ public class Codegen {
}
}
private class State {
private static class State {
Scope scope = new Scope(null);
int localCounter = 1;
MethodVisitor mv;
@ -74,22 +74,488 @@ public class Codegen {
}
}
private void boxPrimitive(State state, TargetType type) {
var mv = state.mv;
if (type.equals(TargetType.Boolean)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
} else if (type.equals(TargetType.Byte)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
} else if (type.equals(TargetType.Double)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
} else if (type.equals(TargetType.Long)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(L)Ljava/lang/Long;", false);
} else if (type.equals(TargetType.Integer)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(L)Ljava/lang/Integer;", false);
} else if (type.equals(TargetType.Float)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
} else if (type.equals(TargetType.Short)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
} else if (type.equals(TargetType.Char)) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Char", "valueOf", "(C)Ljava/lang/Char;", false);
}
}
private void unboxPrimitive(State state, TargetType type) {
var mv = state.mv;
if (type.equals(TargetType.Boolean)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
} else if (type.equals(TargetType.Byte)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
} else if (type.equals(TargetType.Double)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
} else if (type.equals(TargetType.Long)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()L", false);
} else if (type.equals(TargetType.Integer)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
} else if (type.equals(TargetType.Float)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
} else if (type.equals(TargetType.Short)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
} else if (type.equals(TargetType.Char)) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Char", "charValue", "()C", false);
}
}
private void generateRelationalOperator(State state, TargetBinaryOp op, int code) {
var mv = state.mv;
Label if_true = new Label();
Label end = new Label();
generate(state, op.left());
generate(state, op.right());
mv.visitJumpInsn(code, if_true);
mv.visitInsn(ICONST_0);
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(if_true);
mv.visitInsn(ICONST_1);
mv.visitLabel(end);
}
private void generateRelationalOperator(State state, TargetBinaryOp op, int cmp, int code) {
var mv = state.mv;
Label if_true = new Label();
Label end = new Label();
generate(state, op.left());
generate(state, op.right());
mv.visitInsn(cmp);
mv.visitInsn(code);
mv.visitJumpInsn(code, if_true);
mv.visitInsn(ICONST_0);
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(if_true);
mv.visitInsn(ICONST_1);
mv.visitLabel(end);
}
private void generateBinaryOp(State state, TargetBinaryOp op) {
var mv = state.mv;
switch (op) {
case Add add: {
generate(state, add.left());
generate(state, add.right());
var type = add.type();
if (type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)
|| type.equals(TargetType.Short)) {
mv.visitInsn(IADD);
} else if (type.equals(TargetType.Long)) {
mv.visitInsn(LADD);
} else if (type.equals(TargetType.Float)) {
mv.visitInsn(FADD);
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DADD);
} else {
throw new CodeGenException("Invalid argument to Add expression");
}
break;
}
case Sub sub: {
generate(state, sub.left());
generate(state, sub.right());
var type = sub.type();
if (type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)
|| type.equals(TargetType.Short)) {
mv.visitInsn(ISUB);
} else if (type.equals(TargetType.Long)) {
mv.visitInsn(LSUB);
} else if (type.equals(TargetType.Float)) {
mv.visitInsn(FSUB);
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DSUB);
} else {
throw new CodeGenException("Invalid argument to Sub expression");
}
break;
}
case Div div: {
generate(state, div.left());
generate(state, div.right());
var type = div.type();
if (type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)
|| type.equals(TargetType.Short)) {
mv.visitInsn(IDIV);
} else if (type.equals(TargetType.Long)) {
mv.visitInsn(LDIV);
} else if (type.equals(TargetType.Float)) {
mv.visitInsn(FDIV);
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DDIV);
} else {
throw new CodeGenException("Invalid argument to Div expression");
}
break;
}
case Mul mul: {
generate(state, mul.left());
generate(state, mul.right());
var type = mul.type();
if (type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)
|| type.equals(TargetType.Short)) {
mv.visitInsn(IMUL);
} else if (type.equals(TargetType.Long)) {
mv.visitInsn(LMUL);
} else if (type.equals(TargetType.Float)) {
mv.visitInsn(FMUL);
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DMUL);
} else {
throw new CodeGenException("Invalid argument to Mul expression");
}
break;
}
case Rem rem: {
generate(state, rem.left());
generate(state, rem.right());
var type = rem.type();
if (type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)
|| type.equals(TargetType.Short)) {
mv.visitInsn(IREM);
} else if (type.equals(TargetType.Long)) {
mv.visitInsn(LREM);
} else if (type.equals(TargetType.Float)) {
mv.visitInsn(FREM);
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DREM);
} else {
throw new CodeGenException("Invalid argument to Rem expression");
}
break;
}
case Or or: {
Label or_false = new Label();
Label or_true = new Label();
Label end = new Label();
generate(state, or.left());
mv.visitJumpInsn(IFNE, or_true);
generate(state, or.right());
mv.visitJumpInsn(IFEQ, or_false);
mv.visitLabel(or_true);
mv.visitInsn(ICONST_1);
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(or_false);
mv.visitInsn(ICONST_0);
mv.visitLabel(end);
break;
}
case And and: {
Label and_false = new Label();
Label end = new Label();
generate(state, and.left());
mv.visitJumpInsn(IFEQ, and_false);
generate(state, and.right());
mv.visitJumpInsn(IFEQ, and_false);
mv.visitInsn(ICONST_1);
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(and_false);
mv.visitInsn(ICONST_0);
mv.visitLabel(end);
break;
}
case BAnd band: {
generate(state, band.left());
generate(state, band.right());
if (band.type().equals(TargetType.Long))
mv.visitInsn(LAND);
else mv.visitInsn(IAND);
break;
}
case BOr bor: {
generate(state, bor.left());
generate(state, bor.right());
if (bor.type().equals(TargetType.Long))
mv.visitInsn(LOR);
else mv.visitInsn(IOR);
break;
}
case XOr xor: {
generate(state, xor.left());
generate(state, xor.right());
if (xor.type().equals(TargetType.Long))
mv.visitInsn(LXOR);
else mv.visitInsn(IXOR);
break;
}
case Shl shl: {
generate(state, shl.left());
generate(state, shl.right());
if (shl.type().equals(TargetType.Long))
mv.visitInsn(LSHL);
else mv.visitInsn(ISHL);
break;
}
case Shr shr: {
generate(state, shr.left());
generate(state, shr.right());
if (shr.type().equals(TargetType.Long))
mv.visitInsn(LSHR);
else mv.visitInsn(ISHR);
break;
}
case UShr ushr: {
generate(state, ushr.left());
generate(state, ushr.right());
if (ushr.type().equals(TargetType.Long))
mv.visitInsn(LUSHR);
else mv.visitInsn(IUSHR);
break;
}
case Greater greater: {
var type = greater.type();
if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, greater, LCMP, IFGT);
} else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, greater, FCMPL, IFGT);
} else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, greater, DCMPL, IFGT);
} else {
generateRelationalOperator(state, greater, IF_ICMPGT);
}
break;
}
case Less less: {
var type = less.type();
if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, less, LCMP, IFLT);
} else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, less, FCMPL, IFLT);
} else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, less, DCMPL, IFLT);
} else {
generateRelationalOperator(state, less, IF_ICMPLT);
}
break;
}
case GreaterOrEqual greaterOrEqual: {
var type = greaterOrEqual.type();
if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, greaterOrEqual, LCMP, IFGE);
} else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, greaterOrEqual, FCMPL, IFGE);
} else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, greaterOrEqual, DCMPL, IFGE);
} else {
generateRelationalOperator(state, greaterOrEqual, IF_ICMPGE);
}
break;
}
case LessOrEqual lessOrEqual: {
var type = lessOrEqual.type();
if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, lessOrEqual, LCMP, IFLE);
} else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, lessOrEqual, FCMPL, IFLE);
} else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, lessOrEqual, DCMPL, IFLE);
} else {
generateRelationalOperator(state, lessOrEqual, IF_ICMPLE);
}
break;
}
case Equal equal: {
var type = equal.type();
if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, equal, LCMP, IFEQ);
} else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, equal, FCMPL, IFEQ);
} else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, equal, DCMPL, IFEQ);
} else if (type.equals(TargetType.Char)
|| type.equals(TargetType.Short)
|| type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)) {
generateRelationalOperator(state, equal, IF_ICMPEQ);
} else {
generateRelationalOperator(state, equal, IF_ACMPEQ);
}
break;
}
case NotEqual notEqual: {
var type = notEqual.type();
if (type.equals(TargetType.Long)) {
generateRelationalOperator(state, notEqual, LCMP, IFNE);
} else if (type.equals(TargetType.Float)) {
generateRelationalOperator(state, notEqual, FCMPL, IFNE);
} else if (type.equals(TargetType.Double)) {
generateRelationalOperator(state, notEqual, DCMPL, IFNE);
} else if (type.equals(TargetType.Char)
|| type.equals(TargetType.Short)
|| type.equals(TargetType.Byte)
|| type.equals(TargetType.Integer)) {
generateRelationalOperator(state, notEqual, IF_ICMPNE);
} else {
generateRelationalOperator(state, notEqual, IF_ACMPNE);
}
break;
}
}
}
private void generateLambdaExpression(State state, TargetLambdaExpression lambda) {
}
private void generate(State state, TargetExpression expr) {
var mv = state.mv;
switch (expr) {
case TargetBlock block:
case TargetBlock block: {
var localCounter = state.localCounter;
state.enterScope();
for (var e : block.statements()) {
generate(state, e);
if (e instanceof TargetMethodCall) {
if (e.type() != null) mv.visitInsn(POP);
} else if (e instanceof TargetStatementExpression) {
mv.visitInsn(POP);
}
}
state.exitScope();
state.localCounter = localCounter;
break;
}
case TargetVarDecl varDecl:
state.createVariable(varDecl.name(), varDecl.varType());
break;
case TargetBinaryOp op:
generateBinaryOp(state, op);
break;
case TargetAssign assign: {
switch (assign.left()) {
case TargetLocalVar local: {
generate(state, assign.right());
boxPrimitive(state, assign.right().type());
mv.visitInsn(ASTORE);
break;
}
case TargetFieldVar dot: {
generate(state, dot.left());
TargetRefType type = (TargetRefType) dot.type();
generate(state, assign.right());
boxPrimitive(state, assign.right().type());
if (dot.isStatic())
mv.visitInsn(DUP);
else mv.visitInsn(DUP_X1);
mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.right(), type.name(), type.toSignature());
break;
}
default:
throw new IllegalStateException("Unexpected value: " + expr);
throw new CodeGenException("Invalid assignment");
}
break;
}
case TargetLocalVar localVar: {
LocalVar local = state.scope.get(localVar.name());
mv.visitVarInsn(ALOAD, local.index());
unboxPrimitive(state, local.type());
break;
}
case TargetFieldVar dot: {
if (!dot.isStatic())
generate(state, dot.left());
var type = (TargetRefType) dot.left().type();
mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, type.name(), dot.right(), dot.type().toSignature());
break;
}
case TargetFor _for: {
state.enterScope();
var localCounter = state.localCounter;
if (_for.init() != null)
generate(state, _for.init());
Label start = new Label();
Label end = new Label();
mv.visitLabel(start);
if (_for.termination() != null)
generate(state, _for.termination());
mv.visitJumpInsn(IFEQ, end);
generate(state, _for.body());
if (_for.increment() != null) {
generate(state, _for.increment());
if (_for.increment().type() != null) {
mv.visitInsn(POP);
}
}
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end);
state.exitScope();
state.localCounter = localCounter;
break;
}
case TargetWhile _while: {
Label start = new Label();
Label end = new Label();
mv.visitLabel(start);
generate(state, _while.cond());
mv.visitJumpInsn(IFEQ, end);
generate(state, _while.body());
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end);
break;
}
case TargetIf _if: {
generate(state, _if.cond());
Label _else = new Label();
Label end = new Label();
mv.visitJumpInsn(IFEQ, _else);
generate(state, _if.if_body());
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(_else);
if (_if.else_body() != null) {
generate(state, _if.else_body());
}
mv.visitLabel(end);
break;
}
case TargetReturn ret: {
generate(state, ret.expression());
if (ret.expression() != null)
mv.visitInsn(ARETURN);
else mv.visitInsn(RETURN);
break;
}
case TargetThis _this: {
mv.visitVarInsn(ALOAD, 0);
break;
}
case TargetSuper _super: {
// TODO
break;
}
case TargetMethodCall call: {
var method = call.method();
generate(state, call.expr());
for (TargetExpression e : call.args()) {
generate(state, e);
boxPrimitive(state, e.type());
}
mv.visitMethodInsn(method.isStatic() ? INVOKESTATIC: INVOKEVIRTUAL, method.owner().qualifiedName(), method.name(), method.getDescriptor(), false);
break;
}
case TargetLambdaExpression lambda:
generateLambdaExpression(state, lambda);
break;
default:
throw new CodeGenException("Unexpected value: " + expr);
}
}
@ -99,6 +565,7 @@ public class Codegen {
private void generateConstructor(TargetConstructor constructor) {
MethodVisitor mv = cw.visitMethod(constructor.access(), "<init>", constructor.getDescriptor(), null, null);
mv.visitCode();
generate(new State(mv), constructor.block());
mv.visitMaxs(0, 0);
mv.visitEnd();
@ -106,6 +573,7 @@ public class Codegen {
private void generateMethod(TargetMethod method) {
MethodVisitor mv = cw.visitMethod(method.access(), method.name(), method.getDescriptor(), null, null);
mv.visitCode();
generate(new State(mv), method.block());
mv.visitMaxs(0, 0);
mv.visitEnd();

View File

@ -30,7 +30,8 @@ public class ASTToTargetAST {
private TargetMethod convert(Method input, Map<TypePlaceholder, TargetType> sigma) {
List<MethodParameter> params = input.getParameterList().getFormalparalist().stream()
.map(param -> new MethodParameter(convert(param.getType(), sigma), param.getName())).collect(Collectors.toList());
return new TargetMethod(input.name, params, convert(input.block));
// TODO
return new TargetMethod(0, null, input.name, params, convert(input.block));
}
private TargetBlock convert(Block block) {

View File

@ -1,10 +1,32 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, List<TargetType> implementingInterfaces,
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {}
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
public TargetClass(int modifiers, String qualifiedName) {
this(modifiers, qualifiedName, TargetType.Object, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
}
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
this(modifiers, qualifiedName, TargetType.Object, implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
}
public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetBlock block) {
this.methods.add(new TargetMethod(access, this, name, parameterTypes, block));
}
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
this.constructors.add(new TargetConstructor(access, this, paramterTypes, block));
}
public void addField(int access, TargetType type, String name) {
this.fields.add(new TargetField(access, this, type, name));
}
}

View File

@ -4,7 +4,7 @@ import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import java.util.List;
public record TargetConstructor(int access, List<MethodParameter> parameterTypes, TargetBlock block) {
public record TargetConstructor(int access, TargetClass owner, List<MethodParameter> parameterTypes, TargetBlock block) {
public String getDescriptor() {
// TODO

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.type.TargetType;
import org.objectweb.asm.Opcodes;
public record TargetField(int access, TargetType type, String name) {
public record TargetField(int access, TargetClass owner, TargetType type, String name) {
public String getDescriptor() {
// TODO
return null;

View File

@ -0,0 +1,6 @@
package de.dhbwstuttgart.target.tree;
import java.util.List;
public record TargetInterface(String name, List<TargetMethod> methods, List<TargetInterface> extendedInterfaces) {
}

View File

@ -1,13 +1,18 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import org.objectweb.asm.Opcodes;
import java.util.List;
public record TargetMethod(int access, String name, List<MethodParameter> parameterTypes, TargetBlock block) {
public record TargetMethod(int access, TargetClass owner, String name, List<MethodParameter> parameterTypes, TargetBlock block) {
public String getDescriptor() {
// TODO
return null;
}
public boolean isStatic() {
return (access & Opcodes.ACC_STATIC) != 0;
}
}

View File

@ -2,5 +2,5 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetAssign(TargetType type, TargetExpression leftSide, TargetExpression rightSide) implements TargetExpression {
public record TargetAssign(TargetType type, TargetExpression left, TargetExpression right) implements TargetStatementExpression {
}

View File

@ -7,7 +7,7 @@ public sealed interface TargetBinaryOp extends TargetExpression {
TargetExpression left();
TargetExpression right();
// Artihmetic
// Arithmetic
record Add(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
record Sub(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
record Div(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
@ -34,7 +34,6 @@ public sealed interface TargetBinaryOp extends TargetExpression {
record LessOrEqual(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
record NotEqual(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
record Assign(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
}

View File

@ -0,0 +1,6 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetClassName(TargetType type) implements TargetExpression {
}

View File

@ -1,6 +0,0 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetDot(TargetType type, boolean isStatic, TargetExpression left, String right) implements TargetExpression {
}

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.*;
public sealed interface TargetExpression
permits TargetAssign, TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetContinue, TargetDot, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetMethodCall, TargetNew, TargetReturn, TargetSuper, TargetSwitch, TargetThis, TargetUnaryOp, TargetVarDecl, TargetWhile {
permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetTernary, TargetThis, TargetUnaryOp, TargetVarDecl, TargetWhile {
TargetType type();
}

View File

@ -1,7 +1,6 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.TargetField;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetFieldVar(TargetType type, TargetField field) implements TargetExpression {
public record TargetFieldVar(TargetType type, boolean isStatic, TargetExpression left, String right) implements TargetExpression {
}

View File

@ -2,7 +2,7 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetIf(TargetExpression expr, TargetExpression if_body, TargetExpression else_body) implements TargetExpression {
public record TargetIf(TargetExpression cond, TargetExpression if_body, TargetExpression else_body) implements TargetExpression {
@Override
public TargetType type() {
return null;

View File

@ -5,5 +5,5 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List;
public record TargetMethodCall(TargetType type, TargetExpression expr, List<TargetExpression> args, TargetMethod method) implements TargetExpression {
public record TargetMethodCall(TargetType type, TargetExpression expr, List<TargetExpression> args, TargetMethod method) implements TargetStatementExpression {
}

View File

@ -4,5 +4,5 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List;
public record TargetNew(TargetType type, List<TargetExpression> params) implements TargetExpression {
public record TargetNew(TargetType type, List<TargetExpression> params) implements TargetStatementExpression {
}

View File

@ -0,0 +1,4 @@
package de.dhbwstuttgart.target.tree.expression;
public sealed interface TargetStatementExpression extends TargetExpression permits TargetAssign, TargetMethodCall, TargetNew, TargetUnaryOp.PostDecrement, TargetUnaryOp.PostIncrement, TargetUnaryOp.PreDecrement, TargetUnaryOp.PreIncrement {
}

View File

@ -0,0 +1,6 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetTernary(TargetType type, TargetExpression cond, TargetExpression ifTrue, TargetExpression ifFalse) implements TargetExpression {
}

View File

@ -8,8 +8,8 @@ public sealed interface TargetUnaryOp extends TargetExpression {
record Negate(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record Not(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record PreIncrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record PostIncrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record PreDecrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record PostDecrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record PreIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
record PostIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
record PreDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
record PostDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
}

View File

@ -2,7 +2,7 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetWhile(TargetExpression expr, TargetExpression body) implements TargetExpression {
public record TargetWhile(TargetExpression cond, TargetExpression body) implements TargetExpression {
@Override
public TargetType type() {

View File

@ -7,6 +7,6 @@ import java.util.List;
public record TargetRefType(String name, List<TargetType> params) implements TargetType {
@Override
public String toSignature() {
return "L" + this.name.replaceAll("\\.", "/");
return "L" + this.name.replaceAll("\\.", "/") + ";";
}
}

View File

@ -15,6 +15,7 @@ public sealed interface TargetType
TargetRefType Float = new TargetRefType("java.lang.Float", List.of());
TargetRefType Double = new TargetRefType("java.lang.Double", List.of());
TargetRefType String = new TargetRefType("java.lang.String", List.of());
TargetRefType Object = new TargetRefType("java.lang.Object", List.of());
String toSignature();
}

View File

@ -0,0 +1,9 @@
package targetast;
import java.util.Map;
public class ByteArrayClassLoader extends ClassLoader {
public Class loadClass(byte[] code) {
return this.defineClass(null, code, 0, code.length);
}
}

View File

@ -0,0 +1,25 @@
package targetast;
import de.dhbwstuttgart.target.bytecode.Codegen;
import de.dhbwstuttgart.target.tree.TargetClass;
import de.dhbwstuttgart.target.tree.TargetMethod;
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import org.junit.Test;
import org.objectweb.asm.Opcodes;
import java.util.List;
public class TestCodegen {
private static Class generateClass(TargetClass clazz) {
var codegen = new Codegen(clazz);
return new ByteArrayClassLoader().loadClass(codegen.generate());
}
@Test
public void testEmptyClass() throws Exception {
var clazz = new TargetClass(Opcodes.ACC_PUBLIC, "Main");
clazz.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "main", List.of(), new TargetBlock(List.of()));
generateClass(clazz).getDeclaredMethod("main").invoke(null);
}
}