Add new target ast nodes and test cases for switch
This commit is contained in:
parent
a0582e918b
commit
3de9fde672
@ -11,20 +11,20 @@ public class SwitchBlock extends Block {
|
|||||||
|
|
||||||
private List<SwitchLabel> labels = new ArrayList<>();
|
private List<SwitchLabel> labels = new ArrayList<>();
|
||||||
|
|
||||||
private Boolean defaultBlock = false;
|
private boolean defaultBlock = false;
|
||||||
|
|
||||||
public SwitchBlock(List<SwitchLabel> labels, Block statements, Token offset) {
|
public SwitchBlock(List<SwitchLabel> labels, Block statements, Token offset) {
|
||||||
super(statements.getStatements(), offset);
|
super(statements.getStatements(), offset);
|
||||||
this.labels = labels;
|
this.labels = labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwitchBlock(List<SwitchLabel> labels, Block statements, Boolean isDefault, Token offset) {
|
public SwitchBlock(List<SwitchLabel> labels, Block statements, boolean isDefault, Token offset) {
|
||||||
super(statements.getStatements(), offset);
|
super(statements.getStatements(), offset);
|
||||||
this.labels = labels;
|
this.labels = labels;
|
||||||
this.defaultBlock = isDefault;
|
this.defaultBlock = isDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isDefault() {
|
public boolean isDefault() {
|
||||||
return defaultBlock;
|
return defaultBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,11 @@ import de.dhbwstuttgart.syntaxtree.type.*;
|
|||||||
import de.dhbwstuttgart.target.tree.*;
|
import de.dhbwstuttgart.target.tree.*;
|
||||||
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
|
import de.dhbwstuttgart.target.tree.expression.TargetBlock;
|
||||||
import de.dhbwstuttgart.target.tree.expression.TargetExpression;
|
import de.dhbwstuttgart.target.tree.expression.TargetExpression;
|
||||||
|
import de.dhbwstuttgart.target.tree.expression.TargetSwitch;
|
||||||
import de.dhbwstuttgart.target.tree.type.*;
|
import de.dhbwstuttgart.target.tree.type.*;
|
||||||
import de.dhbwstuttgart.typeinference.result.*;
|
import de.dhbwstuttgart.typeinference.result.*;
|
||||||
|
|
||||||
|
import java.lang.annotation.Target;
|
||||||
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;
|
||||||
@ -205,6 +207,10 @@ public class ASTToTargetAST {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TargetSwitch.Case convert(SwitchBlock block) {
|
||||||
|
return new TargetSwitch.Case(block.getLabels().stream().map(this::convert).toList(), convert((Block) block));
|
||||||
|
}
|
||||||
|
|
||||||
protected TargetBlock convert(Block block) {
|
protected TargetBlock convert(Block block) {
|
||||||
return new TargetBlock(block.statements.stream().map(this::convert).toList());
|
return new TargetBlock(block.statements.stream().map(this::convert).toList());
|
||||||
}
|
}
|
||||||
|
@ -74,41 +74,6 @@ public class StatementToTargetExpression implements StatementVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public void visit(LambdaExpression lambda) {
|
public void visit(LambdaExpression lambda) {
|
||||||
} // Don't look at lambda expressions
|
} // Don't look at lambda expressions
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Switch switchStmt) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(SwitchBlock switchBlock) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(SwitchLabel switchLabel) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Yield aYield) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Pattern aPattern) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(RecordPattern aRecordPattern) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(GuardedPattern aGuardedPattern) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
result = new TargetLambdaExpression(converter.convert(lambdaExpression.getType()), captures, parameters, converter.convert(lambdaExpression.getReturnType()), converter.convert(lambdaExpression.methodBody));
|
result = new TargetLambdaExpression(converter.convert(lambdaExpression.getType()), captures, parameters, converter.convert(lambdaExpression.getReturnType()), converter.convert(lambdaExpression.methodBody));
|
||||||
@ -378,18 +343,16 @@ public class StatementToTargetExpression implements StatementVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Switch switchStmt) {
|
public void visit(Switch switchStmt) {
|
||||||
// TODO Auto-generated method stub
|
var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(converter::convert).toList();
|
||||||
|
var default_ = switchStmt.getBlocks().stream().filter(SwitchBlock::isDefault).map(s -> converter.convert((Block) s)).findFirst().orElse(null);
|
||||||
|
result = new TargetSwitch(converter.convert(switchStmt.getSwitch()), cases, default_, converter.convert(switchStmt.getType()), !switchStmt.getStatement());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchBlock switchBlock) {
|
public void visit(SwitchBlock switchBlock) {}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchLabel switchLabel) {
|
public void visit(SwitchLabel switchLabel) {}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Yield aYield) {
|
public void visit(Yield aYield) {
|
||||||
@ -398,16 +361,21 @@ public class StatementToTargetExpression implements StatementVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Pattern aPattern) {
|
public void visit(Pattern aPattern) {
|
||||||
// TODO Auto-generated method stub
|
result = new TargetSwitch.Pattern(converter.convert(aPattern.getType()), aPattern.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(RecordPattern aRecordPattern) {
|
public void visit(RecordPattern aRecordPattern) {
|
||||||
// TODO Auto-generated method stub
|
result = new TargetSwitch.ComplexPattern(
|
||||||
|
converter.convert(aRecordPattern.getType()),
|
||||||
|
aRecordPattern.getSubPattern().stream().map(x -> (TargetSwitch.Pattern) converter.convert(x)).toList()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GuardedPattern aGuardedPattern) {
|
public void visit(GuardedPattern aGuardedPattern) {
|
||||||
// TODO Auto-generated method stub
|
//FIXME This isn't done properly inside the parser, really you should only have one guard (Chaining them together with && just yields another expression)
|
||||||
|
//And then it also needs to be able to accept complex patterns. Because of this we only accept one condition for now.
|
||||||
|
result = new TargetSwitch.Guard(new TargetSwitch.Pattern(converter.convert(aGuardedPattern.getType()), aGuardedPattern.getName()), converter.convert(aGuardedPattern.getConditions().get(0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,4 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record TargetBlock(List<TargetExpression> statements) implements TargetExpression {
|
public record TargetBlock(List<TargetExpression> statements) implements TargetExpression {
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetBreak() implements TargetExpression {
|
public record TargetBreak() implements TargetExpression {
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetContinue() implements TargetExpression {
|
public record TargetContinue() implements TargetExpression {
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.*;
|
import de.dhbwstuttgart.target.tree.type.*;
|
||||||
|
|
||||||
public sealed interface TargetExpression
|
public sealed interface TargetExpression
|
||||||
permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetTernary, TargetThis, TargetUnaryOp, TargetVarDecl, TargetWhile {
|
permits TargetBinaryOp, TargetBlock, TargetBreak, TargetCast, TargetClassName, TargetContinue, TargetFieldVar, TargetFor, TargetForEach, TargetIf, TargetInstanceOf, TargetLambdaExpression, TargetLiteral, TargetLocalVar, TargetReturn, TargetStatementExpression, TargetSuper, TargetSwitch, TargetSwitch.ComplexPattern, TargetSwitch.Guard, TargetSwitch.Pattern, TargetTernary, TargetThis, TargetUnaryOp, TargetVarDecl, TargetWhile, TargetYield {
|
||||||
|
|
||||||
TargetType type();
|
default TargetType type() {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetFor(TargetExpression init, TargetExpression termination, TargetExpression increment, TargetExpression body) implements TargetExpression {
|
public record TargetFor(TargetExpression init, TargetExpression termination, TargetExpression increment, TargetExpression body) implements TargetExpression {
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetForEach(TargetExpression vardecl, TargetExpression list) implements TargetExpression {
|
public record TargetForEach(TargetExpression vardecl, TargetExpression list) implements TargetExpression {
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetIf(TargetExpression cond, TargetExpression if_body, TargetExpression else_body) implements TargetExpression {
|
public record TargetIf(TargetExpression cond, TargetExpression if_body, TargetExpression else_body) implements TargetExpression {
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetReturn(TargetExpression expression) implements TargetExpression {
|
public record TargetReturn(TargetExpression expression) implements TargetExpression {
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
package de.dhbwstuttgart.target.tree.expression;
|
package de.dhbwstuttgart.target.tree.expression;
|
||||||
|
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.Expression;
|
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record TargetSwitch(Expression expr, List<Case> cases, Expression default_) implements TargetExpression {
|
public record TargetSwitch(TargetExpression expr, List<Case> cases, TargetBlock default_, TargetType type, boolean isExpression) implements TargetExpression {
|
||||||
|
|
||||||
@Override
|
public TargetSwitch(TargetExpression expr, List<Case> cases, TargetBlock default_) {
|
||||||
public TargetType type() {
|
this(expr, cases, default_, null, false);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
record Case(Expression value, Expression body) {}
|
public TargetSwitch(TargetExpression expr, List<Case> cases, TargetBlock default_, TargetType type) {
|
||||||
|
this(expr, cases, default_, type, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetSwitch(TargetExpression expr, List<Case> cases, TargetBlock default_, boolean isExpression) {
|
||||||
|
this(expr, cases, default_, null, isExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Case(List<TargetExpression> labels, TargetBlock body) {}
|
||||||
|
|
||||||
|
public record Pattern(TargetType type, String name) implements TargetExpression {}
|
||||||
|
public record ComplexPattern(TargetType type, List<Pattern> subPatterns) implements TargetExpression {}
|
||||||
|
|
||||||
|
public record Guard(TargetExpression inner, TargetExpression expression) implements TargetExpression {}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,4 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
|
|
||||||
public record TargetWhile(TargetExpression cond, TargetExpression body) implements TargetExpression {
|
public record TargetWhile(TargetExpression cond, TargetExpression body) implements TargetExpression {
|
||||||
|
|
||||||
@Override
|
|
||||||
public TargetType type() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package de.dhbwstuttgart.target.tree.expression;
|
||||||
|
|
||||||
|
public record TargetYield(TargetExpression expression) implements TargetExpression {
|
||||||
|
}
|
@ -13,7 +13,9 @@ import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
|||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -196,6 +198,47 @@ public class TestCodegen {
|
|||||||
assertEquals(clazz.getDeclaredMethod("whileLoop").invoke(null), 10);
|
assertEquals(clazz.getDeclaredMethod("whileLoop").invoke(null), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassicSwitch() throws Exception {
|
||||||
|
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC , "Switch");
|
||||||
|
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchClassic", List.of(new MethodParameter(TargetType.Integer, "i")), TargetType.Integer, new TargetBlock(List.of(
|
||||||
|
new TargetVarDecl(TargetType.Integer, "res", null),
|
||||||
|
new TargetSwitch(new TargetLocalVar(TargetType.Integer, "i"), List.of(
|
||||||
|
new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(10)), new TargetBlock(
|
||||||
|
List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(0)), new TargetBreak())
|
||||||
|
)),
|
||||||
|
new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(20)), new TargetBlock(List.of())),
|
||||||
|
new TargetSwitch.Case(List.of(new TargetLiteral.IntLiteral(30)), new TargetBlock(
|
||||||
|
List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(1)), new TargetBreak())
|
||||||
|
))
|
||||||
|
), new TargetBlock(
|
||||||
|
List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "res"), new TargetLiteral.IntLiteral(2)), new TargetBreak())
|
||||||
|
))
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTypeSwitch() throws Exception {
|
||||||
|
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "Switch");
|
||||||
|
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "switchType", List.of(new MethodParameter(TargetType.Object, "obj")), TargetType.Integer, new TargetBlock(List.of(
|
||||||
|
new TargetReturn(new TargetSwitch(new TargetLocalVar(TargetType.Object, "obj"), List.of(
|
||||||
|
new TargetSwitch.Case(List.of(new TargetSwitch.Pattern(TargetType.String, "aString")), new TargetBlock(
|
||||||
|
List.of(new TargetLiteral.IntLiteral(0))
|
||||||
|
)),
|
||||||
|
new TargetSwitch.Case(List.of(new TargetSwitch.Pattern(TargetType.Integer, "anInteger")), new TargetBlock(
|
||||||
|
List.of(new TargetLiteral.IntLiteral(1))
|
||||||
|
))
|
||||||
|
), new TargetBlock(
|
||||||
|
List.of(new TargetLiteral.IntLiteral(2))
|
||||||
|
), TargetType.Integer)
|
||||||
|
))));
|
||||||
|
var clazz = generateClass(targetClass, new ByteArrayClassLoader());
|
||||||
|
var m = clazz.getDeclaredMethod("switchType", Object.class);
|
||||||
|
assertEquals(m.invoke(null, "String"), 0);
|
||||||
|
assertEquals(m.invoke(null, 10), 1);
|
||||||
|
assertEquals(m.invoke(null, 'A'), 2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("The lambda class is not generated because we don't call ASTToTargetAST")
|
@Ignore("The lambda class is not generated because we don't call ASTToTargetAST")
|
||||||
public void testLambda() throws Exception {
|
public void testLambda() throws Exception {
|
||||||
|
Loading…
Reference in New Issue
Block a user