From 4afb6df35e1f46fe85914c05a648f87d9270bf1c Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Thu, 5 Oct 2023 12:04:39 -0400 Subject: [PATCH 1/3] Added Conditionals and related tests https://bedrock.dev/docs/stable/Molang#Conditionals --- src/main/java/com/eliotlash/molang/Parser.java | 10 +++++++--- .../com/eliotlash/molang/ast/ASTTransformation.java | 5 +++++ .../java/com/eliotlash/molang/ast/Evaluator.java | 7 +++++++ src/main/java/com/eliotlash/molang/ast/Expr.java | 12 ++++++++++++ .../java/com/eliotlash/molang/ast/EvaluatorTest.java | 6 ++++++ 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/eliotlash/molang/Parser.java b/src/main/java/com/eliotlash/molang/Parser.java index 60462de..62807f4 100644 --- a/src/main/java/com/eliotlash/molang/Parser.java +++ b/src/main/java/com/eliotlash/molang/Parser.java @@ -300,9 +300,13 @@ private Expr unary() { Expr access = access(); if (match(QUESTION)) { Expr left = expression(); - consume(COLON, "Expected ':' after ternary"); - Expr right = expression(); - return new Expr.Ternary(access, left, right); + //consume(COLON, "Expected ':' after ternary"); + if (match(COLON)) { + Expr right = expression(); + return new Expr.Ternary(access, left, right); + } else { + return new Expr.Conditional(access, left); + } } if (match(ARROW)) { Expr right = expression(); diff --git a/src/main/java/com/eliotlash/molang/ast/ASTTransformation.java b/src/main/java/com/eliotlash/molang/ast/ASTTransformation.java index d63f4b7..61f7440 100644 --- a/src/main/java/com/eliotlash/molang/ast/ASTTransformation.java +++ b/src/main/java/com/eliotlash/molang/ast/ASTTransformation.java @@ -83,6 +83,11 @@ public Expr visitNot(Expr.Not expr) { return new Expr.Not(visit(expr.value())); } + @Override + public Expr visitConditional(Expr.Conditional expr) { + return new Expr.Conditional(visit(expr.condition()), visit(expr.ifTrue())); + } + @Override public Expr visitTernary(Expr.Ternary expr) { return new Expr.Ternary(visit(expr.condition()), visit(expr.ifTrue()), visit(expr.ifFalse())); diff --git a/src/main/java/com/eliotlash/molang/ast/Evaluator.java b/src/main/java/com/eliotlash/molang/ast/Evaluator.java index 8ce9b5e..2aa7195 100644 --- a/src/main/java/com/eliotlash/molang/ast/Evaluator.java +++ b/src/main/java/com/eliotlash/molang/ast/Evaluator.java @@ -187,6 +187,13 @@ public Double visitNot(Expr.Not expr) { return evaluate(expr.value()) == 0 ? 1.0 : 0.0; } + @Override + public Double visitConditional(Expr.Conditional expr) { + double result = evaluate(expr.condition()); + if (result == 0) return 0.0; + return evaluate(expr.ifTrue()); + } + @Override public Double visitTernary(Expr.Ternary expr) { Expr branch = evaluate(expr.condition()) == 0 ? expr.ifFalse() : expr.ifTrue(); diff --git a/src/main/java/com/eliotlash/molang/ast/Expr.java b/src/main/java/com/eliotlash/molang/ast/Expr.java index c110a11..c5d2dd5 100644 --- a/src/main/java/com/eliotlash/molang/ast/Expr.java +++ b/src/main/java/com/eliotlash/molang/ast/Expr.java @@ -157,6 +157,16 @@ public R accept(Visitor visitor) { } } + /** + * condition ? ifTrue + */ + record Conditional(Expr condition, Expr ifTrue) implements Expr { + @Override + public R accept(Visitor visitor) { + return visitor.visitConditional(this); + } + } + /** * condition ? ifTrue : ifFalse */ @@ -228,6 +238,8 @@ default R visit(Expr node) { R visitNot(Not expr); + R visitConditional(Conditional expr); + R visitTernary(Ternary expr); R visitSwitchContext(SwitchContext expr); diff --git a/src/test/java/com/eliotlash/molang/ast/EvaluatorTest.java b/src/test/java/com/eliotlash/molang/ast/EvaluatorTest.java index bc9e2dd..817d208 100644 --- a/src/test/java/com/eliotlash/molang/ast/EvaluatorTest.java +++ b/src/test/java/com/eliotlash/molang/ast/EvaluatorTest.java @@ -87,6 +87,12 @@ void visitNot() { assertEquals(1, eval.visitNot(new Expr.Not(c(0)))); } + @Test + void visitConditional() { + assertEquals(10, eval.visitConditional(new Expr.Conditional(c(1), c(10)))); + assertEquals(0, eval.visitConditional(new Expr.Conditional(c(0), c(10)))); + } + @Test void visitTernary() { assertEquals(10, eval.visitTernary(new Expr.Ternary(c(1), c(10), c(30)))); From dfacdde4f65607abcfb6a23dd8accb2bec523df0 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Thu, 5 Oct 2023 12:05:58 -0400 Subject: [PATCH 2/3] Remove commented code --- src/main/java/com/eliotlash/molang/Parser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/eliotlash/molang/Parser.java b/src/main/java/com/eliotlash/molang/Parser.java index 62807f4..b7eab99 100644 --- a/src/main/java/com/eliotlash/molang/Parser.java +++ b/src/main/java/com/eliotlash/molang/Parser.java @@ -300,7 +300,6 @@ private Expr unary() { Expr access = access(); if (match(QUESTION)) { Expr left = expression(); - //consume(COLON, "Expected ':' after ternary"); if (match(COLON)) { Expr right = expression(); return new Expr.Ternary(access, left, right); From 16b51898fa273246640667290bcfe6058303293a Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Thu, 5 Oct 2023 14:35:08 -0400 Subject: [PATCH 3/3] Add parsing tests for binary and ternary conditionals --- .../java/com/eliotlash/molang/ParserTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/test/java/com/eliotlash/molang/ParserTest.java b/src/test/java/com/eliotlash/molang/ParserTest.java index 3641fbb..d2474e6 100644 --- a/src/test/java/com/eliotlash/molang/ParserTest.java +++ b/src/test/java/com/eliotlash/molang/ParserTest.java @@ -46,6 +46,31 @@ void testOperators() { } } + @Test + void testConditionals() { + // Binary Conditional + assertEquals(new Expr.Conditional(c(0), c(20)), e("0 ? 20")); + assertEquals( + new Expr.Conditional(c(0), paren(new Expr.Conditional(c(20), c(30)))), + e("0 ? (20 ? 30)") + ); + // Ternary Conditional + assertEquals(new Expr.Ternary(c(0), c(10), c(20)), e("0 ? 10 : 20")); + assertEquals( + new Expr.Ternary(c(0), paren(new Expr.Ternary(c(10), c(20), c(30))), c(20)), + e("0 ? (10 ? 20 : 30) : 20") + ); + // Combinations + assertEquals( + new Expr.Conditional(c(0), new Expr.Ternary(c(10), c(20), c(30))), + e("0 ? 10 ? 20 : 30") + ); + assertEquals( + new Expr.Ternary(c(0), c(10), new Expr.Conditional(c(20), c(30))), + e("0 ? 10 : 20 ? 30") + ); + } + @Test void testMath() { Expr.Constant twenty = c(20);