mirror of
https://github.com/JonathanFleischmann/CompilerULTIMATE.git
synced 2024-12-28 15:38:03 +00:00
add some e2e tests and make BytecodeTestUtil usable with different constructors
This commit is contained in:
parent
4733e77522
commit
ee2553b089
@ -1,6 +1,6 @@
|
|||||||
package de.maishai.typedast;
|
package de.maishai.typedast;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.Getter;
|
||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
@ -16,6 +16,7 @@ public class MethodContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MethodVisitor mv;
|
private MethodVisitor mv;
|
||||||
|
private Type returnType;
|
||||||
private final ClassContext classContext;
|
private final ClassContext classContext;
|
||||||
private int localVarIndex = 0;
|
private int localVarIndex = 0;
|
||||||
private final Map<String, LocalVariable> variableIndex = new HashMap<>();
|
private final Map<String, LocalVariable> variableIndex = new HashMap<>();
|
||||||
@ -26,9 +27,10 @@ public class MethodContext {
|
|||||||
//used to jump to the start of the loop with continue
|
//used to jump to the start of the loop with continue
|
||||||
private final Stack<Label> continueLabels = new Stack<>();
|
private final Stack<Label> continueLabels = new Stack<>();
|
||||||
|
|
||||||
public MethodContext(ClassContext classContext, MethodVisitor mv) {
|
public MethodContext(ClassContext classContext, MethodVisitor mv, Type returnType) {
|
||||||
this.mv = mv;
|
this.mv = mv;
|
||||||
this.classContext = classContext;
|
this.classContext = classContext;
|
||||||
|
this.returnType = returnType;
|
||||||
registerVariable("this", classContext.getType());
|
registerVariable("this", classContext.getType());
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
}
|
}
|
||||||
@ -78,6 +80,10 @@ public class MethodContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void wrapUp() {
|
public void wrapUp() {
|
||||||
|
//if return type is void, add return instruction
|
||||||
|
if (returnType.getKind() == Type.Kind.VOID) {
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
}
|
||||||
System.out.println("maxStack: " + maxStack + " localVarIndex: " + localVarIndex);
|
System.out.println("maxStack: " + maxStack + " localVarIndex: " + localVarIndex);
|
||||||
mv.visitMaxs(maxStack, localVarIndex);
|
mv.visitMaxs(maxStack, localVarIndex);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
|
@ -90,7 +90,7 @@ public class TypedConstructor implements TypedNode {
|
|||||||
int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok
|
int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok
|
||||||
MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, "<init>", CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), Type.VOID), null, null);
|
MethodVisitor mv = ctx.getCw().visitMethod(accessModifier, "<init>", CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), Type.VOID), null, null);
|
||||||
System.out.println("Visiting method: " + "<init>" + CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), Type.VOID));
|
System.out.println("Visiting method: " + "<init>" + CodeGenUtils.generateDescriptor(typedParameters.stream().map(TypedParameter::getType).toList(), Type.VOID));
|
||||||
MethodContext mctx = new MethodContext(ctx, mv);
|
MethodContext mctx = new MethodContext(ctx, mv, Type.VOID);
|
||||||
typedParameters.forEach(param -> mctx.registerVariable(param.getParaName(), param.getType()));
|
typedParameters.forEach(param -> mctx.registerVariable(param.getParaName(), param.getType()));
|
||||||
//super();
|
//super();
|
||||||
mctx.pushStack("this");
|
mctx.pushStack("this");
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import e2e.BytecodeTestUtil;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
@ -16,7 +17,7 @@ public class CodegeneratorTests {
|
|||||||
assertDoesNotThrow(() -> {
|
assertDoesNotThrow(() -> {
|
||||||
BytecodeTestUtil testUtility = new BytecodeTestUtil("src/test/testFiles/JavaTestfilesFeatures/MethodCall.java", "MethodCall");
|
BytecodeTestUtil testUtility = new BytecodeTestUtil("src/test/testFiles/JavaTestfilesFeatures/MethodCall.java", "MethodCall");
|
||||||
|
|
||||||
assertEquals(3, testUtility.invokeMethod("method", null));
|
assertEquals(0, testUtility.invokeMethod("method", null));
|
||||||
assertEquals(1, testUtility.invokeMethod("method1", new Class<?>[]{int.class}, 1));
|
assertEquals(1, testUtility.invokeMethod("method1", new Class<?>[]{int.class}, 1));
|
||||||
assertEquals(3, testUtility.invokeMethod("method2", new Class<?>[]{int.class, int.class}, 1, 2));
|
assertEquals(3, testUtility.invokeMethod("method2", new Class<?>[]{int.class, int.class}, 1, 2));
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
package e2e;
|
||||||
|
|
||||||
import de.maishai.Compiler;
|
import de.maishai.Compiler;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@ -6,8 +8,24 @@ import java.util.List;
|
|||||||
public class BytecodeTestUtil {
|
public class BytecodeTestUtil {
|
||||||
|
|
||||||
private Class<?> clazz;
|
private Class<?> clazz;
|
||||||
|
private Object instance;
|
||||||
|
|
||||||
public BytecodeTestUtil(String sourceFilePath, String className) throws Exception {
|
public BytecodeTestUtil(String sourceFilePath, String className) throws Exception {
|
||||||
|
clazz = loadClass(sourceFilePath, className);
|
||||||
|
instance = clazz.getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeTestUtil(String sourceFilePath, String className, Class<?>[] parameterTypes, Object... initargs) throws Exception {
|
||||||
|
clazz = loadClass(sourceFilePath, className);
|
||||||
|
instance = clazz.getDeclaredConstructor(parameterTypes).newInstance(initargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object invokeMethod(String methodName, Class<?>[] parameterTypes, Object... args) throws Exception {
|
||||||
|
Method method = clazz.getMethod(methodName, parameterTypes);
|
||||||
|
return method.invoke(instance, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<?> loadClass(String sourceFilePath, String className) throws Exception {
|
||||||
byte[] resultBytecode = Compiler.generateByteCodeArrayFromFile(List.of(sourceFilePath)).get(0);
|
byte[] resultBytecode = Compiler.generateByteCodeArrayFromFile(List.of(sourceFilePath)).get(0);
|
||||||
|
|
||||||
ClassLoader classLoader = new ClassLoader() {
|
ClassLoader classLoader = new ClassLoader() {
|
||||||
@ -16,13 +34,6 @@ public class BytecodeTestUtil {
|
|||||||
return defineClass(name, resultBytecode, 0, resultBytecode.length);
|
return defineClass(name, resultBytecode, 0, resultBytecode.length);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
clazz = classLoader.loadClass(className);
|
return classLoader.loadClass(className);
|
||||||
}
|
|
||||||
|
|
||||||
public Object invokeMethod(String methodName, Class<?>[] parameterTypes, Object... args) throws Exception {
|
|
||||||
Object instance = clazz.getDeclaredConstructor().newInstance();
|
|
||||||
|
|
||||||
Method method = clazz.getMethod(methodName, parameterTypes);
|
|
||||||
return method.invoke(instance, args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
34
src/test/java/e2e/TestConstructor.java
Normal file
34
src/test/java/e2e/TestConstructor.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package e2e;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
|
public class TestConstructor {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructor_noArgAndUseGetter() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/Constructor.java", "Constructor");
|
||||||
|
Assertions.assertEquals(12, util.invokeMethod("getX", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructor_withArgAndUseGetter() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/Constructor.java", "Constructor", new Class<?>[]{int.class}, 777);
|
||||||
|
Assertions.assertEquals(777, util.invokeMethod("getX", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testField_setAndUseGetter() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/Constructor.java", "Constructor");
|
||||||
|
util.invokeMethod("setX", new Class<?>[]{int.class}, 777);
|
||||||
|
Assertions.assertEquals(777, util.invokeMethod("getX", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
33
src/test/java/e2e/TestForLoop.java
Normal file
33
src/test/java/e2e/TestForLoop.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package e2e;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
|
class TestForLoop {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFor_simple() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/ForLoop.java", "ForLoop");
|
||||||
|
Assertions.assertEquals(10, util.invokeMethod("simple", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFor_withContinue() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/ForLoop.java", "ForLoop");
|
||||||
|
Assertions.assertEquals(8, util.invokeMethod("withContinue", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFor_withBreak() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/ForLoop.java", "ForLoop");
|
||||||
|
Assertions.assertEquals(3, util.invokeMethod("withBreak", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
33
src/test/java/e2e/TestIf.java
Normal file
33
src/test/java/e2e/TestIf.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package e2e;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class TestIf {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIf_simple() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/If.java", "If");
|
||||||
|
assertEquals(1, util.invokeMethod("simple", new Class<?>[]{int.class}, 1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIf_simple2() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/If.java", "If");
|
||||||
|
assertEquals(0, util.invokeMethod("simple", new Class<?>[]{int.class}, 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIf_nested() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/If.java", "If");
|
||||||
|
assertEquals(0, util.invokeMethod("nested", new Class<?>[]{int.class}, 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
17
src/test/java/e2e/TestNewClass.java
Normal file
17
src/test/java/e2e/TestNewClass.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package e2e;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
|
public class TestNewClass {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNew_withFields() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/NewClass.java", "NewClass");
|
||||||
|
Assertions.assertEquals(10, util.invokeMethod("simple", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
32
src/test/java/e2e/TestWhileLoop.java
Normal file
32
src/test/java/e2e/TestWhileLoop.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package e2e;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
|
||||||
|
public class TestWhileLoop {
|
||||||
|
@Test
|
||||||
|
void testWhile_simple() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/WhileLoop.java", "WhileLoop");
|
||||||
|
Assertions.assertEquals(10, util.invokeMethod("simple", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWhile_withContinue() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/WhileLoop.java", "WhileLoop");
|
||||||
|
Assertions.assertEquals(8, util.invokeMethod("withContinue", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWhile_withBreak() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
BytecodeTestUtil util = new BytecodeTestUtil("src/test/testFiles/e2e/WhileLoop.java", "WhileLoop");
|
||||||
|
Assertions.assertEquals(3, util.invokeMethod("withBreak", null));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
18
src/test/testFiles/e2e/Constructor.java
Normal file
18
src/test/testFiles/e2e/Constructor.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
public class Constructor {
|
||||||
|
public int x;
|
||||||
|
public Constructor() {
|
||||||
|
this.x = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Constructor(int y) {
|
||||||
|
this.x = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(int y) {
|
||||||
|
this.x = y;
|
||||||
|
}
|
||||||
|
}
|
31
src/test/testFiles/e2e/ForLoop.java
Normal file
31
src/test/testFiles/e2e/ForLoop.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
public class ForLoop {
|
||||||
|
public int simple() {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < 5; i+=1) {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int withContinue() {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < 5; i+=1) {
|
||||||
|
if (i == 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int withBreak() {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < 5; i+=1) {
|
||||||
|
if (i == 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
22
src/test/testFiles/e2e/If.java
Normal file
22
src/test/testFiles/e2e/If.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
public class If {
|
||||||
|
public int simple(int x) {
|
||||||
|
if (x > 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nested(int x) {
|
||||||
|
if (x > 0) {
|
||||||
|
if (x > 1) {
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
13
src/test/testFiles/e2e/NewClass.java
Normal file
13
src/test/testFiles/e2e/NewClass.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
public class NewClass {
|
||||||
|
public int x;
|
||||||
|
|
||||||
|
public NewClass() {
|
||||||
|
x = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int simple() {
|
||||||
|
x = 4;
|
||||||
|
NewClass y = new NewClass();
|
||||||
|
return x + y.x;
|
||||||
|
}
|
||||||
|
}
|
38
src/test/testFiles/e2e/WhileLoop.java
Normal file
38
src/test/testFiles/e2e/WhileLoop.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
public class WhileLoop {
|
||||||
|
public int simple() {
|
||||||
|
int sum = 0;
|
||||||
|
int i = 0;
|
||||||
|
while (i < 5) {
|
||||||
|
sum += i;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int withContinue() {
|
||||||
|
int sum = 0;
|
||||||
|
int i = 0;
|
||||||
|
while (i < 5) {
|
||||||
|
if (i == 2) {
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sum += i;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int withBreak() {
|
||||||
|
int sum = 0;
|
||||||
|
int i = 0;
|
||||||
|
while (i < 5) {
|
||||||
|
if (i == 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sum += i;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user