New test case

This commit is contained in:
Daniel Holle 2023-08-01 14:02:19 +02:00
parent b0f7a264c2
commit f46c2ad0f7
6 changed files with 92 additions and 16 deletions

View File

@ -0,0 +1,17 @@
import java.lang.Integer;
import java.lang.Object;
import java.lang.Float;
record Rec(Integer a, Object b) {}
public class Switch {
main(Object o) {
return switch (o) {
case Rec(Integer a, Integer b) -> { yield a + b; }
case Rec(Integer a, Float b) -> { yield a * b; }
case Rec(Integer a, Rec(Integer b, Integer c)) -> { yield a + b + c; }
case Integer i -> { yield i; }
default -> { yield 0; }
};
}
}

View File

@ -1,11 +1,18 @@
package de.dhbwstuttgart.bytecode;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import org.objectweb.asm.*;
import java.io.File;
import java.lang.invoke.*;
import java.util.*;
@ -19,11 +26,13 @@ public class Codegen {
public final String className;
private int lambdaCounter = 0;
private final HashMap<TargetLambdaExpression, TargetMethod> lambdas = new HashMap<>();
private final JavaTXCompiler compiler;
public Codegen(TargetStructure clazz) {
public Codegen(TargetStructure clazz, JavaTXCompiler compiler) {
this.clazz = clazz;
this.className = clazz.qualifiedName();
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
this.compiler = compiler;
}
private record LocalVar(int index, String name, TargetType type) {
@ -296,7 +305,7 @@ public class Codegen {
} else if (type.equals(TargetType.Double)) {
mv.visitInsn(DADD);
} else {
throw new CodeGenException("Invalid argument to Add expression");
throw new CodeGenException("Invalid argument to Add expression, type: " + add.type());
}
}
if (add.type().equals(TargetType.String)) {
@ -1110,7 +1119,7 @@ public class Codegen {
types[i] = lit.value();
else if (label instanceof TargetSwitch.Guard guard)
types[i] = Type.getObjectType(guard.inner().type().getInternalName());
// TODO Same here we need to evaluate constants
// TODO Same here we need to evaluate constant;
else throw new NotImplementedException();
}
@ -1144,10 +1153,10 @@ public class Codegen {
var label = cse.labels().get(0);
if (label instanceof TargetSwitch.Guard gd){
state.mv.visitVarInsn(ALOAD, tmp);
bindPattern(state, aSwitch.expr().type(), gd.inner());
bindPattern(state, aSwitch.expr().type(), gd.inner(), start);
} else if (label instanceof TargetSwitch.Pattern pat) {
state.mv.visitVarInsn(ALOAD, tmp);
bindPattern(state, aSwitch.expr().type(), pat);
bindPattern(state, aSwitch.expr().type(), pat, start);
}
if (label instanceof TargetSwitch.Guard gd) {
@ -1188,13 +1197,30 @@ public class Codegen {
state.exitScope();
}
private void bindPattern(State state, TargetType type, TargetSwitch.Pattern pat) {
private void bindPattern(State state, TargetType type, TargetSwitch.Pattern pat, Label start) {
if (pat instanceof TargetSwitch.SimplePattern sp) {
var local = state.createVariable(sp.name(), sp.type());
convertTo(state, type, local.type);
convertTo(state, type, sp.type());
boxPrimitive(state, sp.type());
state.mv.visitVarInsn(ASTORE, local.index);
} else if (pat instanceof TargetSwitch.ComplexPattern cp) {
convertTo(state, type, cp.type());
boxPrimitive(state, cp.type());
var clazz = findClass(new JavaClassName(cp.type().name()));
if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found");
// TODO Check if class is a Record
for (var i = 0; i < cp.subPatterns().size(); i++) {
var subPattern = cp.subPatterns().get(i);
if (i >= clazz.getFieldDecl().size())
throw new CodeGenException("Couldn't find suitable field accessor for '" + cp.type().name() + "'");
var field = clazz.getFieldDecl().get(i);
var fieldType = new TargetRefType(((RefType) field.getType()).getName().toString());
state.mv.visitMethodInsn(INVOKEDYNAMIC, cp.type().getInternalName(), field.getName(), "()" + fieldType.toDescriptor(), false);
convertTo(state, fieldType, subPattern.type());
bindPattern(state, subPattern.type(), subPattern, start);
}
}
}
@ -1300,6 +1326,23 @@ public class Codegen {
return cw.toByteArray();
}
private ClassOrInterface findClass(JavaClassName className) {
try {
for (var sf : compiler.sourceFiles.values()) {
for (var clazz : compiler.getAvailableClasses(sf)) {
if (clazz.getClassName().equals(className))
return clazz;
}
for (var clazz : sf.KlassenVektor) {
if (clazz.getClassName().equals(className))
return clazz;
}
}
} catch (ClassNotFoundException ignored) {}
return null;
}
private void generateRecordMethods() {
var mt = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, MethodHandle[].class);
var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/runtime/ObjectMethods", "bootstrap", mt.toMethodDescriptorString(), false);

View File

@ -681,7 +681,7 @@ public class JavaTXCompiler {
var converter = new ASTToTargetAST(typeInferenceResult, sf, classLoader);
var generatedClasses = new HashMap<JavaClassName, byte[]>();
for (var clazz : sf.getClasses()) {
var codegen = new Codegen(converter.convert(clazz));
var codegen = new Codegen(converter.convert(clazz), this);
var code = codegen.generate();
generatedClasses.put(clazz.getClassName(), code);
converter.auxiliaries.forEach((name, source) -> {

View File

@ -358,11 +358,13 @@ public class StatementToTargetExpression implements StatementVisitor {
public void visit(SwitchBlock switchBlock) {}
@Override
public void visit(SwitchLabel switchLabel) {}
public void visit(SwitchLabel switchLabel) {
result = converter.convert(switchLabel.getExpression());
}
@Override
public void visit(Yield aYield) {
// TODO Auto-generated method stub
result = new TargetYield(converter.convert(aYield.retexpr));
}
@Override

View File

@ -1,5 +1,6 @@
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import org.junit.Ignore;
import org.junit.Test;
@ -649,4 +650,11 @@ public class TestComplete {
System.out.println(clazz.getDeclaredMethod("hashCode").invoke(instance));
System.out.println(clazz.getDeclaredMethod("toString").invoke(instance));
}
@Test
public void testSwitch() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Switch.jav");
var clazz = classFiles.get("Switch");
var instance = clazz.getDeclaredConstructor().newInstance();
}
}

View File

@ -19,11 +19,10 @@ import static org.junit.Assert.*;
import org.objectweb.asm.Opcodes;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Target;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -53,7 +52,7 @@ public class TestCodegen {
result.putAll(classes.stream().map(cli -> {
try {
return generateClass(converter.convert(cli), classLoader);
return generateClass(converter.convert(cli), classLoader, compiler);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
@ -67,8 +66,15 @@ public class TestCodegen {
return result;
}
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader) throws IOException {
var codegen = new Codegen(clazz);
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader) throws IOException, ClassNotFoundException {
Codegen codegen = new Codegen(clazz, new JavaTXCompiler(List.of()));
var code = codegen.generate();
writeClassFile(clazz.qualifiedName(), code);
return classLoader.loadClass(code);
}
public static Class<?> generateClass(TargetStructure clazz, IByteArrayClassLoader classLoader, JavaTXCompiler compiler) throws IOException {
Codegen codegen = new Codegen(clazz, compiler);
var code = codegen.generate();
writeClassFile(clazz.qualifiedName(), code);
return classLoader.loadClass(code);
@ -85,7 +91,7 @@ public class TestCodegen {
var result = classes.stream().map(cli -> {
try {
return generateClass(converter.convert(cli), classLoader);
return generateClass(converter.convert(cli), classLoader, compiler);
} catch (IOException exception) {
throw new RuntimeException(exception);
}