Work on pattern matching in function headers

This commit is contained in:
Daniel Holle 2024-10-02 15:09:19 +02:00
parent 6ccf2a3df6
commit 89bbbdacd8
4 changed files with 63 additions and 81 deletions

View File

@ -2,16 +2,16 @@ import java.lang.Integer;
import java.lang.Number; import java.lang.Number;
import java.lang.Float; import java.lang.Float;
record Point(Number x, Number y) {} public record Point(Number x, Number y) {}
public class OverloadPattern { public class OverloadPattern {
public m(Point(Integer x, Integer y)) { public m(Point(x, y), Point(z, a)) {
return x + y; return x + y + z + a;
} }
public m(Point(Float x, Float y)) { /*public m(Point(Float x, Float y)) {
return x * y; return x * y;
} }*/
public m(Integer x) { public m(Integer x) {
return x; return x;

View File

@ -9,9 +9,13 @@ public class SwitchOverload {
Number f(Double d) { return d * 2; } Number f(Double d) { return d * 2; }
Number f(Integer i) { return i * 5; } Number f(Integer i) { return i * 5; }
public m(r) { public m(r, x) {
x = x + x;
return switch(r) { return switch(r) {
case R(o) -> f(o); case R(o) -> {
x = x + x;
yield f(o);
}
}; };
} }
} }

View File

@ -13,6 +13,7 @@ import de.dhbwstuttgart.target.generate.StatementToTargetExpression;
import de.dhbwstuttgart.target.tree.*; import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import org.antlr.v4.codegen.Target;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.lang.invoke.*; import java.lang.invoke.*;
@ -1521,29 +1522,26 @@ public class Codegen {
mv.visitEnd(); mv.visitEnd();
} }
private int bindLocalVariables(State state, TargetPattern pattern, int offset, int field) { private void bindLocalVariables(State state, TargetComplexPattern cp, int offset) {
if (pattern instanceof TargetComplexPattern cp) { state.mv.visitVarInsn(ALOAD, offset);
state.mv.visitVarInsn(ALOAD, offset);
var clazz = findClass(new JavaClassName(cp.type().name())); var clazz = findClass(new JavaClassName(cp.type().name()));
if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found"); if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found");
for (var i = 0; i < cp.subPatterns().size(); i++) { for (var i = 0; i < cp.subPatterns().size(); i++) {
var subPattern = cp.subPatterns().get(i); var subPattern = cp.subPatterns().get(i);
if (i < cp.subPatterns().size() - 1) if (i < cp.subPatterns().size() - 1)
state.mv.visitInsn(DUP); state.mv.visitInsn(DUP);
extractField(state, cp.type(), i, clazz); extractField(state, cp.type(), i, clazz);
state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName()); state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName());
state.mv.visitVarInsn(ASTORE, offset); offset = state.createVariable(subPattern.name(), subPattern.type()).index;
offset = bindLocalVariables(state, subPattern, offset, i); state.mv.visitVarInsn(ASTORE, offset);
if (subPattern instanceof TargetComplexPattern cp2) {
bindLocalVariables(state, cp2, offset);
} }
} else if (pattern instanceof TargetTypePattern tp) { }
offset++;
state.createVariable(tp.name(), tp.type());
} else throw new NotImplementedException();
return offset;
} }
private void generateMethod(TargetMethod method) { private void generateMethod(TargetMethod method) {
@ -1562,8 +1560,14 @@ public class Codegen {
if (method.block() != null) { if (method.block() != null) {
mv.visitCode(); mv.visitCode();
var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1); var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1);
var offset = 1;
for (var param : method.signature().parameters()) { for (var param : method.signature().parameters()) {
bindLocalVariables(state, param.pattern(), 1, 0); state.createVariable(param.pattern().name(), param.pattern().type());
}
for (var param : method.signature().parameters()) {
if (param.pattern() instanceof TargetComplexPattern cp)
bindLocalVariables(state, cp, offset);
offset++;
} }
generate(state, method.block()); generate(state, method.block());
if (method.signature().returnType() == null) if (method.signature().returnType() == null)

View File

@ -17,6 +17,7 @@ import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*; import de.dhbwstuttgart.typeinference.result.*;
import java.sql.Array;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -206,7 +207,7 @@ public class ASTToTargetAST {
var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList();
var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList(); var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList();
var fields = input.getFieldDecl().stream().map(this::convert).toList(); var fields = input.getFieldDecl().stream().map(this::convert).toList();
var methods = groupOverloads(input, input.getMethods()).stream().flatMap(List::stream).toList(); var methods = groupOverloads(input, input.getMethods()).stream().map(m -> generatePatternOverloads(input, m)).flatMap(List::stream).toList();
TargetMethod staticConstructor = null; TargetMethod staticConstructor = null;
if (input.getStaticInitializer().isPresent()) if (input.getStaticInitializer().isPresent())
@ -271,69 +272,42 @@ public class ASTToTargetAST {
return result; return result;
} }
private String encodeName(String name, ParameterList params) { private String encodeName(String name, TargetMethod.Signature params) {
var res = new StringBuilder(); var res = new StringBuilder();
res.append(name); res.append(name);
res.append('$'); res.append('$');
for (var param : params.getFormalparalist()) { for (var param : params.parameters()) {
if (param instanceof RecordPattern rp) { encodeName(param.pattern(), res);
res.append(FunNGenerator.encodeType(convert(param.getType())));
for (var pattern : rp.getSubPattern()) {
res.append(FunNGenerator.encodeType(convert(pattern.getType())));
}
}
} }
return res.toString(); return res.toString();
} }
private List<TargetMethod> convert(ClassOrInterface clazz, List<Method> overloadedMethods) { private void encodeName(TargetPattern pattern, StringBuilder res) {
if (overloadedMethods.size() == 1) { if (pattern instanceof TargetComplexPattern cp) {
return convert(clazz, overloadedMethods.getFirst()).stream().map(m -> m.method()).toList(); res.append(FunNGenerator.encodeType(cp.type()));
} for (var pat : cp.subPatterns()) {
var methods = new ArrayList<Method>(); encodeName(pat, res);
for (var method : overloadedMethods) {
var newMethod = new Method(
method.modifier,
method.name,
//encodeName(method.name, method.getParameterList()),
method.getReturnType(),
method.getParameterList(),
method.block,
method.getGenerics(),
method.getOffset()
);
methods.add(newMethod);
}
// TODO Record overloading
/*var template = overloadedMethods.get(0);
var pParams = new ArrayList<Pattern>();
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<Statement>();
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*/
var res = new ArrayList<TargetMethod>();
for (var method : methods) {
var overloads = convert(clazz, method);
for (var m : overloads) {
var overload = m.method;
if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature());
res.add(overload);
} }
} else {
res.append(FunNGenerator.encodeType(pattern.type()));
} }
}
private List<TargetMethod> generatePatternOverloads(ClassOrInterface clazz, List<TargetMethod> overloadedMethods) {
if (overloadedMethods.size() <= 1) return overloadedMethods;
// Check if we have a pattern as a parameter
var firstMethod = overloadedMethods.getFirst();
if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods;
// Rename existing methods
var res = new ArrayList<TargetMethod>();
for (var method : overloadedMethods) {
var name = encodeName(method.name(), method.signature());
res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature()));
}
// Generate dispatch method
return res; return res;
} }