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&lt;Object&gt;</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]

Reply via email to