From 769f1bb6774430feed0d31a81b997dd1336897ae Mon Sep 17 00:00:00 2001 From: Vic Nightfall Date: Fri, 1 Sep 2023 18:26:01 +0200 Subject: [PATCH] Progress on implementing the basic case --- .../bytecode/javFiles/OverloadPattern.jav | 2 +- .../dhbwstuttgart/bytecode/FunNGenerator.java | 20 +-- .../de/dhbwstuttgart/syntaxtree/Method.java | 2 +- .../target/generate/ASTToTargetAST.java | 147 ++++++++++++++++-- 4 files changed, 151 insertions(+), 20 deletions(-) diff --git a/resources/bytecode/javFiles/OverloadPattern.jav b/resources/bytecode/javFiles/OverloadPattern.jav index f9bb0e55..5e864164 100644 --- a/resources/bytecode/javFiles/OverloadPattern.jav +++ b/resources/bytecode/javFiles/OverloadPattern.jav @@ -33,7 +33,7 @@ public class OverloadPattern { } Number m(Point point) { - switch(point) { + return switch(point) { case Point(Integer x, Integer y) -> m$Point$_$java$lang$Integer$_$java$lang$Integer$_$(point); case Point(Float x, Float y) -> diff --git a/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java index ac1dbd84..e5bce5f4 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/FunNGenerator.java @@ -59,7 +59,11 @@ public class FunNGenerator { } private static String applySignature(TargetType a) { return a.toSignature(); } - private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s;", applySignature(a)); } + private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s", applySignature(a)); } + + public static String encodeType(TargetType type) { + return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$"); + } public static byte[] generateSuperBytecode(int numberArguments) { StringBuilder superFunNClassSignature = new StringBuilder("<"); @@ -127,14 +131,12 @@ public class FunNGenerator { public static String getSpecializedClassName(List argumentTypes, TargetType returnType) { return String.format("Fun%d$$%s%s", - argumentTypes.size(), - argumentTypes - .stream() - .map(FunNGenerator::applyNameDescriptor) - .collect(Collectors.joining()), - applyNameDescriptor(returnType)) - .replace('/', '$') - .replace(";", "$_$"); + argumentTypes.size(), + argumentTypes + .stream() + .map(FunNGenerator::encodeType) + .collect(Collectors.joining()), + encodeType(returnType)); } public static List getArguments(List list) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/Method.java b/src/main/java/de/dhbwstuttgart/syntaxtree/Method.java index 9eda85e4..904e4c8e 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/Method.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/Method.java @@ -67,7 +67,7 @@ public class Method extends SyntaxTreeNode implements IItemWithOffset, TypeScope return parameterlist; } - public Iterable getGenerics() { + public GenericDeclarationList getGenerics() { return generics; } diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index ebc39bee..f9e19956 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -4,6 +4,7 @@ import de.dhbwstuttgart.bytecode.FunNGenerator; import de.dhbwstuttgart.environment.ByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader; import de.dhbwstuttgart.exceptions.NotImplementedException; +import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.Record; import de.dhbwstuttgart.syntaxtree.factory.ASTFactory; @@ -141,7 +142,7 @@ public class ASTToTargetAST { var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); var constructors = input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(); var fields = input.getFieldDecl().stream().map(this::convert).toList(); - var methods = input.getMethods().stream().map(this::convert).flatMap(List::stream).toList(); + var methods = groupOverloads(input.getMethods()).stream().map(this::convert).flatMap(List::stream).toList(); if (input instanceof Record) return new TargetRecord(input.getModifiers(), input.getClassName().toString(), javaGenerics, txGenerics, superInterfaces, constructors, fields, methods); @@ -199,23 +200,151 @@ public class ASTToTargetAST { return result; } - private List convert(Method input) { + /** + * This only considers type patterns, all other methods aren't grouped together + * @param a + * @param b + * @return + */ + private boolean signatureEquals(Method a, Method b) { + if (!a.name.equals(b.name)) return false; + var para = a.getParameterList().getFormalparalist(); + var parb = b.getParameterList().getFormalparalist(); + if (para.size() != parb.size()) return false; + + for (var i = 0; i < para.size(); i++) { + var pa = para.get(i); + var pb = parb.get(i); + + if (pa instanceof RecordPattern rpa) { + if (pb instanceof RecordPattern rpb) { + if (rpa.getType().equals(rpb.getType())) continue; + } + return false; + } else if (pa.getType().equals(pb.getType())) { + continue; + } + return false; + } + + return true; + } + + // TODO Nested patterns + private List> groupOverloads(List input) { + var done = new HashSet(); + var res = new ArrayList>(); + for (var method : input) { + if (done.contains(method)) continue; + var overloads = new ArrayList(); + overloads.add(method); + done.add(method); + for (var method2 : input) { + if (!done.contains(method2) && signatureEquals(method, method2)) { + done.add(method2); + overloads.add(method2); + } + } + res.add(overloads); + } + return res; + } + + private String encodeName(String name, ParameterList params) { + var res = new StringBuilder(); + res.append(name); + res.append('$'); + for (var param : params.getFormalparalist()) { + if (param instanceof RecordPattern rp) { + res.append(FunNGenerator.encodeType(convert(param.getType()))); + for (var pattern : rp.getSubPattern()) { + res.append(FunNGenerator.encodeType(convert(pattern.getType()))); + } + } + } + return res.toString(); + } + + private List convert(List overloadedMethods) { + if (overloadedMethods.size() == 1) { + return convert(overloadedMethods.get(0)); + } + var res = new ArrayList(); + for (var method : overloadedMethods) { + var newMethod = new Method( + method.modifier, + encodeName(method.name, method.getParameterList()), + method.getReturnType(), + method.getParameterList(), + method.block, + method.getGenerics(), + method.getOffset() + ); + res.add(newMethod); + } + + var template = overloadedMethods.get(0); + + var pParams = new ArrayList(); + var i = 0; + for (var par : template.getParameterList()) { + pParams.add(switch (par) { + case RecordPattern rp -> new RecordPattern(rp.getSubPattern(), "par" + i, rp.getType(), new NullToken()); + default -> par; + }); + i++; + } + var params = new ParameterList(pParams, new NullToken()); + + var statements = new ArrayList(); + statements.add(new Return(makeRecordSwitch(template.getReturnType(), params, res), new NullToken())); + var block = new Block(statements, new NullToken()); + var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken()); + + res.add(entryPoint); // TODO + return res.stream().map(this::convert).flatMap(List::stream).toList(); + } + + private Expression makeRecordSwitch(RefTypeOrTPHOrWildcardOrGeneric returnType, ParameterList params, List overloadedMethods) { + var param = params.getFormalparalist().get(0); + assert param instanceof RecordPattern; // TODO + + var cases = new ArrayList(); + for (var method : overloadedMethods) { + var statements = new ArrayList(); + /*statements.add(new MethodCall( + method.getReturnType(), new ExpressionReceiver(new This(new NullToken())), method.name, + params, + ));*/ + + var block = new Block(statements, new NullToken()); + var labels = new ArrayList(); + cases.add(new SwitchBlock(labels, block, true, new NullToken())); + } + var swtch = new Switch(new LocalVar("par0", param.getType(), new NullToken()), cases, returnType, false, new NullToken()); + + return swtch; + } + + private List convert(Method method) { generics = all.get(0); List result = new ArrayList<>(); Set> parameterSet = new HashSet<>(); for (var s : all) { generics = s; - var javaGenerics = this.generics.javaGenerics.generics(currentClass, input); - var txGenerics = this.generics.txGenerics.generics(currentClass, input); - List params = convert(input.getParameterList(), this.generics.javaGenerics); + var javaGenerics = this.generics.javaGenerics.generics(currentClass, method); + var txGenerics = this.generics.txGenerics.generics(currentClass, method); + List params = convert(method.getParameterList(), this.generics.javaGenerics); if (parameterSet.stream().noneMatch(p -> p.equals(params))) { - List txParams = convert(input.getParameterList(), this.generics.txGenerics); + List txParams = convert(method.getParameterList(), this.generics.txGenerics); - var javaMethodGenerics = collectMethodGenerics(generics.javaGenerics(), javaGenerics, input); - var txMethodGenerics = collectMethodGenerics(generics.txGenerics(), txGenerics, input); + var javaMethodGenerics = collectMethodGenerics(generics.javaGenerics(), javaGenerics, method); + var txMethodGenerics = collectMethodGenerics(generics.txGenerics(), txGenerics, method); - result.add(new TargetMethod(input.modifier, input.name, convert(input.block), new TargetMethod.Signature(javaMethodGenerics, params, convert(input.getReturnType(), this.generics.javaGenerics)), new TargetMethod.Signature(txMethodGenerics, txParams, convert(input.getReturnType(), this.generics.txGenerics)))); + var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, convert(method.getReturnType(), this.generics.javaGenerics)); + var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); + result.add(new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature)); parameterSet.add(params); } }