forked from JavaTX/JavaCompilerCore
Start testing
This commit is contained in:
parent
590a4f04ae
commit
8666bfdf17
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -0,0 +1,6 @@
|
||||
package de.dhbwstuttgart.target.tree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetInterface(String name, List<TargetMethod> methods, List<TargetInterface> extendedInterfaces) {
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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 {}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
|
||||
public record TargetClassName(TargetType type) implements TargetExpression {
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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 {}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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("\\.", "/") + ";";
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
9
src/test/java/targetast/ByteArrayClassLoader.java
Normal file
9
src/test/java/targetast/ByteArrayClassLoader.java
Normal 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);
|
||||
}
|
||||
}
|
25
src/test/java/targetast/TestCodegen.java
Normal file
25
src/test/java/targetast/TestCodegen.java
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user