From f846142ee17eea888786547af058b027e72fe6f1 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Wed, 20 Nov 2024 14:44:10 +0100 Subject: [PATCH] Add broken value matching --- .../bytecode/javFiles/SwitchNestedValue.jav | 14 +++++++++++ .../de/dhbwstuttgart/bytecode/Codegen.java | 23 ++++++++++++++++++- .../dhbwstuttgart/syntaxtree/ASTVisitor.java | 2 ++ .../syntaxtree/AbstractASTWalker.java | 5 ++++ .../syntaxtree/visual/OutputGenerator.java | 5 ++++ .../generate/StatementToTargetExpression.java | 5 ++++ .../expression/TargetExpressionPattern.java | 20 ++++++++++++++++ .../target/tree/expression/TargetPattern.java | 2 +- .../typedeployment/TypeInsertPlacer.java | 2 +- src/test/java/TestComplete.java | 18 +++++++++++++++ 10 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 resources/bytecode/javFiles/SwitchNestedValue.jav create mode 100644 src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpressionPattern.java diff --git a/resources/bytecode/javFiles/SwitchNestedValue.jav b/resources/bytecode/javFiles/SwitchNestedValue.jav new file mode 100644 index 00000000..f34b43b5 --- /dev/null +++ b/resources/bytecode/javFiles/SwitchNestedValue.jav @@ -0,0 +1,14 @@ +import java.lang.Object; +import java.lang.Integer; + +public record R(Integer i) {} + +public class SwitchNestedValue { + public main(r) { + return switch(r) { + case R(10) -> 1; + case R(20) -> 2; + case R(i) -> 3; + }; + } +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index 43d47723..b8020a00 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -109,6 +109,10 @@ public class Codegen { this.scope = this.scope.parent; } + LocalVar createVariable(TargetType type) { + return createVariable("__var" + this.localCounter, type); + } + LocalVar createVariable(String name, TargetType type) { var local = new LocalVar(localCounter, name, type); scope.add(local); @@ -1433,7 +1437,24 @@ public class Codegen { state.mv.visitTypeInsn(CHECKCAST, pat.type().getInternalName()); } - if (pat instanceof TargetTypePattern sp) { + if (pat instanceof TargetExpressionPattern ep) { + var cur = state.createVariable(pat.type()); + state.mv.visitVarInsn(ASTORE, cur.index); + + var expr = new Equal(pat.type(), new TargetLocalVar(cur.type, cur.name), ep.expression()); + generate(state, expr); + + var cont = new Label(); + state.mv.visitJumpInsn(IFNE, cont); + for (var i = 0; i < depth - 1; i++) { + state.mv.visitInsn(POP); + } + + state.mv.visitVarInsn(ALOAD, state.switchResultValue.peek()); + state.mv.visitLdcInsn(index + 1); + state.mv.visitJumpInsn(GOTO, start); + state.mv.visitLabel(cont); + } else if (pat instanceof TargetTypePattern sp) { var local = state.createVariable(sp.name(), sp.type()); state.mv.visitVarInsn(ASTORE, local.index); } else if (pat instanceof TargetComplexPattern cp) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/ASTVisitor.java b/src/main/java/de/dhbwstuttgart/syntaxtree/ASTVisitor.java index 41d821f8..f03c501f 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/ASTVisitor.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/ASTVisitor.java @@ -10,6 +10,8 @@ public interface ASTVisitor extends StatementVisitor{ void visit(FormalParameter formalParameter); + void visit(LiteralPattern literalPattern); + void visit(GenericDeclarationList genericTypeVars); void visit(Field field); diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java index 2b4fff9f..c3b35697 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java @@ -37,6 +37,11 @@ public abstract class AbstractASTWalker implements ASTVisitor { formalParameter.getType().accept((ASTVisitor) this); } + @Override + public void visit(LiteralPattern literalPattern) { + + } + @Override public void visit(GenericDeclarationList genericTypeVars) { Iterator genericIterator = genericTypeVars.iterator(); diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java b/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java index 7297dd87..053cea3a 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java @@ -57,6 +57,11 @@ public class OutputGenerator implements ASTVisitor { out.append(formalParameter.getName()); } + @Override + public void visit(LiteralPattern literalPattern) { + out.append(literalPattern.value); + } + @Override public void visit(GenericDeclarationList genericTypeVars) { Iterator genericIterator = genericTypeVars.iterator(); diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index ba858f91..a7eea728 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -568,6 +568,11 @@ public class StatementToTargetExpression implements ASTVisitor { result = new TargetTypePattern(converter.convert(aPattern.getType()), aPattern.getName()); } + @Override + public void visit(LiteralPattern literalPattern) { + result = new TargetExpressionPattern(converter.convert(new Literal(literalPattern.getType(), literalPattern.value, literalPattern.getOffset()))); + } + @Override public void visit(ExpressionPattern aPattern) { result = converter.convert(aPattern.getExpression()); diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpressionPattern.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpressionPattern.java new file mode 100644 index 00000000..aa7fbbc0 --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetExpressionPattern.java @@ -0,0 +1,20 @@ +package de.dhbwstuttgart.target.tree.expression; + +import de.dhbwstuttgart.target.tree.type.TargetType; + +public record TargetExpressionPattern(TargetExpression expression) implements TargetPattern { + @Override + public TargetPattern withType(TargetType type) { + return this; + } + + @Override + public TargetType type() { + return expression.type(); + } + + @Override + public TargetPattern withName(String name) { + return this; + } +} diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java index 8881ffce..560572b2 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java @@ -2,7 +2,7 @@ package de.dhbwstuttgart.target.tree.expression; import de.dhbwstuttgart.target.tree.type.TargetType; -public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetGuard, TargetTypePattern { +public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetExpressionPattern, TargetGuard, TargetTypePattern { default String name() { return null; } diff --git a/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertPlacer.java b/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertPlacer.java index bbeda06c..af0c164e 100644 --- a/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertPlacer.java +++ b/src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertPlacer.java @@ -13,7 +13,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class TypeInsertPlacer extends AbstractASTWalker{ +public class TypeInsertPlacer extends AbstractASTWalker { Set inserts = new HashSet<>(); private ResultSet withResults; String pkgName; diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 0b1decb1..0e777a72 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -782,6 +782,24 @@ public class TestComplete { assertEquals(swtch.invoke(instance, listWithOneElement), 10); } + @Test + public void testSwitchNestedValue() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchNestedValue.jav"); + var clazz = classFiles.get("SwitchNestedValue"); + var rec = classFiles.get("R"); + var instance = clazz.getDeclaredConstructor().newInstance(); + var m = clazz.getDeclaredMethod("main", rec); + + var ctor = rec.getDeclaredConstructor(Integer.class); + var r1 = ctor.newInstance(10); + var r2 = ctor.newInstance(20); + var r3 = ctor.newInstance(30); + + assertEquals(m.invoke(instance, r1), 1); + assertEquals(m.invoke(instance, r2), 2); + assertEquals(m.invoke(instance, r3), 3); + } + @Test public void testGenericRecordSwitchCase() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "GenericRecordSwitchCase.jav");