From ba94812596fcfd81e9eedf28086c818a8df49727 Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Fri, 17 May 2024 11:04:31 +0530 Subject: [PATCH] support do-while syntax #1 --- .../java/io/karatelabs/js/Interpreter.java | 24 ++++++++++++++++++- .../main/java/io/karatelabs/js/Parser.java | 13 ++++++++++ .../src/main/java/io/karatelabs/js/Type.java | 1 + .../test/java/io/karatelabs/js/EvalTest.java | 6 +++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/karate-js/src/main/java/io/karatelabs/js/Interpreter.java b/karate-js/src/main/java/io/karatelabs/js/Interpreter.java index bcfd689..d8cc373 100644 --- a/karate-js/src/main/java/io/karatelabs/js/Interpreter.java +++ b/karate-js/src/main/java/io/karatelabs/js/Interpreter.java @@ -617,9 +617,10 @@ private static Object evalVarStmt(Node node, Context context) { private static Object evalWhileStmt(Node node, Context context) { Context whileContext = new Context(context); Node whileBody = node.children.get(node.children.size() - 1); + Node whileExpr = node.children.get(2); Object whileResult = null; while (true) { - Object whileCondition = eval(node.children.get(2), whileContext); + Object whileCondition = eval(whileExpr, whileContext); if (!Terms.isTruthy(whileCondition)) { break; } @@ -632,6 +633,25 @@ private static Object evalWhileStmt(Node node, Context context) { return whileResult; } + private static Object evalDoWhileStmt(Node node, Context context) { + Context doContext = new Context(context); + Node doBody = node.children.get(1); + Node doExpr = node.children.get(4); + Object doResult = null; + while (true) { + doResult = eval(doBody, doContext); + if (doContext.isStopped()) { + context.updateFrom(doContext); + break; + } + Object doCondition = eval(doExpr, doContext); + if (!Terms.isTruthy(doCondition)) { + break; + } + } + return doResult; + } + public static Object eval(Node node, Context context) { context.currentNode = node; switch (node.type) { @@ -714,6 +734,8 @@ public static Object eval(Node node, Context context) { return evalVarStmt(node, context); case WHILE_STMT: return evalWhileStmt(node, context); + case DO_WHILE_STMT: + return evalDoWhileStmt(node, context); default: throw new RuntimeException(node.toStringError("eval - unexpected node")); } diff --git a/karate-js/src/main/java/io/karatelabs/js/Parser.java b/karate-js/src/main/java/io/karatelabs/js/Parser.java index b9f022a..3b65473 100644 --- a/karate-js/src/main/java/io/karatelabs/js/Parser.java +++ b/karate-js/src/main/java/io/karatelabs/js/Parser.java @@ -303,6 +303,7 @@ private boolean statement(boolean mandatory) { result = result || try_stmt(); result = result || for_stmt(); result = result || while_stmt(); + result = result || do_while_stmt(); result = result || switch_stmt(); result = result || (break_stmt() && eos()); result = result || (delete_stmt() && eos()); @@ -431,6 +432,18 @@ private boolean while_stmt() { return exit(); } + private boolean do_while_stmt() { + if (!enter(Type.DO_WHILE_STMT, Token.DO)) { + return false; + } + statement(true); + consume(Token.WHILE); + consume(Token.L_PAREN); + expr(-1, true); + consume(Token.R_PAREN); + return exit(); + } + private boolean switch_stmt() { if (!enter(Type.SWITCH_STMT, Token.SWITCH)) { return false; diff --git a/karate-js/src/main/java/io/karatelabs/js/Type.java b/karate-js/src/main/java/io/karatelabs/js/Type.java index 5c05ae3..601f4a3 100644 --- a/karate-js/src/main/java/io/karatelabs/js/Type.java +++ b/karate-js/src/main/java/io/karatelabs/js/Type.java @@ -37,6 +37,7 @@ public enum Type { THROW_STMT, FOR_STMT, WHILE_STMT, + DO_WHILE_STMT, SWITCH_STMT, CASE_BLOCK, DEFAULT_BLOCK, diff --git a/test-core/src/test/java/io/karatelabs/js/EvalTest.java b/test-core/src/test/java/io/karatelabs/js/EvalTest.java index a137f63..b375637 100644 --- a/test-core/src/test/java/io/karatelabs/js/EvalTest.java +++ b/test-core/src/test/java/io/karatelabs/js/EvalTest.java @@ -544,6 +544,12 @@ void testWhileLoop() { assertEquals(5, get("a")); } + @Test + void testDoWhileLoop() { + eval("a = 0; do { a++ } while (a <= 5)"); + assertEquals(6, get("a")); + } + @Test void testTernary() { eval("a = true ? 1 : 2");