From e25666869229ae2f586ad12ceb0f9257ec6bbd91 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 29 Sep 2015 20:42:41 +0100 Subject: Add ternary conditionals --- .../java/org/zwobble/couscous/ast/LiteralNode.java | 7 ++++++- .../zwobble/couscous/ast/TernaryConditionalNode.java | 17 +++++++++++++++++ .../couscous/ast/visitors/ExpressionNodeVisitor.java | 2 ++ .../org/zwobble/couscous/interpreter/Evaluator.java | 11 +++++++++++ .../org/zwobble/couscous/values/BooleanValue.java | 15 +++++++++++++++ .../couscous/tests/interpreter/EvaluatorTests.java | 19 +++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java create mode 100644 src/main/java/org/zwobble/couscous/values/BooleanValue.java diff --git a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java index 594187d..cc57aef 100644 --- a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java +++ b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor; +import org.zwobble.couscous.values.BooleanValue; import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.InterpreterValue; import org.zwobble.couscous.values.StringValue; @@ -13,10 +14,14 @@ public class LiteralNode implements ExpressionNode { return new LiteralNode(new StringValue(value)); } - public static LiteralNode of(int value) { + public static LiteralNode literal(int value) { return new LiteralNode(new IntegerValue(value)); } + public static LiteralNode literal(boolean value) { + return new LiteralNode(new BooleanValue(value)); + } + InterpreterValue value; @Override diff --git a/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java b/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java new file mode 100644 index 0000000..0386a32 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java @@ -0,0 +1,17 @@ +package org.zwobble.couscous.ast; + +import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor; + +import lombok.Value; + +@Value +public class TernaryConditionalNode implements ExpressionNode { + ExpressionNode condition; + ExpressionNode ifTrue; + ExpressionNode ifFalse; + + @Override + public T accept(ExpressionNodeVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java index 0167abc..27692e3 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java @@ -2,10 +2,12 @@ package org.zwobble.couscous.ast.visitors; import org.zwobble.couscous.ast.Assignment; import org.zwobble.couscous.ast.LiteralNode; +import org.zwobble.couscous.ast.TernaryConditionalNode; import org.zwobble.couscous.ast.VariableReferenceNode; public interface ExpressionNodeVisitor { T visit(LiteralNode literal); T visit(VariableReferenceNode variableReference); T visit(Assignment assignment); + T visit(TernaryConditionalNode ternaryConditional); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java index 863ccb0..6586f6a 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -3,8 +3,10 @@ package org.zwobble.couscous.interpreter; import org.zwobble.couscous.ast.Assignment; import org.zwobble.couscous.ast.ExpressionNode; import org.zwobble.couscous.ast.LiteralNode; +import org.zwobble.couscous.ast.TernaryConditionalNode; import org.zwobble.couscous.ast.VariableReferenceNode; import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor; +import org.zwobble.couscous.values.BooleanValue; import org.zwobble.couscous.values.InterpreterValue; import lombok.val; @@ -40,4 +42,13 @@ public class Evaluator implements ExpressionNodeVisitor { environment.put(assignment.getTarget().getReferentId(), value); return value; } + + @Override + public InterpreterValue visit(TernaryConditionalNode ternaryConditional) { + val condition = (BooleanValue)eval(ternaryConditional.getCondition()); + val branch = condition.getValue() + ? ternaryConditional.getIfTrue() + : ternaryConditional.getIfFalse(); + return eval(branch); + } } diff --git a/src/main/java/org/zwobble/couscous/values/BooleanValue.java b/src/main/java/org/zwobble/couscous/values/BooleanValue.java new file mode 100644 index 0000000..6d016e6 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/values/BooleanValue.java @@ -0,0 +1,15 @@ +package org.zwobble.couscous.values; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; + +@Value +public class BooleanValue implements InterpreterValue { + @Getter(value = AccessLevel.NONE) + boolean value; + + public boolean getValue() { + return value; + } +} diff --git a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java index 075d9b3..3adea06 100644 --- a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java +++ b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java @@ -2,6 +2,7 @@ package org.zwobble.couscous.tests.interpreter; import org.junit.Test; import org.zwobble.couscous.ast.FormalArgumentNode; +import org.zwobble.couscous.ast.TernaryConditionalNode; import org.zwobble.couscous.interpreter.Environment; import org.zwobble.couscous.values.StringValue; @@ -22,4 +23,22 @@ public class EvaluatorTests { val result = eval(environment, assign(arg, literal("[updated value]"))); assertEquals(new StringValue("[updated value]"), result); } + + @Test + public void whenConditionIsTrueThenValueOfConditionalTernaryIsTrueBranch() { + val result = eval(emptyEnvironment(), + new TernaryConditionalNode(literal(true), literal("T"), literal("F"))); + assertEquals(new StringValue("T"), result); + } + + @Test + public void whenConditionIsFalseThenValueOfConditionalTernaryIsFalseBranch() { + val result = eval(emptyEnvironment(), + new TernaryConditionalNode(literal(false), literal("T"), literal("F"))); + assertEquals(new StringValue("F"), result); + } + + private static Environment emptyEnvironment() { + return new Environment(ImmutableMap.of()); + } } -- cgit v1.2.3