This is an automated email from the ASF dual-hosted git repository.
gitgabrio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new d3346eed41 [incubator-kie-issues#2336] Fix broken behavior involving
ForIterationNode (#6746)
d3346eed41 is described below
commit d3346eed41e74139e1e5050a31c99793d6f7a161
Author: Gabriele Cardosi <[email protected]>
AuthorDate: Thu Jun 4 10:17:18 2026 +0000
[incubator-kie-issues#2336] Fix broken behavior involving ForIterationNode
(#6746)
* [incubator-kie-issues#2336] Inside ForExpressionNode, exit context frame
inside the while loop to prevent exiting the wrong one.
* [incubator-kie-issues#2336] Implemented unit tests. Minor refactoring to
simplify testing
---------
Co-authored-by: Gabriele-Cardosi <[email protected]>
---
.../kie/dmn/feel/lang/ast/ForExpressionNode.java | 64 ++++++++++++--------
.../dmn/feel/lang/ast/ForExpressionNodeTest.java | 70 ++++++++++++++++++++++
2 files changed, 109 insertions(+), 25 deletions(-)
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ForExpressionNode.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ForExpressionNode.java
index 9b1aae2a97..5b2219aa6f 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ForExpressionNode.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ForExpressionNode.java
@@ -92,7 +92,36 @@ public class ForExpressionNode
}
}
- private void populateToReturn(int k, EvaluationContext ctx, List<Object>
toPopulate) {
+ static void setValueIntoContext(EvaluationContext ctx, String name, Object
value) {
+ ctx.setValue(name, value);
+ }
+
+ @Override
+ public Type getResultType() {
+ return BuiltInType.LIST;
+ }
+
+ @Override
+ public ASTNode[] getChildrenNode() {
+ ASTNode[] children = new ASTNode[iterationContexts.size() + 1];
+ System.arraycopy(iterationContexts.toArray(new ASTNode[]{}), 0,
children, 0, iterationContexts.size());
+ children[children.length - 1] = expression;
+ return children;
+ }
+
+ @Override
+ public <T> T accept(Visitor<T> v) {
+ return v.visit(this);
+ }
+
+ /**
+ * Populate the given <code>List<Object></code> with the result of
evaluating the expressions retrieved from the
+ * <code>IterationContextNode</code> at the <b>k</b> index of
<code>iterationContexts</code>.
+ * @param k
+ * @param ctx
+ * @param toPopulate
+ */
+ void populateToReturn(int k, EvaluationContext ctx, List<Object>
toPopulate) {
LOG.trace("populateToReturn at index {}", k);
if (k > iterationContexts.size() - 1) {
LOG.trace("Index {} out of range, returning", k);
@@ -114,20 +143,18 @@ public class ForExpressionNode
} else if (k < iterationContexts.size() - 1) {
populateToReturn(k + 1, ctx, toPopulate);
}
+ ctx.exitFrame();
}
- ctx.exitFrame();
}
- static void setValueIntoContext(EvaluationContext ctx, String name, Object
value) {
- ctx.setValue(name, value);
- }
-
- @Override
- public Type getResultType() {
- return BuiltInType.LIST;
- }
-
- private ForIteration createForIteration(EvaluationContext ctx,
IterationContextNode iterationContextNode) throws
NullContentInsideForIterationException {
+ /**
+ * Instantiate a <code>ForIteration</code> object based on the evaluation
of the given <code>IterationContextNode</code>.
+ * @param ctx
+ * @param iterationContextNode
+ * @return
+ * @throws NullContentInsideForIterationException
+ */
+ static ForIteration createForIteration(EvaluationContext ctx,
IterationContextNode iterationContextNode) throws
NullContentInsideForIterationException {
LOG.trace("Creating ForIteration for {}", iterationContextNode);
ForIteration toReturn = null;
String name = iterationContextNode.evaluateName(ctx);
@@ -148,17 +175,4 @@ public class ForExpressionNode
}
return toReturn;
}
-
- @Override
- public ASTNode[] getChildrenNode() {
- ASTNode[] children = new ASTNode[iterationContexts.size() + 1];
- System.arraycopy(iterationContexts.toArray(new ASTNode[]{}), 0,
children, 0, iterationContexts.size());
- children[children.length - 1] = expression;
- return children;
- }
-
- @Override
- public <T> T accept(Visitor<T> v) {
- return v.visit(this);
- }
}
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/ForExpressionNodeTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/ForExpressionNodeTest.java
index 2b28ee57bf..810b2077e7 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/ForExpressionNodeTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/ForExpressionNodeTest.java
@@ -20,6 +20,7 @@ package org.kie.dmn.feel.lang.ast;
import java.math.BigDecimal;
import java.time.LocalDate;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -27,6 +28,10 @@ import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.forexpressioniterators.ForIteration;
+import org.kie.dmn.feel.lang.impl.EvaluationContextImpl;
+import org.kie.dmn.feel.lang.impl.ExecutionFrame;
import org.kie.dmn.feel.util.EvaluationContextTestUtil;
import org.kie.dmn.feel.lang.types.BuiltInType;
@@ -81,4 +86,69 @@ class ForExpressionNodeTest {
assertThat(retrieved).isInstanceOf(List.class).asList().containsExactly(LocalDate.of(1980,
1, 1),
LocalDate.of(1980, 1, 2), LocalDate.of(1980, 1, 3));
}
+
+ @Test
+ void populateToReturnFromRange() {
+ String iterationName = "x";
+ IterationContextNode iterationContextNode =
getIterationContextNode(iterationName, getLocalDateRangeNode("[1980-01-01 ..
1980-01-03]", LocalDate.of(1980, 1, 1), LocalDate.of(1980, 1, 3),
RangeNode.IntervalBoundary.CLOSED, RangeNode.IntervalBoundary.CLOSED ),
iterationName + " in [1980-01-01 .. 1980-01-03]");
+ ForExpressionNode forExpressionNode = new
ForExpressionNode(Collections.singletonList(iterationContextNode),
getNameRefNode(BuiltInType.DATE, iterationName), "for " + iterationName + " in
[1980-01-01 .. 1980-01-03] return " + iterationName);
+ List<Object> toPopulate = new ArrayList<>();
+ EvaluationContextImpl ctx = (EvaluationContextImpl)
EvaluationContextTestUtil.newEmptyEvaluationContext();
+ ExecutionFrame peeked = ctx.peek();
+ forExpressionNode.populateToReturn(0, ctx, toPopulate);
+ assertThat(toPopulate).containsExactly(LocalDate.of(1980, 1, 1),
+ LocalDate.of(1980, 1, 2),
+ LocalDate.of(1980, 1, 3));
+ assertThat(ctx.getAllValues()).doesNotContainKeys(iterationName);
+ assertThat(ctx.peek()).isEqualTo(peeked);
+ }
+
+ @Test
+ void populateToReturnFromArray() {
+ String iterationName = "x";
+ IterationContextNode iterationContextNode =
getIterationContextNode("x", getListNode("[ 1, 2, 3, 4 ]", Arrays.asList("1",
"2", "3", "4")), "x in [ 1, 2, 3, 4 ]");
+ ForExpressionNode forExpressionNode = new
ForExpressionNode(Collections.singletonList(iterationContextNode),
getNameRefNode(BuiltInType.UNKNOWN, iterationName), "for " + iterationName + "
in [ 1, 2, 3, 4 ] return " + iterationName);
+ List<Object> toPopulate = new ArrayList<>();
+ EvaluationContextImpl ctx = (EvaluationContextImpl)
EvaluationContextTestUtil.newEmptyEvaluationContext();
+ ExecutionFrame peeked = ctx.peek();
+ forExpressionNode.populateToReturn(0, ctx, toPopulate);
+ assertThat(toPopulate).containsExactly(BigDecimal.ONE,
+ BigDecimal.valueOf(2),
+ BigDecimal.valueOf(3),
+ BigDecimal.valueOf(4));
+ assertThat(ctx.getAllValues()).doesNotContainKeys(iterationName);
+ assertThat(ctx.peek()).isEqualTo(peeked);
+ }
+
+ @Test
+ void populateToReturnOutsideBoundaries() {
+ IterationContextNode x = getIterationContextNode("x",
getLocalDateRangeNode("[1980-01-01 .. 1980-01-03]", LocalDate.of(1980, 1, 1),
LocalDate.of(1980, 1, 3), RangeNode.IntervalBoundary.CLOSED,
RangeNode.IntervalBoundary.CLOSED ), "x in [1980-01-01 .. 1980-01-03]");
+ ForExpressionNode forExpressionNode = new
ForExpressionNode(Collections.singletonList(x),
getNameRefNode(BuiltInType.DATE, "x"), "for x in [1980-01-01 .. 1980-01-03]
return x");
+ List<Object> toPopulate = new ArrayList<>();
+ EvaluationContext ctx =
EvaluationContextTestUtil.newEmptyEvaluationContext();
+ forExpressionNode.populateToReturn(1, ctx, toPopulate);
+ assertThat(toPopulate).isEmpty();
+ }
+
+ @Test
+ void createForIterationFromRange() {
+ String iterationName = "x";
+ IterationContextNode iterationContextNode =
getIterationContextNode(iterationName, getLocalDateRangeNode("[1980-01-01 ..
1980-01-03]", LocalDate.of(1980, 1, 1), LocalDate.of(1980, 1, 3),
RangeNode.IntervalBoundary.CLOSED, RangeNode.IntervalBoundary.CLOSED ), "x in
[1980-01-01 .. 1980-01-03]");
+ ForIteration retrieved =
ForExpressionNode.createForIteration(EvaluationContextTestUtil.newEmptyEvaluationContext(),
iterationContextNode);
+ assertThat(retrieved).isNotNull();
+ assertThat(retrieved.getName()).isEqualTo(iterationName);
+ assertThat(retrieved.hasNextValue()).isTrue();
+ assertThat(retrieved.getNextValue()).isEqualTo(LocalDate.of(1980, 1,
1));
+ }
+
+ @Test
+ void createForIterationFromArray() {
+ String iterationName = "x";
+ IterationContextNode iterationContextNode =
getIterationContextNode("x", getListNode("[ 1, 2, 3, 4 ]", Arrays.asList("1",
"2", "3", "4")), "x in [ 1, 2, 3, 4 ]");
+ ForIteration retrieved =
ForExpressionNode.createForIteration(EvaluationContextTestUtil.newEmptyEvaluationContext(),
iterationContextNode);
+ assertThat(retrieved).isNotNull();
+ assertThat(retrieved.getName()).isEqualTo(iterationName);
+ assertThat(retrieved.hasNextValue()).isTrue();
+ assertThat(retrieved.getNextValue()).isEqualTo(BigDecimal.ONE);
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]