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 16897949cb [incubator-kie-issues#1546] Fix DMN TCK range equality test 
failures for unary test ranges (#6134)
16897949cb is described below

commit 16897949cb6b691ec6b919cd4593288ebbd00cee
Author: Gabriele Cardosi <[email protected]>
AuthorDate: Wed Oct 23 10:42:21 2024 +0200

    [incubator-kie-issues#1546] Fix DMN TCK range equality test failures for 
unary test ranges (#6134)
    
    * Introduce undefined boundaries for range instances.
    
    Signed-off-by: Tibor Zimányi <[email protected]>
    
    * Update inclusion and equality methods for FEEL range.
    
    Signed-off-by: Tibor Zimányi <[email protected]>
    
    * Fix compiled FEEL scenarios with ranges.
    
    * Restore FEELRangesTest.
    
    * Add RangeImpl unit tests.
    
    * [range-problems-gc] WIP
    
    * [range-problems-gc] WIP
    
    * [incubator-kie-issues#1546] Add UndefinedValueComparable 
UndefinedValueNode
    
    * [incubator-kie-issues#1546] Fixing tests - WIP
    
    * [incubator-kie-issues#1546] Fixing tests - WIP
    
    * [incubator-kie-issues#1546] Fixing tests
    
    * [incubator-kie-issues#1546] Fixing tests
    
    ---------
    
    Signed-off-by: Tibor Zimányi <[email protected]>
    Co-authored-by: Tibor Zimányi <[email protected]>
    Co-authored-by: Gabriele-Cardosi <[email protected]>
---
 .../org/kie/dmn/feel/parser/feel11/FEEL_1_1.g4     |  9 +++-
 .../dmn/feel/codegen/feel11/ASTCompilerHelper.java |  6 +++
 .../feel/codegen/feel11/ASTCompilerVisitor.java    |  7 +++
 .../feel/codegen/feel11/ASTUnaryTestTransform.java |  6 +++
 .../feel/codegen/feel11/DMNCodegenConstants.java   |  2 +
 .../kie/dmn/feel/lang/ast/ASTBuilderFactory.java   |  4 ++
 .../java/org/kie/dmn/feel/lang/ast/RangeNode.java  | 11 ++--
 .../ast/UndefinedValueNode.java}                   | 26 +++++-----
 .../java/org/kie/dmn/feel/lang/ast/Visitor.java    |  1 +
 .../ast/visitor/ASTHeuristicCheckerVisitor.java    |  7 ++-
 .../feel/lang/ast/visitor/DefaultedVisitor.java    |  6 +++
 .../dmn/feel/parser/feel11/ASTBuilderVisitor.java  | 13 +++--
 .../main/java/org/kie/dmn/feel/runtime/Range.java  |  2 +
 .../dmn/feel/runtime/functions/RangeFunction.java  |  1 +
 .../org/kie/dmn/feel/runtime/impl/RangeImpl.java   | 60 ++++++++++++++++++----
 .../UndefinedValueComparable.java}                 | 34 +++++++-----
 .../java/org/kie/dmn/feel/util/EvalHelper.java     |  4 ++
 .../main/java/org/kie/dmn/feel/util/TypeUtil.java  | 47 ++++++++++++++---
 .../feel/marshaller/FEELCodeMarshallerTest.java    | 12 +++--
 .../FEELCodeMarshallerUnmarshallTest.java          | 14 +++--
 .../feel/parser/feel11/FEELParserSeverityTest.java |  2 +-
 .../org/kie/dmn/feel/runtime/FEELRangesTest.java   | 12 ++++-
 .../kie/dmn/feel/runtime/impl/RangeImplTest.java   | 38 ++++++++++++++
 .../dmn/validation/dtanalysis/DMNDTAnalyser.java   | 10 ++--
 .../dmn/validation/dtanalysis/model/Interval.java  |  3 +-
 25 files changed, 269 insertions(+), 68 deletions(-)

diff --git 
a/kie-dmn/kie-dmn-feel/src/main/antlr4/org/kie/dmn/feel/parser/feel11/FEEL_1_1.g4
 
b/kie-dmn/kie-dmn-feel/src/main/antlr4/org/kie/dmn/feel/parser/feel11/FEEL_1_1.g4
index 9f04edc453..09eb8cb081 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/antlr4/org/kie/dmn/feel/parser/feel11/FEEL_1_1.g4
+++ 
b/kie-dmn/kie-dmn-feel/src/main/antlr4/org/kie/dmn/feel/parser/feel11/FEEL_1_1.g4
@@ -324,7 +324,8 @@ literal
     |  BooleanLiteral          #boolLiteral
     |   atLiteral               #atLiteralLabel
     |  StringLiteral           #stringLiteral
-    |  NULL                #nullLiteral
+    |  NULL                    #nullLiteral
+    |   UNDEFINEDVALUE          #undefined
     ;
     
 atLiteral
@@ -340,6 +341,7 @@ BooleanLiteral
     |   FALSE
     ;
 
+
 /**************************
  *    OTHER CONSTRUCTS
  **************************/
@@ -463,6 +465,7 @@ reusableKeywords
     | BETWEEN
     | NOT
     | NULL
+    | UNDEFINEDVALUE
     | TRUE
     | FALSE
     ;
@@ -536,6 +539,10 @@ NULL
     : 'null'
     ;
 
+UNDEFINEDVALUE
+    : 'undefined'
+    ;
+
 TRUE
     : 'true'
     ;
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerHelper.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerHelper.java
index dc87cd9e5d..b2b5f1bf59 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerHelper.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerHelper.java
@@ -79,6 +79,7 @@ import org.kie.dmn.feel.lang.ast.TemporalConstantNode;
 import org.kie.dmn.feel.lang.ast.TypeNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.lang.impl.JavaBackedType;
 import org.kie.dmn.feel.lang.impl.MapBackedType;
 import org.kie.dmn.feel.lang.types.AliasFEELType;
@@ -144,6 +145,7 @@ import static 
org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.TEMPORALCONSTA
 import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.TYPE_CT;
 import static 
org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.UNARYTESTLISTNODE_CT;
 import static 
org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.UNARYTESTNODE_CT;
+import static 
org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.UNDEFINEDVALUENODE_CT;
 import static org.kie.dmn.feel.util.CodegenUtils.getEnumExpression;
 import static org.kie.dmn.feel.util.CodegenUtils.getListExpression;
 import static org.kie.dmn.feel.util.CodegenUtils.getStringLiteralExpr;
@@ -488,6 +490,10 @@ public class ASTCompilerHelper {
                                                        n.getText());
     }
 
+    public BlockStmt add(UndefinedValueNode n) {
+        return addVariableDeclaratorWithObjectCreation(UNDEFINEDVALUENODE_CT, 
NodeList.nodeList());
+    }
+
     public String getLastVariableName() {
         return lastVariableName.get();
     }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java
index a4bef5554d..ffa86fc061 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java
@@ -56,6 +56,7 @@ import org.kie.dmn.feel.lang.ast.StringNode;
 import org.kie.dmn.feel.lang.ast.TemporalConstantNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.lang.ast.Visitor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -290,6 +291,12 @@ public class ASTCompilerVisitor implements 
Visitor<BlockStmt> {
         return compilerHelper.add(n);
     }
 
+    @Override
+    public BlockStmt visit(UndefinedValueNode n) {
+        LOGGER.trace("visit {}", n);
+        return compilerHelper.add(n);
+    }
+
     public String getLastVariableName() {
         LOGGER.trace("getLastVariableName");
         return compilerHelper.getLastVariableName();
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTUnaryTestTransform.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTUnaryTestTransform.java
index 133531034e..3f2ea6e907 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTUnaryTestTransform.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTUnaryTestTransform.java
@@ -37,6 +37,7 @@ import org.kie.dmn.feel.lang.ast.RangeNode;
 import org.kie.dmn.feel.lang.ast.StringNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.lang.ast.visitor.DefaultedVisitor;
 
 public class ASTUnaryTestTransform extends 
DefaultedVisitor<ASTUnaryTestTransform.UnaryTestSubexpr> {
@@ -136,6 +137,11 @@ public class ASTUnaryTestTransform extends 
DefaultedVisitor<ASTUnaryTestTransfor
         }
     }
 
+    @Override
+    public UnaryTestSubexpr visit(UndefinedValueNode n) {
+        return new SimpleUnaryExpression(n);
+    }
+
     private UnaryTestSubexpr propagateWildcard(ASTNode n) {
         return Arrays.stream(n.getChildrenNode()).map(e -> 
e.accept(this)).anyMatch(UnaryTestSubexpr::isWildcard) ?
                 new WildCardUnaryExpression((BaseNode) n) : new 
SimpleUnaryExpression((BaseNode) n);
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/DMNCodegenConstants.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/DMNCodegenConstants.java
index f5db4e4150..4b214951b0 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/DMNCodegenConstants.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/DMNCodegenConstants.java
@@ -57,6 +57,7 @@ import org.kie.dmn.feel.lang.ast.StringNode;
 import org.kie.dmn.feel.lang.ast.TemporalConstantNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.lang.impl.JavaBackedType;
 import org.kie.dmn.feel.lang.impl.MapBackedType;
 import org.kie.dmn.feel.lang.types.AliasFEELType;
@@ -172,6 +173,7 @@ public class DMNCodegenConstants {
             
parseClassOrInterfaceType(UnaryTestListNode.class.getCanonicalName());
     public static final ClassOrInterfaceType UNARYTESTNODE_CT =
             parseClassOrInterfaceType(UnaryTestNode.class.getCanonicalName());
+    public static final ClassOrInterfaceType UNDEFINEDVALUENODE_CT = 
parseClassOrInterfaceType(UndefinedValueNode.class.getCanonicalName());
 
     private DMNCodegenConstants() {
     }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ASTBuilderFactory.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ASTBuilderFactory.java
index 95a1f5c54a..8908a3a9dd 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ASTBuilderFactory.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ASTBuilderFactory.java
@@ -43,6 +43,10 @@ public class ASTBuilderFactory {
         return new NullNode( ctx );
     }
 
+    public static UndefinedValueNode newUndefinedValueNode() {
+        return new UndefinedValueNode();
+    }
+
     public static StringNode newStringNode(ParserRuleContext ctx) {
         return new StringNode( ctx );
     }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/RangeNode.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/RangeNode.java
index c64317ad43..0d44d025d7 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/RangeNode.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/RangeNode.java
@@ -28,6 +28,7 @@ import org.kie.dmn.feel.lang.types.BuiltInType;
 import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.runtime.impl.RangeImpl;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 import org.kie.dmn.feel.util.Msg;
 
 public class RangeNode
@@ -113,13 +114,17 @@ public class RangeNode
         
         Type sType = BuiltInType.determineTypeFromInstance(s);
         Type eType = BuiltInType.determineTypeFromInstance(e);
-        if (s != null && e != null && sType != eType && 
!s.getClass().isAssignableFrom(e.getClass())) {
+        boolean withUndefined = s instanceof UndefinedValueComparable || e 
instanceof UndefinedValueComparable;
+        if (s != null && e != null &&
+                !withUndefined &&
+                sType != eType &&
+                !s.getClass().isAssignableFrom(e.getClass())) {
             ctx.notifyEvt( astEvent(Severity.ERROR, 
Msg.createMessage(Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, "Start", "End")));
             return null;
         }
 
-        Comparable start = convertToComparable( ctx, s );
-        Comparable end = convertToComparable( ctx, e );
+        Comparable start = s instanceof UndefinedValueComparable ? 
(Comparable) s : convertToComparable(ctx, s );
+        Comparable end = e instanceof UndefinedValueComparable ? (Comparable) 
e : convertToComparable( ctx, e );
 
         return new RangeImpl( lowerBound==IntervalBoundary.OPEN ? 
Range.RangeBoundary.OPEN : Range.RangeBoundary.CLOSED,
                               start,
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UndefinedValueNode.java
similarity index 64%
copy from kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
copy to 
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UndefinedValueNode.java
index 39666b6c85..dd423acdb5 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UndefinedValueNode.java
@@ -16,22 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.kie.dmn.feel.runtime;
+package org.kie.dmn.feel.lang.ast;
 
-public interface Range {
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 
-    enum RangeBoundary {
-        OPEN, CLOSED;
-    }
-
-    RangeBoundary getLowBoundary();
-
-    Comparable getLowEndPoint();
+public class UndefinedValueNode
+        extends BaseNode {
 
-    Comparable getHighEndPoint();
+    public UndefinedValueNode() { }
 
-    RangeBoundary getHighBoundary();
+    @Override
+    public Object evaluate(EvaluationContext ctx) {
+        return new UndefinedValueComparable();
+    }
 
-    Boolean includes(Object param);
+    @Override
+    public <T> T accept(Visitor<T> v) {
+        return v.visit(this);
+    }
 
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/Visitor.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/Visitor.java
index 8277535645..1158d134b0 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/Visitor.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/Visitor.java
@@ -60,4 +60,5 @@ public interface Visitor<T> {
 
     T visit(UnaryTestListNode n);
     T visit(UnaryTestNode n);
+    T visit(UndefinedValueNode n);
 }
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java
index 2d39b7d19d..5927d3e0c0 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTHeuristicCheckerVisitor.java
@@ -19,16 +19,15 @@
 package org.kie.dmn.feel.lang.ast.visitor;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent;
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.lang.ast.ASTNode;
 import org.kie.dmn.feel.lang.ast.InfixOpNode;
-import org.kie.dmn.feel.lang.ast.NullNode;
 import org.kie.dmn.feel.lang.ast.RangeNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.runtime.events.ASTHeuristicCheckEvent;
 import org.kie.dmn.feel.util.Msg;
 
@@ -63,8 +62,8 @@ public class ASTHeuristicCheckerVisitor extends 
DefaultedVisitor<List<FEELEvent>
 
     @Override
     public List<FEELEvent> visit(RangeNode n) {
-        if ((n.getStart() instanceof NullNode && n.getEnd() instanceof 
RangeNode)
-                || (n.getStart() instanceof RangeNode && n.getEnd() instanceof 
NullNode)) {
+        if ((n.getStart() instanceof UndefinedValueNode && n.getEnd() 
instanceof RangeNode)
+                || (n.getStart() instanceof RangeNode && n.getEnd() instanceof 
UndefinedValueNode)) {
             return List.of(new ASTHeuristicCheckEvent(Severity.WARN, 
Msg.createMessage(Msg.UT_OF_UT, n.getText()), n));
         }
         return defaultVisit(n);
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/DefaultedVisitor.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/DefaultedVisitor.java
index 6eb2d6b79d..1b55497e2f 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/DefaultedVisitor.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/DefaultedVisitor.java
@@ -54,6 +54,7 @@ import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
 import org.kie.dmn.feel.lang.ast.StringNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.lang.ast.Visitor;
 
 public abstract class DefaultedVisitor<T> implements Visitor<T> {
@@ -240,4 +241,9 @@ public abstract class DefaultedVisitor<T> implements 
Visitor<T> {
         return defaultVisit(n);
     }
 
+    @Override
+    public T visit(UndefinedValueNode n) {
+        return defaultVisit(n);
+    }
+
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java
index 295b9fe539..64465e00d0 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java
@@ -113,6 +113,11 @@ public class ASTBuilderVisitor
         return ASTBuilderFactory.newNullNode( ctx );
     }
 
+    @Override
+    public BaseNode visitUndefined(FEEL_1_1Parser.UndefinedContext ctx) {
+        return ASTBuilderFactory.newUndefinedValueNode();
+    }
+
     @Override
     public BaseNode visitStringLiteral(FEEL_1_1Parser.StringLiteralContext 
ctx) {
         return ASTBuilderFactory.newStringNode( ctx );
@@ -188,13 +193,13 @@ public class ASTBuilderVisitor
         String op = ctx.op.getText();
         switch (UnaryOperator.determineOperator(op)) {
             case GT:
-                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.OPEN, value, ASTBuilderFactory.newNullNode(ctx), 
RangeNode.IntervalBoundary.OPEN);
+                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.OPEN, value, 
ASTBuilderFactory.newUndefinedValueNode(), RangeNode.IntervalBoundary.OPEN);
             case GTE:
-                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.CLOSED, value, ASTBuilderFactory.newNullNode(ctx), 
RangeNode.IntervalBoundary.OPEN);
+                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.CLOSED, value, 
ASTBuilderFactory.newUndefinedValueNode(), RangeNode.IntervalBoundary.OPEN);
             case LT:
-                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.OPEN, ASTBuilderFactory.newNullNode(ctx), value, 
RangeNode.IntervalBoundary.OPEN);
+                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.OPEN, ASTBuilderFactory.newUndefinedValueNode(), 
value, RangeNode.IntervalBoundary.OPEN);
             case LTE:
-                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.OPEN, ASTBuilderFactory.newNullNode(ctx), value, 
RangeNode.IntervalBoundary.CLOSED);
+                return ASTBuilderFactory.newIntervalNode(ctx, 
RangeNode.IntervalBoundary.OPEN, ASTBuilderFactory.newUndefinedValueNode(), 
value, RangeNode.IntervalBoundary.CLOSED);
             default:
                 throw new UnsupportedOperationException("by the parser rule 
FEEL grammar rule 7.a for range syntax should not have determined the operator 
" + op);
         }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
index 39666b6c85..3ca1ec857b 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
@@ -34,4 +34,6 @@ public interface Range {
 
     Boolean includes(Object param);
 
+    boolean isWithUndefined();
+
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java
index 9dab904aca..5e37b769bc 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java
@@ -134,6 +134,7 @@ public class RangeFunction extends BaseFEELFunction {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "endpoints must be of 
equivalent types"));
         }
 
+        // Boundary values need to be always defined in range string. They can 
be undefined only in unary test, that represents range, e.g. (<10). 
         return FEELFnResult.ofResult(new RangeImpl(startBoundary, (Comparable) 
left, (Comparable) right, endBoundary));
     }
 
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java
index f16ee87dd3..51893062d9 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java
@@ -23,6 +23,11 @@ import java.util.function.BiPredicate;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.util.BooleanEvalHelper;
 
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.GT;
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.GTE;
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.LT;
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.LTE;
+
 public class RangeImpl
         implements Range {
 
@@ -30,7 +35,7 @@ public class RangeImpl
     private RangeBoundary highBoundary;
     private Comparable    lowEndPoint;
     private Comparable    highEndPoint;
-
+    private boolean withUndefined = false;
 
     public RangeImpl() {
     }
@@ -40,6 +45,7 @@ public class RangeImpl
         this.highBoundary = highBoundary;
         this.lowEndPoint = lowEndPoint;
         this.highEndPoint = highEndPoint;
+        withUndefined = lowEndPoint instanceof UndefinedValueComparable || 
highEndPoint instanceof UndefinedValueComparable;
     }
 
     @Override
@@ -67,21 +73,30 @@ public class RangeImpl
         if (param == null) {
             return null;
         }
-        if (lowEndPoint == null) {
-            if (highEndPoint == null) {
+        if (lowEndPoint == null || lowEndPoint instanceof 
UndefinedValueComparable) {
+            if (highEndPoint == null || highEndPoint instanceof 
UndefinedValueComparable) {
                 return null;
-            } else {
+            } else if (lowEndPoint != null) { // it means it is 
UndefinedValueComparable
                 return negInfRangeIncludes(param);
+            } else {
+                return false;
             }
         } else {
-            if (highEndPoint == null) {
+            if (highEndPoint instanceof UndefinedValueComparable) {
                 return posInfRangeIncludes(param);
-            } else {
+            } else if (highEndPoint != null) {
                 return finiteRangeIncludes(param);
+            } else {
+                return false;
             }
         }
     }
 
+    @Override
+    public boolean isWithUndefined() {
+        return withUndefined;
+    }
+
     private Boolean finiteRangeIncludes(Object param) {
         if (lowBoundary == RangeBoundary.OPEN && highBoundary == 
RangeBoundary.OPEN) {
             return bothOrThrow(compare(lowEndPoint, param, (l, r) -> 
l.compareTo(r) < 0) , compare(highEndPoint, param,  (l, r) -> l.compareTo(r) > 
0), param);
@@ -154,9 +169,36 @@ public class RangeImpl
 
     @Override
     public String toString() {
+        return withUndefined ? withUndefinedtoString() : 
withoutUndefinedtoString();
+    }
+
+    private String withoutUndefinedtoString() {
         return (lowBoundary == RangeBoundary.OPEN ? "(" : "[") +
-               " " + lowEndPoint +
-               " .. " + highEndPoint +
-               " " + ( highBoundary == RangeBoundary.OPEN ? ")" : "]" );
+                " " + lowEndPoint +
+                " .. " + highEndPoint +
+                " " + ( highBoundary == RangeBoundary.OPEN ? ")" : "]" );
+    }
+
+    private String withUndefinedtoString() {
+        StringBuilder sb = new StringBuilder("( ");
+        if (lowEndPoint instanceof UndefinedValueComparable) {
+            if (highBoundary == RangeBoundary.OPEN) {
+                sb.append(LT.symbol);
+            } else {
+                sb.append(LTE.symbol);
+            }
+            sb.append(" ");
+            sb.append(highEndPoint);
+        } else if (highEndPoint instanceof UndefinedValueComparable) {
+            if (lowBoundary == RangeBoundary.OPEN) {
+                sb.append(GT.symbol);
+            } else {
+                sb.append(GTE.symbol);
+            }
+            sb.append(" ");
+            sb.append(lowEndPoint);
+        }
+        sb.append(" )");
+        return sb.toString();
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/UndefinedValueComparable.java
similarity index 63%
copy from kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
copy to 
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/UndefinedValueComparable.java
index 39666b6c85..240f7c98da 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/UndefinedValueComparable.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,22 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.kie.dmn.feel.runtime;
+package org.kie.dmn.feel.runtime.impl;
 
-public interface Range {
+public class UndefinedValueComparable implements 
Comparable<UndefinedValueComparable> {
 
-    enum RangeBoundary {
-        OPEN, CLOSED;
-    }
-
-    RangeBoundary getLowBoundary();
 
-    Comparable getLowEndPoint();
-
-    Comparable getHighEndPoint();
+    @Override
+    public int compareTo(UndefinedValueComparable o) {
+        return 0;
+    }
 
-    RangeBoundary getHighBoundary();
+    @Override
+    public String toString() {
+        return "undefined";
+    }
 
-    Boolean includes(Object param);
+    @Override
+    public int hashCode() {
+        return 0;
+    }
 
-}
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof UndefinedValueComparable;
+    }
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
index ddd788b19d..346712fe93 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
@@ -38,6 +38,7 @@ import org.kie.dmn.api.core.FEELPropertyAccessible;
 import org.kie.dmn.feel.lang.FEELProperty;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.runtime.Range.RangeBoundary;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -186,6 +187,9 @@ public class EvalHelper {
                 default:
                     return PropertyValueResult.notDefined();
             }
+            if (result instanceof UndefinedValueComparable) {
+                result = null;
+            }
         } else {
             Method getter = getGenericAccessor( current.getClass(), property );
             if ( getter != null ) {
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java
index 7af8ad5d7a..339f1dbf14 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java
@@ -41,6 +41,12 @@ import org.kie.dmn.feel.runtime.custom.ZoneTime;
 import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction;
 import org.kie.dmn.feel.runtime.functions.DateFunction;
 import org.kie.dmn.feel.runtime.functions.TimeFunction;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
+
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.GT;
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.GTE;
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.LT;
+import static org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator.LTE;
 
 public final class TypeUtil {
 
@@ -78,7 +84,8 @@ public final class TypeUtil {
         } else if (val instanceof ZoneTime zoneTime) {
             return formatTimeString(zoneTime.format(), wrapForCodeUsage);
         } else if (val instanceof LocalDateTime || val instanceof 
OffsetDateTime) {
-            return 
formatDateTimeString(DateAndTimeFunction.FEEL_DATE_TIME.format((TemporalAccessor)
 val), wrapForCodeUsage);
+            return 
formatDateTimeString(DateAndTimeFunction.FEEL_DATE_TIME.format((TemporalAccessor)
 val),
+                                        wrapForCodeUsage);
         } else if (val instanceof ZonedDateTime) {
             TemporalAccessor ta = (TemporalAccessor) val;
             ZoneId zone = ta.query(TemporalQueries.zone());
@@ -86,7 +93,8 @@ public final class TypeUtil {
                 // it is a ZoneRegion
                 return 
formatDateTimeString(DateAndTimeFunction.REGION_DATETIME_FORMATTER.format((TemporalAccessor)
 val), wrapForCodeUsage);
             } else {
-                return 
formatDateTimeString(DateAndTimeFunction.FEEL_DATE_TIME.format((TemporalAccessor)
 val), wrapForCodeUsage);
+                return 
formatDateTimeString(DateAndTimeFunction.FEEL_DATE_TIME.format((TemporalAccessor)
 val),
+                                            wrapForCodeUsage);
             }
         } else if (val instanceof Duration) {
             return formatDuration((Duration) val, wrapForCodeUsage);
@@ -183,11 +191,33 @@ public final class TypeUtil {
 
     public static String formatRange(final Range val, final boolean 
wrapDateTimeValuesInFunctions) {
         final StringBuilder sb = new StringBuilder();
-        sb.append(val.getLowBoundary() == Range.RangeBoundary.OPEN ? "( " : "[ 
");
-        sb.append(formatValue(val.getLowEndPoint(), 
wrapDateTimeValuesInFunctions));
-        sb.append(" .. ");
-        sb.append(formatValue(val.getHighEndPoint(), 
wrapDateTimeValuesInFunctions));
-        sb.append(val.getHighBoundary() == Range.RangeBoundary.OPEN ? " )" : " 
]");
+        if (val.isWithUndefined()) {
+            sb.append("( ");
+            if (val.getLowEndPoint() instanceof UndefinedValueComparable) {
+                if (val.getHighBoundary() == Range.RangeBoundary.OPEN) {
+                    sb.append(LT.symbol);
+                } else {
+                    sb.append(LTE.symbol);
+                }
+                sb.append(" ");
+                sb.append(formatValue(val.getHighEndPoint(), 
wrapDateTimeValuesInFunctions));
+            } else if (val.getHighEndPoint() instanceof 
UndefinedValueComparable) {
+                if (val.getLowBoundary() == Range.RangeBoundary.OPEN) {
+                    sb.append(GT.symbol);
+                } else {
+                    sb.append(GTE.symbol);
+                }
+                sb.append(" ");
+                sb.append(formatValue(val.getLowEndPoint(), 
wrapDateTimeValuesInFunctions));
+            }
+            sb.append(" )");
+        } else {
+            sb.append(val.getLowBoundary() == Range.RangeBoundary.OPEN ? "( " 
: "[ ");
+            sb.append(formatValue(val.getLowEndPoint(), 
wrapDateTimeValuesInFunctions));
+            sb.append(" .. ");
+            sb.append(formatValue(val.getHighEndPoint(), 
wrapDateTimeValuesInFunctions));
+            sb.append(val.getHighBoundary() == Range.RangeBoundary.OPEN ? " )" 
: " ]");
+        }
         return sb.toString();
     }
 
@@ -274,7 +304,8 @@ public final class TypeUtil {
         sb.append(timeSegmentChar);
     }
 
-    private static void appendSecondsToDurationString(final StringBuilder sb, 
final long seconds, final long nanoseconds) {
+    private static void appendSecondsToDurationString(final StringBuilder sb, 
final long seconds,
+                                                      final long nanoseconds) {
         if (seconds < 0 && nanoseconds > 0) {
             if (seconds == -1) {
                 sb.append("0");
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerTest.java
index 8b2adc20b4..b79ad9ab47 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerTest.java
@@ -36,6 +36,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.runtime.impl.RangeImpl;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -96,13 +97,18 @@ public class FEELCodeMarshallerTest {
                 { Arrays.asList( Duration.ofDays( 4 ), Duration.ofDays( 2 ), 
Duration.ofHours( 25 ) ), "[ duration( \"P4D\" ), duration( \"P2D\" ), 
duration( \"P1DT1H\" ) ]" },
                 { Arrays.asList( Arrays.asList( 1, 2 ), Arrays.asList( 3, 4 ) 
), "[ [ 1, 2 ], [ 3, 4 ] ]" },
                 // ranges
-                { new RangeImpl( Range.RangeBoundary.CLOSED, "a", "z", 
Range.RangeBoundary.OPEN ), "[ \"a\" .. \"z\" )" },
-                { new RangeImpl( Range.RangeBoundary.CLOSED, Duration.ofHours( 
30 ), Duration.ofHours( 50 ), Range.RangeBoundary.OPEN ), "[ duration( 
\"P1DT6H\" ) .. duration( \"P2DT2H\" ) )" },
+                { new RangeImpl( Range.RangeBoundary.CLOSED, "a", "z", 
Range.RangeBoundary.OPEN), "[ \"a\" .. \"z\" )" },
+                { new RangeImpl( Range.RangeBoundary.CLOSED, Duration.ofHours( 
30 ), Duration.ofHours( 50 ), Range.RangeBoundary.OPEN), "[ duration( 
\"P1DT6H\" ) .. duration( \"P2DT2H\" ) )" },
+                { new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ONE, new 
UndefinedValueComparable(), Range.RangeBoundary.OPEN), "( > 1 )" },
+                { new RangeImpl(Range.RangeBoundary.CLOSED, BigDecimal.ONE, 
new UndefinedValueComparable(), Range.RangeBoundary.OPEN), "( >= 1 )" },
+                { new RangeImpl(Range.RangeBoundary.OPEN, new 
UndefinedValueComparable(), BigDecimal.ONE, Range.RangeBoundary.OPEN), "( < 1 
)" },
+                { new RangeImpl(Range.RangeBoundary.OPEN, new 
UndefinedValueComparable(), BigDecimal.ONE, Range.RangeBoundary.CLOSED), "( <= 
1 )" },
                 // context
                 { new LinkedHashMap() {{ put( "Full Name", "John Doe"); put( 
"Age", 35 ); put( "Date of Birth", LocalDate.of( 1982, 6, 9 ) ); }},
                   "{ Full Name : \"John Doe\", Age : 35, Date of Birth : date( 
\"1982-06-09\" ) }" },
                 // null
-                { null, "null" }
+                { null, "null" },
+                { new UndefinedValueComparable(), "undefined"}
         };
         return Arrays.asList( cases );
     }
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerUnmarshallTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerUnmarshallTest.java
index aa2457b836..0635ac3640 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerUnmarshallTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/marshaller/FEELCodeMarshallerUnmarshallTest.java
@@ -37,6 +37,7 @@ import org.kie.dmn.feel.lang.types.BuiltInType;
 import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.runtime.impl.RangeImpl;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -91,13 +92,20 @@ public class FEELCodeMarshallerUnmarshallTest {
                 { BuiltInType.UNKNOWN, "[ duration( \"P4D\" ), duration( 
\"P2D\" ), duration( \"P1DT1H\" ) ]", Arrays.asList( Duration.ofDays( 4 ), 
Duration.ofDays( 2 ), Duration.ofHours( 25 ) ) },
                 { BuiltInType.UNKNOWN, "[ [ 1, 2 ], [ 3, 4 ] ]", 
Arrays.asList( Arrays.asList( BigDecimal.valueOf( 1 ), BigDecimal.valueOf( 2 ) 
), Arrays.asList( BigDecimal.valueOf( 3 ), BigDecimal.valueOf( 4 ) ) ) },
                 // ranges
-                { BuiltInType.UNKNOWN, "[ \"a\" .. \"z\" )", new RangeImpl( 
Range.RangeBoundary.CLOSED, "a", "z", Range.RangeBoundary.OPEN ) },
-                { BuiltInType.UNKNOWN, "[ duration( \"P1DT6H\" ) .. duration( 
\"P2DT2H\" ) )", new RangeImpl( Range.RangeBoundary.CLOSED, Duration.ofHours( 
30 ), Duration.ofHours( 50 ), Range.RangeBoundary.OPEN ) },
+                { BuiltInType.UNKNOWN, "[ \"a\" .. \"z\" )", new RangeImpl( 
Range.RangeBoundary.CLOSED, "a", "z", Range.RangeBoundary.OPEN) },
+                { BuiltInType.UNKNOWN, "[ duration( \"P1DT6H\" ) .. duration( 
\"P2DT2H\" ) )", new RangeImpl( Range.RangeBoundary.CLOSED, Duration.ofHours( 
30 ), Duration.ofHours( 50 ), Range.RangeBoundary.OPEN) },
+
+                {  BuiltInType.UNKNOWN, "( > 1 )", new 
RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ONE, new 
UndefinedValueComparable(), Range.RangeBoundary.OPEN)},
+                { BuiltInType.UNKNOWN, "( >= 1 )", new 
RangeImpl(Range.RangeBoundary.CLOSED, BigDecimal.ONE, new 
UndefinedValueComparable(), Range.RangeBoundary.OPEN) },
+                { BuiltInType.UNKNOWN, "( < 1 )",  new 
RangeImpl(Range.RangeBoundary.OPEN, new UndefinedValueComparable(), 
BigDecimal.ONE, Range.RangeBoundary.OPEN)},
+                { BuiltInType.UNKNOWN, "( <= 1 )", new 
RangeImpl(Range.RangeBoundary.OPEN, new UndefinedValueComparable(), 
BigDecimal.ONE, Range.RangeBoundary.CLOSED) },
+
                 // context
                 { BuiltInType.UNKNOWN, "{ Full Name : \"John Doe\", Age : 35, 
Date of Birth : date( \"1982-06-09\" ) }",
                   new LinkedHashMap() {{ put( "Full Name", "John Doe"); put( 
"Age", BigDecimal.valueOf( 35 ) ); put( "Date of Birth", LocalDate.of( 1982, 6, 
9 ) ); }} },
                 // null
-                { BuiltInType.UNKNOWN, "null", null }
+                { BuiltInType.UNKNOWN, "null", null },
+                { BuiltInType.UNKNOWN, "undefined", new 
UndefinedValueComparable() }
         };
         return Arrays.asList( cases );
     }
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserSeverityTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserSeverityTest.java
index 6f49989897..02851b82d2 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserSeverityTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserSeverityTest.java
@@ -83,7 +83,7 @@ class FEELParserSeverityTest {
 
     @Test
     void unexistentOperatorInvokeLTLT() {
-        // RHDM-1119 
+        // RHDM-1119
         String inputExpression = "{ m: <<18 }.m(16)";
         ASTNode number = parseSeverity(inputExpression, 
FEELEvent.Severity.WARN);
 
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java
index 780e31e96d..b2419f5263 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java
@@ -31,6 +31,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent;
 import org.kie.dmn.feel.lang.FEELDialect;
 import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
 import org.kie.dmn.feel.runtime.impl.RangeImpl;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 
 public class FEELRangesTest extends BaseFEELTest {
 
@@ -42,6 +43,13 @@ public class FEELRangesTest extends BaseFEELTest {
 
     private static Collection<Object[]> data() {
         final Object[][] cases = new Object[][]{
+                // when converting from unary tests, boundaries are dictated 
by comparison
+                {"(>1)", new RangeImpl(Range.RangeBoundary.OPEN, 
BigDecimal.ONE, new UndefinedValueComparable(), Range.RangeBoundary.OPEN), 
null},
+                {"(>=1)", new RangeImpl(Range.RangeBoundary.CLOSED, 
BigDecimal.ONE, new UndefinedValueComparable(), Range.RangeBoundary.OPEN), 
null},
+                {"(<1)", new RangeImpl(Range.RangeBoundary.OPEN, new 
UndefinedValueComparable(), BigDecimal.ONE, Range.RangeBoundary.OPEN), null},
+                {"(<=1)", new RangeImpl(Range.RangeBoundary.OPEN, new 
UndefinedValueComparable(), BigDecimal.ONE, Range.RangeBoundary.CLOSED), null},
+                {"(null..10)", new RangeImpl(Range.RangeBoundary.OPEN, null, 
BigDecimal.valueOf(10), Range.RangeBoundary.OPEN), null},
+
                 {"[1..2]", new RangeImpl(Range.RangeBoundary.CLOSED, 
BigDecimal.ONE, BigDecimal.valueOf(2), Range.RangeBoundary.CLOSED), null},
                 {"[2..1]", new RangeImpl(Range.RangeBoundary.CLOSED, 
BigDecimal.valueOf(2), BigDecimal.ONE, Range.RangeBoundary.CLOSED), null},
                 {"[1..2)", new RangeImpl(Range.RangeBoundary.CLOSED, 
BigDecimal.ONE, BigDecimal.valueOf(2), Range.RangeBoundary.OPEN), null},
@@ -161,7 +169,7 @@ public class FEELRangesTest extends BaseFEELTest {
                             put("enddate", LocalDate.of(1978, 10, 13));
                             put("rangedates", new 
RangeImpl(Range.RangeBoundary.CLOSED, LocalDate.of(1978, 9, 12), 
LocalDate.of(1978, 10, 13), Range.RangeBoundary.CLOSED));
                         }}, null},
-                
+
                 // Table 42:
                 {"[1..10].start included", Boolean.TRUE, null},
                 {"[1..10].start", new BigDecimal(1), null},
@@ -172,12 +180,14 @@ public class FEELRangesTest extends BaseFEELTest {
                 {"(1..10].end", new BigDecimal(10), null},
                 {"(1..10].end included", Boolean.TRUE, null},
                 {"(<=10).start included", Boolean.FALSE, null},
+                {"(<10).start", null, null},
                 {"(<=10).start", null, null},
                 {"(<=10).end", new BigDecimal(10), null},
                 {"(<=10).end included", Boolean.TRUE, null},
                 {"(>1).start included", Boolean.FALSE, null},
                 {"(>1).start", new BigDecimal(1), null},
                 {"(>1).end", null, null},
+                {"(>=1).end", null, null},
                 {"(>1).end included", Boolean.FALSE, null},
         };
         return addAdditionalParameters(cases, false);
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java
index 6201fe90b1..521abb12fc 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java
@@ -25,6 +25,24 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 class RangeImplTest {
 
+    @Test
+    void isWithUndefined() {
+        RangeImpl rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, null, 
null, Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isFalse();
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, 10, null, 
Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isFalse();
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, null, 10, 
Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isFalse();
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, null, new 
UndefinedValueComparable(), Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isTrue();
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, new 
UndefinedValueComparable(), null, Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isTrue();
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, 10, new 
UndefinedValueComparable(), Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isTrue();
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, new 
UndefinedValueComparable(), 10, Range.RangeBoundary.OPEN);
+        assertThat(rangeImpl.isWithUndefined()).isTrue();
+    }
+
     @Test
     void getLowBoundary() {
         final Range.RangeBoundary lowBoundary = Range.RangeBoundary.CLOSED;
@@ -77,6 +95,26 @@ class RangeImplTest {
         assertThat(rangeImpl.includes(10)).isTrue();
         assertThat(rangeImpl.includes(12)).isTrue();
         assertThat(rangeImpl.includes(15)).isTrue();
+
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, new 
UndefinedValueComparable(), 15, Range.RangeBoundary.CLOSED);
+        assertThat(rangeImpl.includes(-1456)).isTrue();
+        assertThat(rangeImpl.includes(20)).isFalse();
+        assertThat(rangeImpl.includes(null)).isNull();
+
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, 15, new 
UndefinedValueComparable(), Range.RangeBoundary.CLOSED);
+        assertThat(rangeImpl.includes(-1456)).isFalse();
+        assertThat(rangeImpl.includes(20)).isTrue();
+        assertThat(rangeImpl.includes(null)).isNull();
+
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, null, new 
UndefinedValueComparable(), Range.RangeBoundary.CLOSED);
+        assertThat(rangeImpl.includes(-1456)).isNull();
+        assertThat(rangeImpl.includes(20)).isNull();
+        assertThat(rangeImpl.includes(null)).isNull();
+
+        rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, new 
UndefinedValueComparable(), null, Range.RangeBoundary.CLOSED);
+        assertThat(rangeImpl.includes(-1456)).isNull();
+        assertThat(rangeImpl.includes(20)).isNull();
+        assertThat(rangeImpl.includes(null)).isNull();
     }
 
     @Test
diff --git 
a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyser.java
 
b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyser.java
index 84bdbc3683..e82e068c88 100644
--- 
a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyser.java
+++ 
b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyser.java
@@ -55,6 +55,7 @@ import org.kie.dmn.feel.lang.ast.RangeNode.IntervalBoundary;
 import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode;
 import org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator;
+import org.kie.dmn.feel.lang.ast.UndefinedValueNode;
 import org.kie.dmn.feel.lang.ast.Visitor;
 import org.kie.dmn.feel.lang.impl.FEELBuilder;
 import org.kie.dmn.feel.lang.impl.InterpretedExecutableExpression;
@@ -289,9 +290,9 @@ public class DMNDTAnalyser implements InternalDMNDTAnalyser 
{
     }
     
     private Optional<BaseNode> checkForDiamondRange(RangeNode rangeNode) {
-        if ((rangeNode.getStart() instanceof NullNode || rangeNode.getStart() 
== null) && rangeNode.getUpperBound() == IntervalBoundary.OPEN && 
rangeNode.getEnd() instanceof RangeNode) {
+        if ((rangeNode.getStart() instanceof NullNode || rangeNode.getStart() 
instanceof UndefinedValueNode || rangeNode.getStart() == null) && 
rangeNode.getUpperBound() == IntervalBoundary.OPEN && rangeNode.getEnd() 
instanceof RangeNode) {
             return Optional.ofNullable(((RangeNode) 
rangeNode.getEnd()).getStart()); // <> value
-        } else if ((rangeNode.getEnd() instanceof NullNode || 
rangeNode.getEnd() == null) && rangeNode.getLowerBound() == 
IntervalBoundary.OPEN && rangeNode.getStart() instanceof RangeNode) {
+        } else if ((rangeNode.getEnd() instanceof NullNode || 
rangeNode.getEnd() instanceof UndefinedValueNode  || rangeNode.getEnd() == 
null) && rangeNode.getLowerBound() == IntervalBoundary.OPEN && 
rangeNode.getStart() instanceof RangeNode) {
             return Optional.ofNullable(((RangeNode) 
rangeNode.getStart()).getEnd()); // >< value
         } else {
             return Optional.empty();
@@ -751,14 +752,15 @@ public class DMNDTAnalyser implements 
InternalDMNDTAnalyser {
             return new Interval(RangeBoundary.CLOSED, 
valueFromNode(ut.getValue()), minMax.getUpperBound().getValue(), 
minMax.getUpperBound().getBoundaryType(), rule, col);
         } else if (ut.getValue() instanceof RangeNode) {
             RangeNode rangeNode = (RangeNode) ut.getValue();
-            if (!(rangeNode.getStart() instanceof NullNode || 
rangeNode.getEnd() instanceof NullNode)) {
+            if (!(rangeNode.getStart() instanceof NullNode || 
rangeNode.getStart() instanceof UndefinedValueNode ||
+                    rangeNode.getEnd() instanceof NullNode || 
rangeNode.getEnd() instanceof UndefinedValueNode)) {
                 return new Interval(rangeNode.getLowerBound() == 
IntervalBoundary.OPEN ? RangeBoundary.OPEN : RangeBoundary.CLOSED,
                                     valueFromNode(rangeNode.getStart()),
                                     valueFromNode(rangeNode.getEnd()),
                                     rangeNode.getUpperBound() == 
IntervalBoundary.OPEN ? RangeBoundary.OPEN : RangeBoundary.CLOSED,
                                     rule,
                                     col);
-            } else if (rangeNode.getStart() instanceof NullNode) {
+            } else if (rangeNode.getStart() instanceof NullNode || 
rangeNode.getStart() instanceof UndefinedValueNode) {
                 return new Interval(minMax.getLowerBound().getBoundaryType(),
                                     minMax.getLowerBound().getValue(),
                                     valueFromNode(rangeNode.getEnd()),
diff --git 
a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java
 
b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java
index bb9c9ca09c..fb4ebccc8a 100644
--- 
a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java
+++ 
b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java
@@ -30,6 +30,7 @@ import java.util.stream.Stream;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.runtime.Range.RangeBoundary;
 import org.kie.dmn.feel.runtime.impl.RangeImpl;
+import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
 import org.kie.dmn.feel.util.Generated;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -99,7 +100,7 @@ public class Interval {
         if (input != POS_INF && input != NEG_INF) {
             return input;
         } else {
-            return null;
+            return new UndefinedValueComparable();
         }
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to