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.TargetConstructor;
import de.dhbwstuttgart.target.tree.TargetField; import de.dhbwstuttgart.target.tree.TargetField;
import de.dhbwstuttgart.target.tree.TargetMethod; import de.dhbwstuttgart.target.tree.TargetMethod;
import de.dhbwstuttgart.target.tree.expression.TargetBlock; import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.expression.TargetExpression; import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.expression.TargetVarDecl;
import de.dhbwstuttgart.target.tree.type.TargetType; import de.dhbwstuttgart.target.tree.type.TargetType;
import javassist.compiler.CodeGen;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.Map; import java.util.Map;
import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Opcodes.*;
import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*;
public class Codegen { public class Codegen {
private TargetClass clazz; private TargetClass clazz;
@ -25,9 +25,9 @@ public class Codegen {
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); 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; Scope parent;
Map<String, LocalVar> locals; Map<String, LocalVar> locals;
@ -51,7 +51,7 @@ public class Codegen {
} }
} }
private class State { private static class State {
Scope scope = new Scope(null); Scope scope = new Scope(null);
int localCounter = 1; int localCounter = 1;
MethodVisitor mv; 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) { private void generate(State state, TargetExpression expr) {
var mv = state.mv;
switch (expr) { switch (expr) {
case TargetBlock block: case TargetBlock block: {
var localCounter = state.localCounter; var localCounter = state.localCounter;
state.enterScope(); state.enterScope();
for (var e : block.statements()) { for (var e : block.statements()) {
generate(state, e); 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.exitScope();
state.localCounter = localCounter; state.localCounter = localCounter;
break; break;
}
case TargetVarDecl varDecl: case TargetVarDecl varDecl:
state.createVariable(varDecl.name(), varDecl.varType()); state.createVariable(varDecl.name(), varDecl.varType());
break; 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 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: default:
throw new IllegalStateException("Unexpected value: " + expr); throw new CodeGenException("Unexpected value: " + expr);
} }
} }
@ -99,6 +565,7 @@ public class Codegen {
private void generateConstructor(TargetConstructor constructor) { private void generateConstructor(TargetConstructor constructor) {
MethodVisitor mv = cw.visitMethod(constructor.access(), "<init>", constructor.getDescriptor(), null, null); MethodVisitor mv = cw.visitMethod(constructor.access(), "<init>", constructor.getDescriptor(), null, null);
mv.visitCode();
generate(new State(mv), constructor.block()); generate(new State(mv), constructor.block());
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
@ -106,6 +573,7 @@ public class Codegen {
private void generateMethod(TargetMethod method) { private void generateMethod(TargetMethod method) {
MethodVisitor mv = cw.visitMethod(method.access(), method.name(), method.getDescriptor(), null, null); MethodVisitor mv = cw.visitMethod(method.access(), method.name(), method.getDescriptor(), null, null);
mv.visitCode();
generate(new State(mv), method.block()); generate(new State(mv), method.block());
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();

View File

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

View File

@ -1,10 +1,32 @@
package de.dhbwstuttgart.target.tree; 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.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType; import de.dhbwstuttgart.target.tree.type.TargetType;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, List<TargetType> implementingInterfaces, 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; 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() { public String getDescriptor() {
// TODO // TODO

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.type.TargetType; import de.dhbwstuttgart.target.tree.type.TargetType;
import org.objectweb.asm.Opcodes; 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() { public String getDescriptor() {
// TODO // TODO
return null; 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; package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetBlock; import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import org.objectweb.asm.Opcodes;
import java.util.List; 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() { public String getDescriptor() {
// TODO // TODO
return null; 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; 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 left();
TargetExpression right(); TargetExpression right();
// Artihmetic // Arithmetic
record Add(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {} record Add(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
record Sub(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 {} 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 LessOrEqual(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {}
record NotEqual(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.*; import de.dhbwstuttgart.target.tree.type.*;
public sealed interface TargetExpression 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(); TargetType type();
} }

View File

@ -1,7 +1,6 @@
package de.dhbwstuttgart.target.tree.expression; package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.TargetField;
import de.dhbwstuttgart.target.tree.type.TargetType; 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; 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 @Override
public TargetType type() { public TargetType type() {
return null; return null;

View File

@ -5,5 +5,5 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List; 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; 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

@ -6,10 +6,10 @@ public sealed interface TargetUnaryOp extends TargetExpression {
TargetExpression expr(); TargetExpression expr();
record Negate(TargetType type, TargetExpression expr) implements TargetUnaryOp {} record Negate(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record Not(TargetType type, TargetExpression expr) implements TargetUnaryOp {} record Not(TargetType type, TargetExpression expr) implements TargetUnaryOp {}
record PreIncrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {} record PreIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
record PostIncrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {} record PostIncrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
record PreDecrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {} record PreDecrement(TargetType type, TargetExpression expr) implements TargetStatementExpression {}
record PostDecrement(TargetType type, TargetExpression expr) implements TargetUnaryOp {} 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; 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 @Override
public TargetType type() { public TargetType type() {

View File

@ -7,6 +7,6 @@ import java.util.List;
public record TargetRefType(String name, List<TargetType> params) implements TargetType { public record TargetRefType(String name, List<TargetType> params) implements TargetType {
@Override @Override
public String toSignature() { 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 Float = new TargetRefType("java.lang.Float", List.of());
TargetRefType Double = new TargetRefType("java.lang.Double", List.of()); TargetRefType Double = new TargetRefType("java.lang.Double", List.of());
TargetRefType String = new TargetRefType("java.lang.String", List.of()); TargetRefType String = new TargetRefType("java.lang.String", List.of());
TargetRefType Object = new TargetRefType("java.lang.Object", List.of());
String toSignature(); 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);
}
}