From b774281cbb8832509ec9e0c65b6f2924d0a2dc52 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Mon, 22 Apr 2024 12:17:53 +0200 Subject: [PATCH] Add Ternary, fix #324 --- resources/bytecode/javFiles/Ternary.jav | 9 +++++++ .../de/dhbwstuttgart/bytecode/Codegen.java | 14 +++++++++++ .../StatementGenerator.java | 8 ++++++- .../syntaxtree/AbstractASTWalker.java | 7 ++++++ .../syntaxtree/StatementVisitor.java | 2 ++ .../syntaxtree/statement/Ternary.java | 24 +++++++++++++++++++ .../syntaxtree/visual/OutputGenerator.java | 12 ++++++++++ .../generate/StatementToTargetExpression.java | 5 ++++ .../generate/TracingStatementVisitor.java | 7 ++++++ .../target/tree/expression/TargetTernary.java | 2 +- .../typeinference/typeAlgo/TYPEStmt.java | 10 ++++++++ src/test/java/TestComplete.java | 8 +++++++ 12 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 resources/bytecode/javFiles/Ternary.jav create mode 100644 src/main/java/de/dhbwstuttgart/syntaxtree/statement/Ternary.java diff --git a/resources/bytecode/javFiles/Ternary.jav b/resources/bytecode/javFiles/Ternary.jav new file mode 100644 index 00000000..321490ba --- /dev/null +++ b/resources/bytecode/javFiles/Ternary.jav @@ -0,0 +1,9 @@ +import java.lang.Boolean; +import java.lang.String; +import java.lang.Integer; + +public class Ternary { + public main(x) { + return x > 10 ? "big" : "small"; + } +} \ 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 d0835561..ee39830a 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -1108,6 +1108,20 @@ public class Codegen { mv.visitInsn(ATHROW); break; } + case TargetTernary ternary: { + generate(state, ternary.cond()); + var iffalse = new Label(); + var end = new Label(); + mv.visitJumpInsn(IFEQ, iffalse); + generate(state, ternary.iftrue()); + convertTo(state, ternary.iftrue().type(), ternary.type()); + mv.visitJumpInsn(GOTO, end); + mv.visitLabel(iffalse); + generate(state, ternary.iffalse()); + convertTo(state, ternary.iffalse().type(), ternary.type()); + mv.visitLabel(end); + break; + } default: throw new CodeGenException("Unexpected value: " + expr); } diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java index 02cad496..b9aae9d3 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java @@ -832,7 +832,13 @@ public class StatementGenerator { } private Expression convert(Java17Parser.ConditionalassignexpressionContext expression) { - throw new NotImplementedException(); + return new Ternary(TypePlaceholder.fresh( + expression.getStart()), + convert(expression.expression(0)), + convert(expression.expression(1)), + convert(expression.expression(2)), + expression.getStart() + ); } private Expression convert(Java17Parser.OrexpressionContext expression) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java index 548cbb1c..bc963fb3 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java @@ -332,4 +332,11 @@ public abstract class AbstractASTWalker implements ASTVisitor { public void visit(GuardedPattern aGuardedPattern) { } + + @Override + public void visit(Ternary ternary) { + ternary.cond.accept(this); + ternary.iftrue.accept(this); + ternary.iffalse.accept(this); + } } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java b/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java index 08cff88a..1f1dc61c 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/StatementVisitor.java @@ -80,4 +80,6 @@ public interface StatementVisitor { void visit(Literal literal); void visit(Throw aThrow); + + void visit(Ternary ternary); } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/statement/Ternary.java b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/Ternary.java new file mode 100644 index 00000000..23a1d72b --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/Ternary.java @@ -0,0 +1,24 @@ +package de.dhbwstuttgart.syntaxtree.statement; + +import de.dhbwstuttgart.syntaxtree.StatementVisitor; +import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import org.antlr.v4.runtime.Token; + +public class Ternary extends Expression { + + public final Expression cond; + public final Expression iftrue; + public final Expression iffalse; + + public Ternary(RefTypeOrTPHOrWildcardOrGeneric type, Expression cond, Expression iftrue, Expression iffalse, Token offset) { + super(type, offset); + this.cond = cond; + this.iftrue = iftrue; + this.iffalse = iffalse; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java b/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java index 8b1175bb..c84b95a1 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/visual/OutputGenerator.java @@ -427,6 +427,18 @@ public class OutputGenerator implements ASTVisitor { // TODO implement } + @Override + public void visit(Ternary ternary) { + out.append("("); + ternary.cond.accept(this); + out.append(" ? "); + ternary.iftrue.accept(this); + out.append(" : "); + ternary.iffalse.accept(this); + out.append(")::"); + ternary.getType().accept(this); + } + @Override public void visit(Switch switchStmt) { out.append("switch("); diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 3816e12d..74f0fe89 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -359,6 +359,11 @@ public class StatementToTargetExpression implements ASTVisitor { result = new TargetThrow(converter.convert(aThrow.expr)); } + @Override + public void visit(Ternary ternary) { + result = new TargetTernary(converter.convert(ternary.getType()), converter.convert(ternary.cond), converter.convert(ternary.iftrue), converter.convert(ternary.iffalse)); + } + @Override public void visit(Switch switchStmt) { var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(converter::convert).toList(); diff --git a/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java b/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java index 64655dbe..7b6f2a5f 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/TracingStatementVisitor.java @@ -203,4 +203,11 @@ public abstract class TracingStatementVisitor implements StatementVisitor { public void visit(Yield aYield) { } + + @Override + public void visit(Ternary ternary) { + ternary.cond.accept(this); + ternary.iftrue.accept(this); + ternary.iffalse.accept(this); + } } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetTernary.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetTernary.java index 17349489..8edeaaaf 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetTernary.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetTernary.java @@ -2,5 +2,5 @@ package de.dhbwstuttgart.target.tree.expression; import de.dhbwstuttgart.target.tree.type.TargetType; -public record TargetTernary(TargetType type, TargetExpression cond, TargetExpression ifTrue, TargetExpression ifFalse) implements TargetExpression { +public record TargetTernary(TargetType type, TargetExpression cond, TargetExpression iftrue, TargetExpression iffalse) implements TargetExpression { } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java index 5e866781..417c44a8 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java @@ -488,6 +488,16 @@ public class TYPEStmt implements StatementVisitor { aThrow.expr.accept(this); } + @Override + public void visit(Ternary ternary) { + ternary.cond.accept(this); + ternary.iftrue.accept(this); + ternary.iffalse.accept(this); + constraintsSet.addUndConstraint(new Pair(ternary.cond.getType(), bool, PairOperator.EQUALSDOT)); + constraintsSet.addUndConstraint(new Pair(ternary.iftrue.getType(), ternary.getType(), PairOperator.SMALLERDOT)); + constraintsSet.addUndConstraint(new Pair(ternary.iffalse.getType(), ternary.getType(), PairOperator.SMALLERDOT)); + } + @Override public void visit(Return returnExpr) { returnExpr.retexpr.accept(this); diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 6e743108..93cfb387 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -916,6 +916,14 @@ public class TestComplete { var instance = clazz.getDeclaredConstructor().newInstance(); } + @Test + public void testTernary() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Ternary.jav"); + var clazz = classFiles.get("Ternary"); + var instance = clazz.getDeclaredConstructor().newInstance(); + assertEquals(clazz.getDeclaredMethod("main", Integer.class).invoke(instance, 5), "small"); + } + @Test public void testBug122() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug122.jav");