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 0805f07bb0 [incubator-kie-issues#83] Refactor InfixOpNode inside DMN
core (#5621)
0805f07bb0 is described below
commit 0805f07bb0f3144c4652421d997a8284a736b210
Author: Gabriele Cardosi <[email protected]>
AuthorDate: Wed Dec 13 14:40:59 2023 +0100
[incubator-kie-issues#83] Refactor InfixOpNode inside DMN core (#5621)
* [incubator-kie-issues#83] WIP - Splitting structur and behaviour. Tests
failing
* [incubator-kie-issues#83] Working status. Same single test failing as in
main
* [incubator-kie-issues#83] Cleanup
* [incubator-kie-issues#83] DivExecutor
* [incubator-kie-issues#83] AddExecutor
* [incubator-kie-issues#83] MultExecutor
* [incubator-kie-issues#83] SubExecutor
* [incubator-kie-issues#83] Fix DMNRuntimeListenerTest
* [incubator-kie-issues#83] Fix as per PR review
* [incubator-kie-issues#83] Remove duplicated code
* [incubator-kie-issues#83] Renaming as per PR review
---------
Co-authored-by: BAMOE CI <[email protected]>
---
.../feel11/CompiledFEELSemanticMappings.java | 51 ++-
.../kie/dmn/feel/codegen/feel11/Expressions.java | 7 +-
.../org/kie/dmn/feel/lang/ast/BetweenNode.java | 51 ++-
.../org/kie/dmn/feel/lang/ast/InfixOpNode.java | 427 ++-------------------
.../org/kie/dmn/feel/lang/ast/InfixOperator.java | 79 ++++
.../feel/lang/ast/infixexecutors/AddExecutor.java | 127 ++++++
.../feel/lang/ast/infixexecutors/AndExecutor.java | 58 +++
.../ast/infixexecutors/ClassIdentifierTuple.java | 56 +++
.../feel/lang/ast/infixexecutors/DivExecutor.java | 102 +++++
.../feel/lang/ast/infixexecutors/EqExecutor.java | 46 +++
.../ast/infixexecutors/EvaluatedParameters.java | 38 ++
.../feel/lang/ast/infixexecutors/GtExecutor.java | 46 +++
.../feel/lang/ast/infixexecutors/GteExecutor.java | 49 +++
.../lang/ast/infixexecutors/InfixExecutor.java | 30 ++
.../ast/infixexecutors/InfixExecutorUtils.java | 165 ++++++++
.../feel/lang/ast/infixexecutors/LtExecutor.java | 46 +++
.../feel/lang/ast/infixexecutors/LteExecutor.java | 50 +++
.../feel/lang/ast/infixexecutors/MultExecutor.java | 91 +++++
.../feel/lang/ast/infixexecutors/NeExecutor.java | 47 +++
.../feel/lang/ast/infixexecutors/OrExecutor.java | 58 +++
.../feel/lang/ast/infixexecutors/PowExecutor.java | 50 +++
.../feel/lang/ast/infixexecutors/SubExecutor.java | 104 +++++
.../org/kie/dmn/feel/lang/ast/InfixOpNodeTest.java | 196 ----------
.../kie/dmn/feel/lang/ast/InfixOperatorTest.java | 127 ++++++
.../infixexecutors/ClassidentifierTupleTest.java | 35 ++
.../ast/infixexecutors/InfixExecutorUtilsTest.java | 101 +++++
.../kie/dmn/feel/parser/feel11/FEELParserTest.java | 66 +---
.../dmn/feel/runtime/FEELNumberCoercionTest.java | 2 +-
.../dmn/validation/dtanalysis/DMNDTAnalyser.java | 2 +-
29 files changed, 1610 insertions(+), 697 deletions(-)
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSemanticMappings.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSemanticMappings.java
index 9768f448f9..78326a136f 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSemanticMappings.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSemanticMappings.java
@@ -18,18 +18,9 @@
*/
package org.kie.dmn.feel.codegen.feel11;
-import java.math.MathContext;
-import java.time.Period;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Supplier;
-
-import ch.obermuhlner.math.big.BigDecimalMath;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.feel.lang.EvaluationContext;
-import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.lang.ast.InfixOperator;
import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
import org.kie.dmn.feel.runtime.Range;
import org.kie.dmn.feel.runtime.UnaryTest;
@@ -39,6 +30,12 @@ import org.kie.dmn.feel.runtime.impl.RangeImpl;
import org.kie.dmn.feel.util.EvalHelper;
import org.kie.dmn.feel.util.Msg;
+import java.time.Period;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Supplier;
+
/**
* The purpose of this class is to offer import .* methods to compiled FEEL
classes compiling expressions.
* Implementing DMN FEEL spec chapter 10.3.2.12 Semantic mappings
@@ -265,12 +262,13 @@ public class CompiledFEELSemanticMappings {
/**
* FEEL spec Table 38
- * Delegates to {@link InfixOpNode} except evaluationcontext
+ * Delegates to {@link InfixOperator} except evaluationcontext
+ *
* @deprecated does not support short-circuit of the operator
*/
@Deprecated
public static Boolean and(Object left, Object right) {
- return (Boolean) InfixOpNode.and(left, right, null);
+ return (Boolean) InfixOperator.AND.evaluate(left, right, null);
}
public static Boolean and(Boolean left, Supplier<Boolean> right) {
@@ -300,14 +298,15 @@ public class CompiledFEELSemanticMappings {
/**
* FEEL spec Table 38
- * Delegates to {@link InfixOpNode} except evaluationcontext
+ * Delegates to {@link InfixOperator} except evaluationcontext
+ *
* @deprecated does not support short-circuit of the operator
*/
@Deprecated
public static Boolean or(Object left, Object right) {
- return (Boolean) InfixOpNode.or(left, right, null);
+ return (Boolean) InfixOperator.OR.evaluate(left, right, null);
}
-
+
public static Boolean or(Boolean left, Supplier<Boolean> right) {
if (left != null) {
if (!left.booleanValue()) {
@@ -335,38 +334,38 @@ public class CompiledFEELSemanticMappings {
/**
* FEEL spec Table 45
- * Delegates to {@link InfixOpNode} except evaluationcontext
+ * Delegates to {@link InfixOperator} except evaluationcontext
*/
public static Object add(final Object left, final Object right, final
EvaluationContext context) {
- return InfixOpNode.add(left, right, context);
+ return InfixOperator.ADD.evaluate(left, right, context);
}
/**
* FEEL spec Table 45
- * Delegates to {@link InfixOpNode} except evaluationcontext
+ * Delegates to {@link InfixOperator} except evaluationcontext
*/
public static Object sub(final Object left, final Object right, final
EvaluationContext context) {
- return InfixOpNode.sub(left, right, context);
+ return InfixOperator.SUB.evaluate(left, right, context);
}
/**
* FEEL spec Table 45
- * Delegates to {@link InfixOpNode} except evaluationcontext
+ * Delegates to {@link InfixOperator} except evaluationcontext
*/
public static Object mult(final Object left, final Object right, final
EvaluationContext context) {
- return InfixOpNode.mult(left, right, context);
+ return InfixOperator.MULT.evaluate(left, right, context);
}
/**
* FEEL spec Table 45
- * Delegates to {@link InfixOpNode} except evaluationcontext
+ * Delegates to {@link InfixOperator} except evaluationcontext
*/
public static Object div(final Object left, final Object right, final
EvaluationContext context) {
- return InfixOpNode.div(left, right, context);
+ return InfixOperator.DIV.evaluate(left, right, context);
}
public static Object pow(final Object left, final Object right, final
EvaluationContext context) {
- return InfixOpNode.math(left, right, context, (l, r) ->
BigDecimalMath.pow(l, r, MathContext.DECIMAL128));
+ return InfixOperator.POW.evaluate(left, right, context);
}
/**
@@ -375,7 +374,7 @@ public class CompiledFEELSemanticMappings {
*/
public static Boolean lte(Object left, Object right) {
return or(lt(left, right),
- eq(left, right)); // do not use Java || to avoid potential
NPE due to FEEL 3vl.
+ eq(left, right)); // do not use Java || to avoid potential NPE
due to FEEL 3vl.
}
/**
@@ -392,7 +391,7 @@ public class CompiledFEELSemanticMappings {
*/
public static Boolean gte(Object left, Object right) {
return or(gt(left, right),
- eq(left, right)); // do not use Java || to avoid potential
NPE due to FEEL 3vl.
+ eq(left, right)); // do not use Java || to avoid potential NPE
due to FEEL 3vl.
}
/**
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Expressions.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Expressions.java
index 80d354626d..b2ae13201f 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Expressions.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Expressions.java
@@ -39,10 +39,7 @@ import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.type.UnknownType;
-import org.kie.dmn.feel.lang.ast.InfixOpNode;
-import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
-import org.kie.dmn.feel.lang.ast.RangeNode;
-import org.kie.dmn.feel.lang.ast.UnaryTestNode;
+import org.kie.dmn.feel.lang.ast.*;
import org.kie.dmn.feel.lang.impl.MapBackedType;
import org.kie.dmn.feel.lang.impl.NamedParameter;
import org.kie.dmn.feel.lang.types.GenFnType;
@@ -110,7 +107,7 @@ public class Expressions {
}
public static MethodCallExpr binary(
- InfixOpNode.InfixOperator operator,
+ InfixOperator operator,
Expression l,
Expression r) {
switch (operator) {
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/BetweenNode.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/BetweenNode.java
index feb773f595..383c107cb8 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/BetweenNode.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/BetweenNode.java
@@ -22,6 +22,7 @@ import org.antlr.v4.runtime.ParserRuleContext;
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.feel.lang.EvaluationContext;
import org.kie.dmn.feel.lang.Type;
+import org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils;
import org.kie.dmn.feel.lang.types.BuiltInType;
import org.kie.dmn.feel.util.EvalHelper;
import org.kie.dmn.feel.util.Msg;
@@ -34,7 +35,7 @@ public class BetweenNode
private BaseNode end;
public BetweenNode(ParserRuleContext ctx, BaseNode value, BaseNode start,
BaseNode end) {
- super( ctx );
+ super(ctx);
this.value = value;
this.start = start;
this.end = end;
@@ -67,34 +68,52 @@ public class BetweenNode
@Override
public Object evaluate(EvaluationContext ctx) {
boolean problem = false;
- if ( value == null ) { ctx.notifyEvt( astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "value")) ); problem = true; }
- if ( start == null ) { ctx.notifyEvt( astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "start")) ); problem = true; }
- if ( end == null ) { ctx.notifyEvt( astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "end")) ); problem = true; }
+ if (value == null) {
+ ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "value")));
+ problem = true;
+ }
+ if (start == null) {
+ ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "start")));
+ problem = true;
+ }
+ if (end == null) {
+ ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "end")));
+ problem = true;
+ }
if (problem) return null;
Object o_val = value.evaluate(ctx);
Object o_s = start.evaluate(ctx);
Object o_e = end.evaluate(ctx);
- if ( o_val == null ) { ctx.notifyEvt( astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "value")) ); problem = true; }
- if ( o_s == null ) { ctx.notifyEvt( astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "start")) ); problem = true; }
- if ( o_e == null ) { ctx.notifyEvt( astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "end")) ); problem = true; }
+ if (o_val == null) {
+ ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "value")));
+ problem = true;
+ }
+ if (o_s == null) {
+ ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "start")));
+ problem = true;
+ }
+ if (o_e == null) {
+ ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.IS_NULL, "end")));
+ problem = true;
+ }
if (problem) return null;
- Object gte = InfixOpNode.or(EvalHelper.compare(o_val, o_s, ctx, (l, r)
-> l.compareTo(r) > 0),
- EvalHelper.isEqual(o_val, o_s, ctx),
- ctx); // do not use Java || to avoid
potential NPE due to FEEL 3vl.
+ Object gte = InfixExecutorUtils.or(EvalHelper.compare(o_val, o_s, ctx,
(l, r) -> l.compareTo(r) > 0),
+ EvalHelper.isEqual(o_val, o_s, ctx),
+ ctx); // do not use Java || to avoid potential NPE due to FEEL
3vl.
if (gte == null) {
ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, "value", "start")));
}
- Object lte = InfixOpNode.or(EvalHelper.compare(o_val, o_e, ctx, (l, r)
-> l.compareTo(r) < 0),
- EvalHelper.isEqual(o_val, o_e, ctx),
- ctx); // do not use Java || to avoid
potential NPE due to FEEL 3vl.
+ Object lte = InfixExecutorUtils.or(EvalHelper.compare(o_val, o_e, ctx,
(l, r) -> l.compareTo(r) < 0),
+ EvalHelper.isEqual(o_val, o_e, ctx),
+ ctx); // do not use Java || to avoid potential NPE due to FEEL
3vl.
if (lte == null) {
ctx.notifyEvt(astEvent(Severity.ERROR,
Msg.createMessage(Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, "value", "end")));
}
-
- return InfixOpNode.and(gte, lte, ctx); // do not use Java && to avoid
potential NPE due to FEEL 3vl.
+
+ return InfixExecutorUtils.and(gte, lte, ctx); // do not use Java && to
avoid potential NPE due to FEEL 3vl.
}
@Override
@@ -104,7 +123,7 @@ public class BetweenNode
@Override
public ASTNode[] getChildrenNode() {
- return new ASTNode[] { value, start, end };
+ return new ASTNode[]{value, start, end};
}
@Override
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOpNode.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOpNode.java
index 5c4cc05df7..6932289271 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOpNode.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOpNode.java
@@ -18,80 +18,22 @@
*/
package org.kie.dmn.feel.lang.ast;
-import java.math.BigDecimal;
-import java.math.MathContext;
-import java.math.RoundingMode;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.chrono.ChronoPeriod;
-import java.time.temporal.ChronoUnit;
-import java.time.temporal.Temporal;
-import java.time.temporal.TemporalAmount;
-import java.util.function.BinaryOperator;
-
-import ch.obermuhlner.math.big.BigDecimalMath;
import org.antlr.v4.runtime.ParserRuleContext;
-import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.feel.lang.EvaluationContext;
import org.kie.dmn.feel.lang.Type;
import org.kie.dmn.feel.lang.types.BuiltInType;
-import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
-import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
-import org.kie.dmn.feel.util.EvalHelper;
-import org.kie.dmn.feel.util.Msg;
public class InfixOpNode
extends BaseNode {
- public static enum InfixOperator {
- ADD( "+" ),
- SUB( "-" ),
- MULT( "*" ),
- DIV( "/" ),
- POW( "**" ),
- LTE( "<=" ),
- LT( "<" ),
- GT( ">" ),
- GTE( ">=" ),
- EQ( "=" ),
- NE( "!=" ),
- AND( "and" ),
- OR( "or" );
-
- public final String symbol;
-
- InfixOperator(String symbol) {
- this.symbol = symbol;
- }
-
- public static InfixOperator determineOperator(String symbol) {
- for ( InfixOperator op : InfixOperator.values() ) {
- if ( op.symbol.equals( symbol ) ) {
- return op;
- }
- }
- throw new IllegalArgumentException( "No operator found for symbol
'" + symbol + "'" );
- }
-
- public boolean isBoolean() {
- return this == LTE || this == LT || this == GT || this == GTE ||
this == EQ || this == NE || this == AND || this == OR;
- }
- }
-
private InfixOperator operator;
- private BaseNode left;
- private BaseNode right;
+ private BaseNode left;
+ private BaseNode right;
public InfixOpNode(ParserRuleContext ctx, BaseNode left, String op,
BaseNode right) {
- super( ctx );
+ super(ctx);
this.left = left;
- this.operator = InfixOperator.determineOperator( op );
+ this.operator = InfixOperator.determineOperator(op);
this.right = right;
}
@@ -126,40 +68,42 @@ public class InfixOpNode
@Override
public Type getResultType() {
// see FEEL spec Table 45.
- if ( operator.isBoolean() ) { return BuiltInType.BOOLEAN; }
- switch ( operator ) {
+ if (operator.isBoolean()) {
+ return BuiltInType.BOOLEAN;
+ }
+ switch (operator) {
case ADD:
case SUB: {
- if ( left.getResultType() == BuiltInType.NUMBER &&
right.getResultType() == BuiltInType.NUMBER ) {
+ if (left.getResultType() == BuiltInType.NUMBER &&
right.getResultType() == BuiltInType.NUMBER) {
return BuiltInType.NUMBER;
- } else if ( left.getResultType() == BuiltInType.DATE_TIME &&
right.getResultType() == BuiltInType.DATE_TIME ) {
+ } else if (left.getResultType() == BuiltInType.DATE_TIME &&
right.getResultType() == BuiltInType.DATE_TIME) {
return BuiltInType.DATE_TIME;
- } else if ( left.getResultType() == BuiltInType.TIME &&
right.getResultType() == BuiltInType.TIME ) {
+ } else if (left.getResultType() == BuiltInType.TIME &&
right.getResultType() == BuiltInType.TIME) {
return BuiltInType.TIME;
- } else if ( left.getResultType() == BuiltInType.DURATION ||
right.getResultType() == BuiltInType.DURATION ) {
- if ( left.getResultType() == BuiltInType.DATE_TIME ||
right.getResultType() == BuiltInType.DATE_TIME ) {
+ } else if (left.getResultType() == BuiltInType.DURATION ||
right.getResultType() == BuiltInType.DURATION) {
+ if (left.getResultType() == BuiltInType.DATE_TIME ||
right.getResultType() == BuiltInType.DATE_TIME) {
return BuiltInType.DATE_TIME;
- } else if ( left.getResultType() == BuiltInType.TIME ||
right.getResultType() == BuiltInType.TIME ) {
+ } else if (left.getResultType() == BuiltInType.TIME ||
right.getResultType() == BuiltInType.TIME) {
return BuiltInType.TIME;
- } else if ( left.getResultType() == BuiltInType.DURATION
&& right.getResultType() == BuiltInType.DURATION ) {
+ } else if (left.getResultType() == BuiltInType.DURATION &&
right.getResultType() == BuiltInType.DURATION) {
return BuiltInType.DURATION;
}
- } else if ( left.getResultType() == BuiltInType.STRING &&
right.getResultType() == BuiltInType.STRING ) {
+ } else if (left.getResultType() == BuiltInType.STRING &&
right.getResultType() == BuiltInType.STRING) {
return BuiltInType.STRING;
}
}
case MULT:
case DIV: {
- if ( left.getResultType() == BuiltInType.NUMBER &&
right.getResultType() == BuiltInType.NUMBER ) {
+ if (left.getResultType() == BuiltInType.NUMBER &&
right.getResultType() == BuiltInType.NUMBER) {
return BuiltInType.NUMBER;
- } else if ( left.getResultType() == BuiltInType.DURATION ||
right.getResultType() == BuiltInType.DURATION ) {
- if ( left.getResultType() == BuiltInType.NUMBER ||
right.getResultType() == BuiltInType.NUMBER ) {
+ } else if (left.getResultType() == BuiltInType.DURATION ||
right.getResultType() == BuiltInType.DURATION) {
+ if (left.getResultType() == BuiltInType.NUMBER ||
right.getResultType() == BuiltInType.NUMBER) {
return BuiltInType.NUMBER;
}
}
}
case POW: {
- if ( left.getResultType() == BuiltInType.NUMBER &&
right.getResultType() == BuiltInType.NUMBER ) {
+ if (left.getResultType() == BuiltInType.NUMBER &&
right.getResultType() == BuiltInType.NUMBER) {
return BuiltInType.NUMBER;
}
}
@@ -171,267 +115,12 @@ public class InfixOpNode
@Override
public Object evaluate(EvaluationContext ctx) {
if (this.left == null) return null;
- switch ( operator ) {
- case ADD:
- return add(this.left.evaluate(ctx), this.right.evaluate(ctx),
ctx);
- case SUB:
- return sub(this.left.evaluate(ctx), this.right.evaluate(ctx),
ctx);
- case MULT:
- return mult(this.left.evaluate(ctx), this.right.evaluate(ctx),
ctx);
- case DIV:
- return div(this.left.evaluate(ctx), this.right.evaluate(ctx),
ctx);
- case POW:
- return math(this.left.evaluate(ctx), this.right.evaluate(ctx),
ctx, (l, r) -> BigDecimalMath.pow(l, r, MathContext.DECIMAL128));
- case AND:
- Boolean leftAND =
EvalHelper.getBooleanOrNull(this.left.evaluate(ctx));
- if (leftAND != null) {
- if (leftAND.booleanValue()) {
- return
EvalHelper.getBooleanOrNull(this.right.evaluate(ctx));
- } else {
- return Boolean.FALSE; //left hand operand is false, we
do not need to evaluate right side
- }
- } else {
- Boolean rightAND =
EvalHelper.getBooleanOrNull(this.right.evaluate(ctx));
- return Boolean.FALSE.equals(rightAND) ? Boolean.FALSE :
null;
- }
- case OR:
- Boolean leftOR =
EvalHelper.getBooleanOrNull(this.left.evaluate(ctx));
- if (leftOR != null) {
- if (!leftOR.booleanValue()) {
- return
EvalHelper.getBooleanOrNull(this.right.evaluate(ctx));
- } else {
- return Boolean.TRUE; //left hand operand is true, we
do not need to evaluate right side
- }
- } else {
- Boolean rightOR =
EvalHelper.getBooleanOrNull(this.right.evaluate(ctx));
- return Boolean.TRUE.equals(rightOR) ? Boolean.TRUE : null;
- }
- case LTE:
- Object leftLTE = this.left.evaluate(ctx);
- Object rightLTE = this.right.evaluate(ctx);
- return or(EvalHelper.compare(leftLTE, rightLTE, ctx, (l, r) ->
l.compareTo(r) < 0),
- EvalHelper.isEqual(leftLTE, rightLTE, ctx),
- ctx); // do not use Java || to avoid potential NPE
due to FEEL 3vl.
- case LT:
- return EvalHelper.compare(this.left.evaluate(ctx),
this.right.evaluate(ctx), ctx, (l, r) -> l.compareTo(r) < 0);
- case GT:
- return EvalHelper.compare(this.left.evaluate(ctx),
this.right.evaluate(ctx), ctx, (l, r) -> l.compareTo(r) > 0);
- case GTE:
- Object leftGTE = this.left.evaluate(ctx);
- Object rightGTE = this.right.evaluate(ctx);
- return or(EvalHelper.compare(leftGTE, rightGTE, ctx, (l, r) ->
l.compareTo(r) > 0),
- EvalHelper.isEqual(leftGTE, rightGTE, ctx),
- ctx); // do not use Java || to avoid potential NPE
due to FEEL 3vl.
- case EQ:
- return EvalHelper.isEqual(this.left.evaluate(ctx),
this.right.evaluate(ctx), ctx);
- case NE:
- Boolean result = EvalHelper.isEqual(this.left.evaluate(ctx),
this.right.evaluate(ctx), ctx);
- return result != null ? !result : null;
- default:
- return null;
- }
- }
-
- public static Object add(Object left, Object right, EvaluationContext ctx)
{
- if ( left == null || right == null ) {
- return null;
- } else if ( left instanceof String && right instanceof String ) {
- return left + ((String) right);
- } else if (left instanceof ChronoPeriod && right instanceof
ChronoPeriod) {
- return new ComparablePeriod(((ChronoPeriod)
left).plus((ChronoPeriod) right));
- } else if ( left instanceof Duration && right instanceof Duration ) {
- return ((Duration) left).plus( (Duration) right);
- } else if (left instanceof ZonedDateTime && right instanceof
ChronoPeriod) {
- return ((ZonedDateTime) left).plus((ChronoPeriod) right);
- } else if (left instanceof OffsetDateTime && right instanceof
ChronoPeriod) {
- return ((OffsetDateTime) left).plus((ChronoPeriod) right);
- } else if (left instanceof LocalDateTime && right instanceof
ChronoPeriod) {
- return ((LocalDateTime) left).plus((ChronoPeriod) right);
- } else if (left instanceof LocalDate && right instanceof ChronoPeriod)
{
- return ((LocalDate) left).plus((ChronoPeriod) right);
- } else if ( left instanceof ZonedDateTime && right instanceof Duration
) {
- return ((ZonedDateTime) left).plus( (Duration) right);
- } else if ( left instanceof OffsetDateTime && right instanceof
Duration ) {
- return ((OffsetDateTime) left).plus( (Duration) right);
- } else if ( left instanceof LocalDateTime && right instanceof Duration
) {
- return ((LocalDateTime) left).plus( (Duration) right);
- } else if ( left instanceof LocalDate && right instanceof Duration ) {
- return addLocalDateAndDuration((LocalDate) left, (Duration) right);
- } else if (left instanceof ChronoPeriod && right instanceof
ZonedDateTime) {
- return ((ZonedDateTime) right).plus((ChronoPeriod) left);
- } else if (left instanceof ChronoPeriod && right instanceof
OffsetDateTime) {
- return ((OffsetDateTime) right).plus((ChronoPeriod) left);
- } else if (left instanceof ChronoPeriod && right instanceof
LocalDateTime) {
- return ((LocalDateTime) right).plus((ChronoPeriod) left);
- } else if (left instanceof ChronoPeriod && right instanceof LocalDate)
{
- return ((LocalDate) right).plus((ChronoPeriod) left);
- } else if ( left instanceof Duration && right instanceof ZonedDateTime
) {
- return ((ZonedDateTime) right).plus( (Duration) left);
- } else if ( left instanceof Duration && right instanceof
OffsetDateTime ) {
- return ((OffsetDateTime) right).plus( (Duration) left);
- } else if ( left instanceof Duration && right instanceof LocalDateTime
) {
- return ((LocalDateTime) right).plus( (Duration) left);
- } else if ( left instanceof Duration && right instanceof LocalDate ) {
- return addLocalDateAndDuration((LocalDate) right, (Duration) left);
- } else if ( left instanceof LocalTime && right instanceof Duration ) {
- return ((LocalTime) left).plus( (Duration) right);
- } else if ( left instanceof Duration && right instanceof LocalTime ) {
- return ((LocalTime) right).plus( (Duration) left);
- } else if ( left instanceof OffsetTime && right instanceof Duration ) {
- return ((OffsetTime) left).plus( (Duration) right);
- } else if ( left instanceof Duration && right instanceof OffsetTime ) {
- return ((OffsetTime) right).plus( (Duration) left);
- } else if ( left instanceof Temporal && right instanceof Temporal ) {
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.OPERATION_IS_UNDEFINED_FOR_PARAMETERS.getMask()));
- return null;
- } else {
- return math( left, right, ctx, (l, r) -> l.add( r,
MathContext.DECIMAL128 ) );
- }
- }
-
- public static Object sub(Object left, Object right, EvaluationContext ctx)
{
- if ( left == null || right == null ) {
- return null;
- } else if ( left instanceof Temporal && right instanceof Temporal ) {
- return subtractTemporals((Temporal) left, (Temporal) right, ctx);
- } else if (left instanceof ChronoPeriod && right instanceof
ChronoPeriod) {
- return new ComparablePeriod(((ChronoPeriod)
left).minus((ChronoPeriod) right));
- } else if ( left instanceof Duration && right instanceof Duration ) {
- return ((Duration) left).minus( (Duration) right);
- } else if (left instanceof ZonedDateTime && right instanceof
ChronoPeriod) {
- return ((ZonedDateTime) left).minus((ChronoPeriod) right);
- } else if (left instanceof OffsetDateTime && right instanceof
ChronoPeriod) {
- return ((OffsetDateTime) left).minus((ChronoPeriod) right);
- } else if (left instanceof LocalDateTime && right instanceof
ChronoPeriod) {
- return ((LocalDateTime) left).minus((ChronoPeriod) right);
- } else if (left instanceof LocalDate && right instanceof ChronoPeriod)
{
- return ((LocalDate) left).minus((ChronoPeriod) right);
- } else if ( left instanceof ZonedDateTime && right instanceof Duration
) {
- return ((ZonedDateTime) left).minus( (Duration) right);
- } else if ( left instanceof OffsetDateTime && right instanceof
Duration ) {
- return ((OffsetDateTime) left).minus( (Duration) right);
- } else if ( left instanceof LocalDateTime && right instanceof Duration
) {
- return ((LocalDateTime) left).minus( (Duration) right);
- } else if ( left instanceof LocalDate && right instanceof Duration ) {
- LocalDateTime leftLDT = LocalDateTime.of((LocalDate) left,
LocalTime.MIDNIGHT);
- LocalDateTime evaluated = leftLDT.minus((Duration) right);
- return LocalDate.of(evaluated.getYear(), evaluated.getMonth(),
evaluated.getDayOfMonth());
- } else if ( left instanceof LocalTime && right instanceof Duration ) {
- return ((LocalTime) left).minus( (Duration) right);
- } else if ( left instanceof OffsetTime && right instanceof Duration ) {
- return ((OffsetTime) left).minus( (Duration) right);
- } else {
- return math( left, right, ctx, (l, r) -> l.subtract( r,
MathContext.DECIMAL128 ) );
- }
- }
-
- public static Object mult(Object left, Object right, EvaluationContext
ctx) {
- if ( left == null || right == null ) {
- return null;
- } else if (!isAllowedMultiplicationBasedOnSpec(left, right, ctx)) {
- return null;
- } else if ( left instanceof Duration && right instanceof Number ) {
- final BigDecimal durationNumericValue =
BigDecimal.valueOf(((Duration) left).toNanos());
- final BigDecimal rightDecimal = BigDecimal.valueOf(((Number)
right).doubleValue());
- return
Duration.ofNanos(durationNumericValue.multiply(rightDecimal).longValue());
- } else if ( left instanceof Number && right instanceof Duration ) {
- return Duration.ofSeconds( EvalHelper.getBigDecimalOrNull( left
).multiply( EvalHelper.getBigDecimalOrNull( ((Duration)right).getSeconds() ),
MathContext.DECIMAL128 ).longValue() );
- } else if (left instanceof ChronoPeriod && right instanceof Number) {
- return
ComparablePeriod.ofMonths(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
left)).multiply(EvalHelper.getBigDecimalOrNull(right),
MathContext.DECIMAL128).intValue());
- } else if (left instanceof Number && right instanceof ChronoPeriod) {
- return
ComparablePeriod.ofMonths(EvalHelper.getBigDecimalOrNull(left).multiply(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
right)), MathContext.DECIMAL128).intValue());
- } else if (left instanceof ChronoPeriod && right instanceof
ChronoPeriod) {
- return
EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
left)).multiply(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
right)), MathContext.DECIMAL128);
- } else {
- return math( left, right, ctx, (l, r) -> l.multiply( r,
MathContext.DECIMAL128 ) );
- }
- }
-
- public static Object div(Object left, Object right, EvaluationContext ctx)
{
- if ( left == null || right == null ) {
- return null;
- } else if ( left instanceof Duration && right instanceof Number ) {
- final BigDecimal durationNumericValue =
BigDecimal.valueOf(((Duration) left).toNanos());
- final BigDecimal rightDecimal = BigDecimal.valueOf(((Number)
right).doubleValue());
- return Duration.ofNanos(durationNumericValue.divide(rightDecimal,
0, RoundingMode.HALF_EVEN).longValue());
- } else if ( left instanceof Number && right instanceof TemporalAmount)
{
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.OPERATION_IS_UNDEFINED_FOR_PARAMETERS.getMask()));
- return null;
- } else if ( left instanceof Duration && right instanceof Duration ) {
- return EvalHelper.getBigDecimalOrNull( ((Duration)
left).getSeconds() ).divide( EvalHelper.getBigDecimalOrNull(
((Duration)right).getSeconds() ), MathContext.DECIMAL128 );
- } else if (left instanceof ChronoPeriod && right instanceof Number) {
- final BigDecimal rightDecimal =
EvalHelper.getBigDecimalOrNull(right);
- if (rightDecimal.compareTo(BigDecimal.ZERO) == 0) {
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.DIVISION_BY_ZERO.getMask()));
- return null;
- } else {
- return
ComparablePeriod.ofMonths(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
left)).divide(rightDecimal, MathContext.DECIMAL128).intValue());
- }
- } else if (left instanceof ChronoPeriod && right instanceof
ChronoPeriod) {
- return
EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
left)).divide(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
right)), MathContext.DECIMAL128);
- } else {
- return math( left, right, ctx, (l, r) -> l.divide( r,
MathContext.DECIMAL128 ) );
- }
- }
-
- public static Object math(Object left, Object right, EvaluationContext
ctx, BinaryOperator<BigDecimal> op) {
- BigDecimal l = left instanceof String ? null :
EvalHelper.getBigDecimalOrNull( left );
- BigDecimal r = right instanceof String ? null :
EvalHelper.getBigDecimalOrNull( right );
- if ( l == null || r == null ) {
- return null;
- }
- try {
- return op.apply( l, r );
- } catch ( ArithmeticException e ) {
- // happens in cases like division by 0
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.GENERAL_ARITHMETIC_EXCEPTION, e.getMessage())));
- return null;
- }
- }
-
- /**
- * Implements the ternary logic AND operation
- * @deprecated this variant do not allow short-circuit of the operator
- */
- @Deprecated
- public static Object and(Object left, Object right, EvaluationContext ctx)
{
- Boolean l = EvalHelper.getBooleanOrNull( left );
- Boolean r = EvalHelper.getBooleanOrNull( right );
- // have to check for all nulls first to avoid NPE
- if ( (l == null && r == null) || (l == null && r == true) || (r ==
null && l == true) ) {
- return null;
- } else if ( l == null || r == null ) {
- return false;
- }
- return l && r;
- }
-
- /**
- * Implements the ternary logic OR operation
- * @deprecated this variant do not allow short-circuit of the operator
- */
- @Deprecated
- public static Object or(Object left, Object right, EvaluationContext ctx) {
- Boolean l = EvalHelper.getBooleanOrNull( left );
- Boolean r = EvalHelper.getBooleanOrNull( right );
- // have to check for all nulls first to avoid NPE
- if ( (l == null && r == null) || (l == null && r == false) || (r ==
null && l == false) ) {
- return null;
- } else if ( l == null || r == null ) {
- return true;
- }
- return l || r;
- }
-
- private static LocalDate addLocalDateAndDuration(LocalDate left, Duration
right) {
- LocalDateTime leftLDT = LocalDateTime.of( left, LocalTime.MIDNIGHT);
- LocalDateTime evaluated = leftLDT.plus(right);
- return LocalDate.of(evaluated.getYear(), evaluated.getMonth(),
evaluated.getDayOfMonth());
+ return operator.evaluate(this, ctx);
}
@Override
public ASTNode[] getChildrenNode() {
- return new ASTNode[] { left, right };
+ return new ASTNode[]{left, right};
}
@Override
@@ -439,76 +128,4 @@ public class InfixOpNode
return v.visit(this);
}
- private static Object subtractTemporals(final Temporal left, final
Temporal right, final EvaluationContext ctx) {
- // Based on the Table 57 in the spec, if it is only date, convert to
date and time.
- final Temporal leftTemporal = getTemporalForSubtraction(left);
- final Temporal rightTemporal = getTemporalForSubtraction(right);
-
- if (isAllowedTemporalSubtractionBasedOnSpec(leftTemporal,
rightTemporal, ctx)) {
- return Duration.between(rightTemporal, leftTemporal);
- } else {
- return null;
- }
- }
-
- private static Temporal getTemporalForSubtraction(final Temporal temporal)
{
- if (temporal instanceof LocalDate) {
- return ZonedDateTime.of((LocalDate) temporal, LocalTime.MIDNIGHT,
ZoneOffset.UTC);
- } else {
- return temporal;
- }
- }
-
- /**
- * Checks if the multiplication is supported by the DMN specification
based on the objects specified as parameters.
- *
- * @param left Left parameter of the subtraction expression.
- * @param right Right parameter of the subtraction expression.
- * @param ctx Context that is used to notify about not allowed set of
parameters.
- * @return True, if the parameters are valid for multiplication based on
the DMN specification.
- * False, when multiplication is not defined for the specified set
of parameters in the DMN spec, or is forbidden: <br>
- * - Multiplication of two durations e is not allowed in the
specification.
- */
- static boolean isAllowedMultiplicationBasedOnSpec(final Object left, final
Object right, final EvaluationContext ctx) {
- if (left instanceof TemporalAmount && right instanceof TemporalAmount)
{
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.INVALID_PARAMETERS_FOR_OPERATION, "multiplication",
-
left.getClass().getName(),
-
right.getClass().getName())));
- return false;
- }
- return true;
- }
-
- /**
- * Checks if the subtraction is supported by the DMN specification based
on the temporals specified as parameters.
- *
- * @param leftTemporal Left temporal parameter of the subtraction
expression.
- * @param rightTemporal Right temporal parameter of the subtraction
expression.
- * @param ctx Context that is used to notify about not allowed set of
parameters.
- * @return True, if the temporal parameters are valid for subtraction
based on the DMN specification.
- * False, when subtraction is not defined for the specified set of
parameters in the DMN spec, or is forbidden: <br>
- * - Subtraction of a datetime with timezone and a datetime
without a timezone is not defined in the specification.
- * - Subtraction of a time and a datetime is not defined in the
specification.
- */
- private static boolean isAllowedTemporalSubtractionBasedOnSpec(final
Temporal leftTemporal, final Temporal rightTemporal, final EvaluationContext
ctx) {
- // Both datetimes have a timezone or both timezones don't have it.
Cannot combine timezoned datetime and datetime without a timezone.
- if ((leftTemporal instanceof ZonedDateTime || leftTemporal instanceof
OffsetDateTime)
- && (rightTemporal instanceof LocalDateTime)) {
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.DATE_AND_TIME_TIMEZONE_NEEDED, "first", leftTemporal,
"second", rightTemporal)));
- return false;
- } else if ((rightTemporal instanceof ZonedDateTime || rightTemporal
instanceof OffsetDateTime)
- && (leftTemporal instanceof LocalDateTime)) {
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.DATE_AND_TIME_TIMEZONE_NEEDED, "second", rightTemporal,
"first", leftTemporal)));
- return false;
- }
-
- // Cannot combine time and date (or datetime) based on the DMN
specification.
- if ((!leftTemporal.isSupported(ChronoUnit.DAYS) &&
rightTemporal.isSupported(ChronoUnit.DAYS))
- || (!rightTemporal.isSupported(ChronoUnit.DAYS) &&
leftTemporal.isSupported(ChronoUnit.DAYS))) {
- ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.OPERATION_IS_UNDEFINED_FOR_PARAMETERS.getMask()));
- return false;
- }
-
- return true;
- }
}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOperator.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOperator.java
new file mode 100644
index 0000000000..b881f1925f
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InfixOperator.java
@@ -0,0 +1,79 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.infixexecutors.*;
+
+/**
+ * Enum responsible to execute Infix operations.
+ * Each entry provide
+ * 1. the symbol of the operator
+ * 2. the actual <code>InfixExecutor</code> instance to be executed
+ */
+public enum InfixOperator {
+ ADD("+", AddExecutor.instance()),
+ SUB("-", SubExecutor.instance()),
+ MULT("*", MultExecutor.instance()),
+ DIV("/", DivExecutor.instance()),
+ POW("**", PowExecutor.instance()),
+ LTE("<=", LteExecutor.instance()),
+ LT("<", LtExecutor.instance()),
+ GT(">", GtExecutor.instance()),
+ GTE(">=", GteExecutor.instance()),
+ EQ("=", EqExecutor.instance()),
+ NE("!=", NeExecutor.instance()),
+ AND("and", AndExecutor.instance()),
+ OR("or", OrExecutor.instance());
+
+ public final String symbol;
+ private final InfixExecutor infixExecutor;
+
+ InfixOperator(String symbol,
+ InfixExecutor infixExecutor) {
+ this.symbol = symbol;
+ this.infixExecutor = infixExecutor;
+ }
+
+ public static InfixOperator determineOperator(String symbol) {
+ for (InfixOperator op : InfixOperator.values()) {
+ if (op.symbol.equals(symbol)) {
+ return op;
+ }
+ }
+ throw new IllegalArgumentException("No operator found for symbol '" +
symbol + "'");
+ }
+
+ public boolean isBoolean() {
+ return this == LTE || this == LT || this == GT || this == GTE || this
== EQ || this == NE || this == AND || this == OR;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+
+ public Object evaluate(final Object left, final Object right,
EvaluationContext ctx) {
+ return infixExecutor.evaluate(left, right, ctx);
+ }
+
+ public Object evaluate(InfixOpNode opNode, EvaluationContext ctx) {
+ return infixExecutor.evaluate(opNode, ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/AddExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/AddExecutor.java
new file mode 100644
index 0000000000..3af4d454fa
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/AddExecutor.java
@@ -0,0 +1,127 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.api.feel.runtime.events.FEELEvent;
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
+import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.Msg;
+
+import java.math.MathContext;
+import java.time.*;
+import java.time.chrono.ChronoPeriod;
+import java.time.temporal.Temporal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import static
org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.addLocalDateAndDuration;
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math;
+
+public class AddExecutor implements InfixExecutor {
+
+ private static final AddExecutor INSTANCE = new AddExecutor();
+ private final Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> addFunctionsByClassesTuple;
+
+ private AddExecutor() {
+ addFunctionsByClassesTuple = getAddFunctionsByClassesTuple();
+ }
+
+ public static AddExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return evaluate(new EvaluatedParameters(left, right), ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+ private Object evaluate(EvaluatedParameters params, EvaluationContext ctx)
{
+ if (params.getLeft() == null || params.getRight() == null) {
+ return null;
+ }
+ ClassIdentifierTuple identifierTuple = new
ClassIdentifierTuple(params.getLeft(), params.getRight());
+ if (addFunctionsByClassesTuple.containsKey(identifierTuple)) {
+ return
addFunctionsByClassesTuple.get(identifierTuple).apply(params, ctx);
+ } else {
+ return math(params.getLeft(), params.getRight(), ctx, (l, r) ->
l.add(r, MathContext.DECIMAL128));
+ }
+ }
+
+ private Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> getAddFunctionsByClassesTuple() {
+ Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> toReturn = new HashMap<>();
+ toReturn.put(new ClassIdentifierTuple(String.class, String.class),
(parameters, ctx) -> parameters.getLeft() + (String) parameters.getRight());
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
ChronoPeriod.class), (parameters, ctx) ->
+ new ComparablePeriod(((ChronoPeriod)
parameters.getLeft()).plus((ChronoPeriod) parameters.getRight())));
+ toReturn.put(new ClassIdentifierTuple(Duration.class, Duration.class),
(parameters, ctx) ->
+ ((Duration) parameters.getLeft()).plus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(ZonedDateTime.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((ZonedDateTime) parameters.getLeft()).plus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(OffsetDateTime.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((OffsetDateTime) parameters.getLeft()).plus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDateTime.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((LocalDateTime) parameters.getLeft()).plus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDate.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((LocalDate) parameters.getLeft()).plus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(ZonedDateTime.class,
Duration.class), (parameters, ctx) ->
+ ((ZonedDateTime) parameters.getLeft()).plus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(OffsetDateTime.class,
Duration.class), (parameters, ctx) ->
+ ((OffsetDateTime) parameters.getLeft()).plus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDateTime.class,
Duration.class), (parameters, ctx) ->
+ ((LocalDateTime) parameters.getLeft()).plus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDate.class,
Duration.class), (parameters, ctx) ->
+ addLocalDateAndDuration((LocalDate) parameters.getLeft(),
(Duration) parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
ZonedDateTime.class), (parameters, ctx) ->
+ ((ZonedDateTime) parameters.getRight()).plus((ChronoPeriod)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
OffsetDateTime.class), (parameters, ctx) ->
+ ((OffsetDateTime) parameters.getRight()).plus((ChronoPeriod)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
LocalDateTime.class), (parameters, ctx) ->
+ ((LocalDateTime) parameters.getRight()).plus((ChronoPeriod)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
LocalDate.class), (parameters, ctx) ->
+ ((LocalDate) parameters.getRight()).plus((ChronoPeriod)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(Duration.class,
ZonedDateTime.class), (parameters, ctx) ->
+ ((ZonedDateTime) parameters.getRight()).plus((Duration)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(Duration.class,
OffsetDateTime.class), (parameters, ctx) ->
+ ((OffsetDateTime) parameters.getRight()).plus((Duration)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(Duration.class,
LocalDateTime.class), (parameters, ctx) ->
+ ((LocalDateTime) parameters.getRight()).plus((Duration)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(Duration.class,
LocalDate.class), (parameters, ctx) ->
+ addLocalDateAndDuration((LocalDate) parameters.getRight(),
(Duration) parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(LocalTime.class,
Duration.class), (parameters, ctx) ->
+ ((LocalTime) parameters.getLeft()).plus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(Duration.class,
LocalTime.class), (parameters, ctx) ->
+ ((LocalTime) parameters.getRight()).plus((Duration)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(OffsetTime.class,
Duration.class), (parameters, ctx) ->
+ ((OffsetTime) parameters.getLeft()).plus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(Duration.class,
OffsetTime.class), (parameters, ctx) ->
+ ((OffsetTime) parameters.getRight()).plus((Duration)
parameters.getLeft()));
+ toReturn.put(new ClassIdentifierTuple(Temporal.class, Temporal.class),
(parameters, ctx) -> {
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.OPERATION_IS_UNDEFINED_FOR_PARAMETERS.getMask()));
+ return null;
+ });
+ return toReturn;
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/AndExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/AndExecutor.java
new file mode 100644
index 0000000000..766c74ba65
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/AndExecutor.java
@@ -0,0 +1,58 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.and;
+
+public class AndExecutor implements InfixExecutor {
+
+ private static final AndExecutor INSTANCE = new AndExecutor();
+
+ private AndExecutor() {
+ }
+
+ public static AndExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return and(left, right, ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ Boolean leftAND =
EvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx));
+ if (leftAND != null) {
+ if (leftAND.booleanValue()) {
+ return
EvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx));
+ } else {
+ return Boolean.FALSE; //left hand operand is false, we do not
need to evaluate right side
+ }
+ } else {
+ Boolean rightAND =
EvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx));
+ return Boolean.FALSE.equals(rightAND) ? Boolean.FALSE : null;
+ }
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/ClassIdentifierTuple.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/ClassIdentifierTuple.java
new file mode 100644
index 0000000000..bbecdbccfb
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/ClassIdentifierTuple.java
@@ -0,0 +1,56 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import java.util.Objects;
+
+public class ClassIdentifierTuple {
+
+ private final Class<?> LEFT_TYPE;
+ private final Class<?> RIGHT_TYPE;
+
+
+ public ClassIdentifierTuple(Object leftObject, Object rightObject) {
+ this.LEFT_TYPE = leftObject != null ? leftObject.getClass() : null;
+ this.RIGHT_TYPE = rightObject != null ? rightObject.getClass() : null;
+ }
+
+ public ClassIdentifierTuple(Class<?> leftType, Class<?> rightType) {
+ this.LEFT_TYPE = leftType;
+ this.RIGHT_TYPE = rightType;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ClassIdentifierTuple that = (ClassIdentifierTuple) o;
+ return isEquals(LEFT_TYPE, that.LEFT_TYPE) && isEquals(RIGHT_TYPE,
that.RIGHT_TYPE);
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ static boolean isEquals(Class<?> thisClass, Class<?> thatClass) {
+ return (thisClass != null && thatClass != null) &&
+ (Objects.equals(thisClass, thatClass) ||
thatClass.isAssignableFrom(thisClass));
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/DivExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/DivExecutor.java
new file mode 100644
index 0000000000..9a2bb13479
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/DivExecutor.java
@@ -0,0 +1,102 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.api.feel.runtime.events.FEELEvent;
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
+import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.EvalHelper;
+import org.kie.dmn.feel.util.Msg;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.time.Duration;
+import java.time.chrono.ChronoPeriod;
+import java.time.temporal.TemporalAmount;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math;
+
+public class DivExecutor implements InfixExecutor {
+
+ private static final DivExecutor INSTANCE = new DivExecutor();
+ private final Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> sumFunctionsByClassesTuple;
+
+ private DivExecutor() {
+ sumFunctionsByClassesTuple = getSumFunctionsByClassesTuple();
+ }
+
+ public static DivExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return evaluate(new EvaluatedParameters(left, right), ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+ private Object evaluate(EvaluatedParameters params, EvaluationContext ctx)
{
+ if (params.getLeft() == null || params.getRight() == null) {
+ return null;
+ }
+ ClassIdentifierTuple identifierTuple = new
ClassIdentifierTuple(params.getLeft(), params.getRight());
+ if (sumFunctionsByClassesTuple.containsKey(identifierTuple)) {
+ return
sumFunctionsByClassesTuple.get(identifierTuple).apply(params, ctx);
+ } else {
+ return math(params.getLeft(), params.getRight(), ctx, (l, r) ->
l.divide(r, MathContext.DECIMAL128));
+ }
+ }
+
+ private Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> getSumFunctionsByClassesTuple() {
+ Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> toReturn = new HashMap<>();
+ toReturn.put(new ClassIdentifierTuple(Duration.class, Number.class),
(parameters, ctx) -> {
+ final BigDecimal durationNumericValue =
BigDecimal.valueOf(((Duration) parameters.getLeft()).toNanos());
+ final BigDecimal rightDecimal = BigDecimal.valueOf(((Number)
parameters.getRight()).doubleValue());
+ return Duration.ofNanos(durationNumericValue.divide(rightDecimal,
0, RoundingMode.HALF_EVEN).longValue());
+ });
+ toReturn.put(new ClassIdentifierTuple(Number.class,
TemporalAmount.class), (parameters, ctx) -> {
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.OPERATION_IS_UNDEFINED_FOR_PARAMETERS.getMask()));
+ return null;
+ });
+ toReturn.put(new ClassIdentifierTuple(Duration.class, Duration.class),
(parameters, ctx) ->
+ EvalHelper.getBigDecimalOrNull(((Duration)
parameters.getLeft()).getSeconds()).divide(EvalHelper.getBigDecimalOrNull(((Duration)
parameters.getRight()).getSeconds()), MathContext.DECIMAL128));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
Number.class), (parameters, ctx) -> {
+ final BigDecimal rightDecimal =
EvalHelper.getBigDecimalOrNull(parameters.getRight());
+ if (rightDecimal.compareTo(BigDecimal.ZERO) == 0) {
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.DIVISION_BY_ZERO.getMask()));
+ return null;
+ } else {
+ return
ComparablePeriod.ofMonths(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getLeft())).divide(rightDecimal,
MathContext.DECIMAL128).intValue());
+ }
+ });
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
ChronoPeriod.class), (parameters, ctx) ->
+
EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getLeft())).divide(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getRight())), MathContext.DECIMAL128));
+ return toReturn;
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/EqExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/EqExecutor.java
new file mode 100644
index 0000000000..144d12019f
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/EqExecutor.java
@@ -0,0 +1,46 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+public class EqExecutor implements InfixExecutor {
+
+ private static final EqExecutor INSTANCE = new EqExecutor();
+
+ private EqExecutor() {
+ }
+
+ public static EqExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return EvalHelper.isEqual(left, right, ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/EvaluatedParameters.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/EvaluatedParameters.java
new file mode 100644
index 0000000000..a4f14dfd4b
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/EvaluatedParameters.java
@@ -0,0 +1,38 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+public class EvaluatedParameters {
+
+ private final Object left;
+ private final Object right;
+
+ public EvaluatedParameters(Object leftObject, Object rightObject) {
+ this.left = leftObject;
+ this.right = rightObject;
+ }
+
+ public Object getLeft() {
+ return left;
+ }
+
+ public Object getRight() {
+ return right;
+ }
+ }
\ No newline at end of file
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/GtExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/GtExecutor.java
new file mode 100644
index 0000000000..86a289ce5b
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/GtExecutor.java
@@ -0,0 +1,46 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+public class GtExecutor implements InfixExecutor {
+
+ private static final GtExecutor INSTANCE = new GtExecutor();
+
+ private GtExecutor() {
+ }
+
+ public static GtExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return EvalHelper.compare(left, right, ctx, (l, r) -> l.compareTo(r) >
0);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/GteExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/GteExecutor.java
new file mode 100644
index 0000000000..9a50dd40c2
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/GteExecutor.java
@@ -0,0 +1,49 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or;
+
+public class GteExecutor implements InfixExecutor {
+
+ private static final GteExecutor INSTANCE = new GteExecutor();
+
+ private GteExecutor() {
+ }
+
+ public static GteExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return or(EvalHelper.compare(left, right, ctx, (l, r) ->
l.compareTo(r) > 0),
+ EvalHelper.isEqual(left, right, ctx),
+ ctx); // do not use Java || to avoid potential NPE due to FEEL
3vl.
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutor.java
new file mode 100644
index 0000000000..3a594555c8
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutor.java
@@ -0,0 +1,30 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+
+public interface InfixExecutor {
+
+ Object evaluate(final Object left, final Object right, EvaluationContext
ctx);
+
+ Object evaluate(InfixOpNode infixNode, EvaluationContext ctx);
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
new file mode 100644
index 0000000000..2ebd96768e
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
@@ -0,0 +1,165 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.api.feel.runtime.events.FEELEvent;
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.EvalHelper;
+import org.kie.dmn.feel.util.Msg;
+
+import java.math.BigDecimal;
+import java.time.*;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAmount;
+import java.util.function.BinaryOperator;
+
+public class InfixExecutorUtils {
+
+ /**
+ * Implements the ternary logic OR operation
+ *
+ * @deprecated this variant do not allow short-circuit of the operator
+ */
+ @Deprecated
+ public static Object or(Object left, Object right, EvaluationContext ctx) {
+ Boolean l = EvalHelper.getBooleanOrNull(left);
+ Boolean r = EvalHelper.getBooleanOrNull(right);
+ // have to check for all nulls first to avoid NPE
+ if ((l == null && r == null) || (l == null && r == false) || (r ==
null && l == false)) {
+ return null;
+ } else if (l == null || r == null) {
+ return true;
+ }
+ return l || r;
+ }
+
+ /**
+ * Implements the ternary logic AND operation
+ *
+ * @deprecated this variant do not allow short-circuit of the operator
+ */
+ @Deprecated
+ public static Object and(Object left, Object right, EvaluationContext ctx)
{
+ Boolean l = EvalHelper.getBooleanOrNull(left);
+ Boolean r = EvalHelper.getBooleanOrNull(right);
+ // have to check for all nulls first to avoid NPE
+ if ((l == null && r == null) || (l == null && r == true) || (r == null
&& l == true)) {
+ return null;
+ } else if (l == null || r == null) {
+ return false;
+ }
+ return l && r;
+ }
+
+ static Object math(Object left, Object right, EvaluationContext ctx,
BinaryOperator<BigDecimal> op) {
+ BigDecimal l = left instanceof String ? null :
EvalHelper.getBigDecimalOrNull(left);
+ BigDecimal r = right instanceof String ? null :
EvalHelper.getBigDecimalOrNull(right);
+ if (l == null || r == null) {
+ return null;
+ }
+ try {
+ return op.apply(l, r);
+ } catch (ArithmeticException e) {
+ // happens in cases like division by 0
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.GENERAL_ARITHMETIC_EXCEPTION, e.getMessage())));
+ return null;
+ }
+ }
+
+ static LocalDate addLocalDateAndDuration(LocalDate left, Duration right) {
+ LocalDateTime leftLDT = LocalDateTime.of(left, LocalTime.MIDNIGHT);
+ LocalDateTime evaluated = leftLDT.plus(right);
+ return LocalDate.of(evaluated.getYear(), evaluated.getMonth(),
evaluated.getDayOfMonth());
+ }
+
+ static Object subtractTemporals(final Temporal left, final Temporal right,
final EvaluationContext ctx) {
+ // Based on the Table 57 in the spec, if it is only date, convert to
date and time.
+ final Temporal leftTemporal = getTemporalForSubtraction(left);
+ final Temporal rightTemporal = getTemporalForSubtraction(right);
+
+ if (isAllowedTemporalSubtractionBasedOnSpec(leftTemporal,
rightTemporal, ctx)) {
+ return Duration.between(rightTemporal, leftTemporal);
+ } else {
+ return null;
+ }
+ }
+
+ static Temporal getTemporalForSubtraction(final Temporal temporal) {
+ if (temporal instanceof LocalDate) {
+ return ZonedDateTime.of((LocalDate) temporal, LocalTime.MIDNIGHT,
ZoneOffset.UTC);
+ } else {
+ return temporal;
+ }
+ }
+
+ /**
+ * Checks if the multiplication is supported by the DMN specification
based on the objects specified as parameters.
+ *
+ * @param left Left parameter of the subtraction expression.
+ * @param right Right parameter of the subtraction expression.
+ * @param ctx Context that is used to notify about not allowed set of
parameters.
+ * @return True, if the parameters are valid for multiplication based on
the DMN specification.
+ * False, when multiplication is not defined for the specified set of
parameters in the DMN spec, or is forbidden: <br>
+ * - Multiplication of two durations e is not allowed in the specification.
+ */
+ static boolean isAllowedMultiplicationBasedOnSpec(final Object left, final
Object right, final EvaluationContext ctx) {
+ if (left instanceof TemporalAmount && right instanceof TemporalAmount)
{
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.INVALID_PARAMETERS_FOR_OPERATION, "multiplication",
+ left.getClass().getName(),
+ right.getClass().getName())));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the subtraction is supported by the DMN specification based
on the temporals specified as parameters.
+ *
+ * @param leftTemporal Left temporal parameter of the subtraction
expression.
+ * @param rightTemporal Right temporal parameter of the subtraction
expression.
+ * @param ctx Context that is used to notify about not allowed
set of parameters.
+ * @return True, if the temporal parameters are valid for subtraction
based on the DMN specification.
+ * False, when subtraction is not defined for the specified set of
parameters in the DMN spec, or is forbidden: <br>
+ * - Subtraction of a datetime with timezone and a datetime without a
timezone is not defined in the specification.
+ * - Subtraction of a time and a datetime is not defined in the
specification.
+ */
+ static boolean isAllowedTemporalSubtractionBasedOnSpec(final Temporal
leftTemporal, final Temporal rightTemporal, final EvaluationContext ctx) {
+ // Both datetimes have a timezone or both timezones don't have it.
Cannot combine timezoned datetime and datetime without a timezone.
+ if ((leftTemporal instanceof ZonedDateTime || leftTemporal instanceof
OffsetDateTime)
+ && (rightTemporal instanceof LocalDateTime)) {
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.DATE_AND_TIME_TIMEZONE_NEEDED, "first", leftTemporal,
"second", rightTemporal)));
+ return false;
+ } else if ((rightTemporal instanceof ZonedDateTime || rightTemporal
instanceof OffsetDateTime)
+ && (leftTemporal instanceof LocalDateTime)) {
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.createMessage(Msg.DATE_AND_TIME_TIMEZONE_NEEDED, "second", rightTemporal,
"first", leftTemporal)));
+ return false;
+ }
+
+ // Cannot combine time and date (or datetime) based on the DMN
specification.
+ if ((!leftTemporal.isSupported(ChronoUnit.DAYS) &&
rightTemporal.isSupported(ChronoUnit.DAYS))
+ || (!rightTemporal.isSupported(ChronoUnit.DAYS) &&
leftTemporal.isSupported(ChronoUnit.DAYS))) {
+ ctx.notifyEvt(() -> new
InvalidParametersEvent(FEELEvent.Severity.ERROR,
Msg.OPERATION_IS_UNDEFINED_FOR_PARAMETERS.getMask()));
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LtExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LtExecutor.java
new file mode 100644
index 0000000000..0db56818b9
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LtExecutor.java
@@ -0,0 +1,46 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+public class LtExecutor implements InfixExecutor {
+
+ private static final LtExecutor INSTANCE = new LtExecutor();
+
+ private LtExecutor() {
+ }
+
+ public static LtExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return EvalHelper.compare(left, right, ctx, (l, r) -> l.compareTo(r) <
0);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LteExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LteExecutor.java
new file mode 100644
index 0000000000..d4f9d90886
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LteExecutor.java
@@ -0,0 +1,50 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or;
+
+public class LteExecutor implements InfixExecutor {
+
+ private static final LteExecutor INSTANCE = new LteExecutor();
+
+ private LteExecutor() {
+ }
+
+ public static LteExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return or(EvalHelper.compare(left, right, ctx, (l, r) ->
l.compareTo(r) < 0),
+ EvalHelper.isEqual(left, right, ctx),
+ ctx); // do not use Java || to avoid potential NPE due to FEEL
3vl.
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/MultExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/MultExecutor.java
new file mode 100644
index 0000000000..3b435ce50b
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/MultExecutor.java
@@ -0,0 +1,91 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
+import org.kie.dmn.feel.util.EvalHelper;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.time.*;
+import java.time.chrono.ChronoPeriod;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import static
org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.isAllowedMultiplicationBasedOnSpec;
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math;
+
+public class MultExecutor implements InfixExecutor {
+
+ private static final MultExecutor INSTANCE = new MultExecutor();
+ private final Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> multFunctionsByClassesTuple;
+
+ private MultExecutor() {
+ multFunctionsByClassesTuple = getMultFunctionsByClassesTuple();
+ }
+
+ public static MultExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return evaluate(new EvaluatedParameters(left, right), ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+ private Object evaluate(EvaluatedParameters params, EvaluationContext ctx)
{
+ if ( params.getLeft() == null || params.getRight() == null ) {
+ return null;
+ } else if (!isAllowedMultiplicationBasedOnSpec(params.getLeft(),
params.getRight(), ctx)) {
+ return null;
+ }
+ ClassIdentifierTuple identifierTuple = new
ClassIdentifierTuple(params.getLeft(), params.getRight());
+ if (multFunctionsByClassesTuple.containsKey(identifierTuple)) {
+ return
multFunctionsByClassesTuple.get(identifierTuple).apply(params, ctx);
+ } else {
+ return math( params.getLeft(), params.getRight(), ctx, (l, r) ->
l.multiply( r, MathContext.DECIMAL128 ) );
+ }
+ }
+
+ private Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> getMultFunctionsByClassesTuple() {
+ Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> toReturn = new HashMap<>();
+ toReturn.put(new ClassIdentifierTuple(Duration.class, Number.class),
(parameters, ctx) -> {
+ final BigDecimal durationNumericValue =
BigDecimal.valueOf(((Duration) parameters.getLeft()).toNanos());
+ final BigDecimal rightDecimal = BigDecimal.valueOf(((Number)
parameters.getRight()).doubleValue());
+ return
Duration.ofNanos(durationNumericValue.multiply(rightDecimal).longValue());
+ });
+ toReturn.put(new ClassIdentifierTuple(Number.class, Duration.class),
(parameters, ctx) ->
+
Duration.ofSeconds(EvalHelper.getBigDecimalOrNull(parameters.getLeft()).multiply(EvalHelper.getBigDecimalOrNull(((Duration)
parameters.getRight()).getSeconds()), MathContext.DECIMAL128).longValue()));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
Number.class), (parameters, ctx) ->
+
ComparablePeriod.ofMonths(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getLeft())).multiply(EvalHelper.getBigDecimalOrNull(parameters.getRight()),
MathContext.DECIMAL128).intValue()));
+ toReturn.put(new ClassIdentifierTuple(Number.class,
ChronoPeriod.class), (parameters, ctx) ->
+
ComparablePeriod.ofMonths(EvalHelper.getBigDecimalOrNull(parameters.getLeft()).multiply(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getRight())), MathContext.DECIMAL128).intValue()));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
ChronoPeriod.class), (parameters, ctx) ->
+
EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getLeft())).multiply(EvalHelper.getBigDecimalOrNull(ComparablePeriod.toTotalMonths((ChronoPeriod)
parameters.getRight())), MathContext.DECIMAL128));
+ return toReturn;
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/NeExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/NeExecutor.java
new file mode 100644
index 0000000000..4e285dae10
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/NeExecutor.java
@@ -0,0 +1,47 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+public class NeExecutor implements InfixExecutor {
+
+ private static final NeExecutor INSTANCE = new NeExecutor();
+
+ private NeExecutor() {
+ }
+
+ public static NeExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ Boolean result = EvalHelper.isEqual(left, right, ctx);
+ return result != null ? !result : null;
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/OrExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/OrExecutor.java
new file mode 100644
index 0000000000..8c079bd9c9
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/OrExecutor.java
@@ -0,0 +1,58 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.util.EvalHelper;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or;
+
+public class OrExecutor implements InfixExecutor {
+
+ private static final OrExecutor INSTANCE = new OrExecutor();
+
+ private OrExecutor() {
+ }
+
+ public static OrExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return or(left, right, ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ Boolean leftOR =
EvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx));
+ if (leftOR != null) {
+ if (!leftOR.booleanValue()) {
+ return
EvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx));
+ } else {
+ return Boolean.TRUE; //left hand operand is true, we do not
need to evaluate right side
+ }
+ } else {
+ Boolean rightOR =
EvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx));
+ return Boolean.TRUE.equals(rightOR) ? Boolean.TRUE : null;
+ }
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/PowExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/PowExecutor.java
new file mode 100644
index 0000000000..8f0e09cb0c
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/PowExecutor.java
@@ -0,0 +1,50 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import ch.obermuhlner.math.big.BigDecimalMath;
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+
+import java.math.MathContext;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math;
+
+public class PowExecutor implements InfixExecutor {
+
+ private static final PowExecutor INSTANCE = new PowExecutor();
+
+ private PowExecutor() {
+ }
+
+ public static PowExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return math(left, right, ctx, (l, r) -> BigDecimalMath.pow(l, r,
MathContext.DECIMAL128));
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/SubExecutor.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/SubExecutor.java
new file mode 100644
index 0000000000..2516a3c0db
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/SubExecutor.java
@@ -0,0 +1,104 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.lang.ast.InfixOpNode;
+import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
+
+import java.math.MathContext;
+import java.time.*;
+import java.time.chrono.ChronoPeriod;
+import java.time.temporal.Temporal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math;
+import static
org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.subtractTemporals;
+
+public class SubExecutor implements InfixExecutor {
+
+ private static final SubExecutor INSTANCE = new SubExecutor();
+ private final Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> subFunctionsByClassesTuple;
+
+ private SubExecutor() {
+ subFunctionsByClassesTuple = getSubFunctionsByClassesTuple();
+ }
+
+ public static SubExecutor instance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public Object evaluate(Object left, Object right, EvaluationContext ctx) {
+ return evaluate(new EvaluatedParameters(left, right), ctx);
+ }
+
+ @Override
+ public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) {
+ return evaluate(infixNode.getLeft().evaluate(ctx),
infixNode.getRight().evaluate(ctx), ctx);
+ }
+
+ private Object evaluate(EvaluatedParameters params, EvaluationContext ctx)
{
+ if (params.getLeft() == null || params.getRight() == null) {
+ return null;
+ }
+ ClassIdentifierTuple identifierTuple = new
ClassIdentifierTuple(params.getLeft(), params.getRight());
+ if (subFunctionsByClassesTuple.containsKey(identifierTuple)) {
+ return
subFunctionsByClassesTuple.get(identifierTuple).apply(params, ctx);
+ } else {
+ return math(params.getLeft(), params.getRight(), ctx, (l, r) ->
l.subtract(r, MathContext.DECIMAL128));
+ }
+ }
+
+ private Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> getSubFunctionsByClassesTuple() {
+ Map<ClassIdentifierTuple, BiFunction<EvaluatedParameters,
EvaluationContext, Object>> toReturn = new HashMap<>();
+ toReturn.put(new ClassIdentifierTuple(Temporal.class, Temporal.class),
(parameters, ctx) ->
+ subtractTemporals((Temporal) parameters.getLeft(), (Temporal)
parameters.getRight(), ctx));
+ toReturn.put(new ClassIdentifierTuple(ChronoPeriod.class,
ChronoPeriod.class), (parameters, ctx) ->
+ new ComparablePeriod(((ChronoPeriod)
parameters.getLeft()).minus((ChronoPeriod) parameters.getRight())));
+ toReturn.put(new ClassIdentifierTuple(Duration.class, Duration.class),
(parameters, ctx) ->
+ ((Duration) parameters.getLeft()).minus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(ZonedDateTime.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((ZonedDateTime) parameters.getLeft()).minus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(OffsetDateTime.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((OffsetDateTime) parameters.getLeft()).minus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDateTime.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((LocalDateTime) parameters.getLeft()).minus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDate.class,
ChronoPeriod.class), (parameters, ctx) ->
+ ((LocalDate) parameters.getLeft()).minus((ChronoPeriod)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(ZonedDateTime.class,
Duration.class), (parameters, ctx) ->
+ ((ZonedDateTime) parameters.getLeft()).minus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(OffsetDateTime.class,
Duration.class), (parameters, ctx) ->
+ ((OffsetDateTime) parameters.getLeft()).minus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDateTime.class,
Duration.class), (parameters, ctx) ->
+ ((LocalDateTime) parameters.getLeft()).minus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(LocalDate.class,
Duration.class), (parameters, ctx) -> {
+ LocalDateTime leftLDT = LocalDateTime.of((LocalDate)
parameters.getLeft(), LocalTime.MIDNIGHT);
+ LocalDateTime evaluated = leftLDT.minus((Duration)
parameters.getRight());
+ return LocalDate.of(evaluated.getYear(), evaluated.getMonth(),
evaluated.getDayOfMonth());
+ });
+ toReturn.put(new ClassIdentifierTuple(LocalTime.class,
Duration.class), (parameters, ctx) ->
+ ((LocalTime) parameters.getLeft()).minus((Duration)
parameters.getRight()));
+ toReturn.put(new ClassIdentifierTuple(OffsetTime.class,
Duration.class), (parameters, ctx) ->
+ ((OffsetTime) parameters.getLeft()).minus((Duration)
parameters.getRight()));
+ return toReturn;
+ }
+}
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/InfixOpNodeTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/InfixOpNodeTest.java
deleted file mode 100644
index 0d38ae29bc..0000000000
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/InfixOpNodeTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/**
- * 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
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.kie.dmn.feel.lang.ast;
-
-import java.math.BigDecimal;
-import java.math.MathContext;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.function.BinaryOperator;
-import java.util.function.Supplier;
-
-import ch.obermuhlner.math.big.BigDecimalMath;
-import org.junit.Before;
-import org.junit.Test;
-import org.kie.dmn.feel.lang.EvaluationContext;
-
-import static java.time.temporal.ChronoUnit.DAYS;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-public class InfixOpNodeTest {
-
- private static List<BinaryOperator<BigDecimal>> MATH_OPERATORS;
-
- @Before
- public void setUp() throws Exception {
- MATH_OPERATORS = new ArrayList<>();
- MATH_OPERATORS.add((l, r) -> l.add(r, MathContext.DECIMAL128));
- MATH_OPERATORS.add((l, r) -> l.subtract(r, MathContext.DECIMAL128));
- MATH_OPERATORS.add((l, r) -> l.multiply(r, MathContext.DECIMAL128));
- MATH_OPERATORS.add((l, r) -> l.divide(r, MathContext.DECIMAL128));
- MATH_OPERATORS.add((l, r) -> BigDecimalMath.pow(l, r,
MathContext.DECIMAL128));
- }
-
- @Test
- public void math_BothNumbers() {
- final Random rnd = new Random();
- MATH_OPERATORS.forEach(operator -> {
- BigDecimal left = BigDecimal.valueOf(rnd.nextDouble());
- BigDecimal right = BigDecimal.valueOf(rnd.nextDouble());
- BigDecimal expected = operator.apply(left, right);
- Object retrieved = InfixOpNode.math(left, right, null, operator);
- assertThat(retrieved).isNotNull()
- .isInstanceOf(BigDecimal.class)
- .isEqualTo(expected);
- });
- }
-
- @Test
- public void math_NumberAndString() {
- final Random rnd = new Random();
- MATH_OPERATORS.forEach(operator -> {
- BigDecimal left = BigDecimal.valueOf(rnd.nextDouble());
- String right = String.valueOf(rnd.nextDouble());
- Object retrieved = InfixOpNode.math(left, right, null, operator);
- assertThat(retrieved).isNull();
- });
- }
-
- @Test
- public void addLocalDateAndDuration() {
- LocalDate left = LocalDate.of(2021, 1, 1);
- Duration right = Duration.of(-1, ChronoUnit.HOURS);
- LocalDate retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
- right = Duration.of(-24, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
- right = Duration.of(-25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 30));
- right = Duration.of(1, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
-
- left = LocalDate.of(2021, 1, 2);
- right = Duration.of(1, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 2));
- right = Duration.of(24, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 3));
- right = Duration.of(25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 3));
-
- left = LocalDate.of(2021, 1, 3);
- right = Duration.of(25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 4));
-
- left = LocalDate.of(2020, 12, 30);
- right = Duration.of(-25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 28));
-
- left = LocalDate.of(2020, 12, 31);
- right = Duration.of(-1, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.add(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 30));
- }
-
- @Test
- public void subLocalDateAndDuration() {
- LocalDate left = LocalDate.of(2021, 1, 1);
- Duration right = Duration.of(-1, ChronoUnit.HOURS);
- LocalDate retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
- right = Duration.of(-24, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 2));
- right = Duration.of(-25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 2));
- right = Duration.of(1, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
-
- left = LocalDate.of(2021, 1, 2);
- right = Duration.of(1, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
- right = Duration.of(24, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
- right = Duration.of(25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
-
- left = LocalDate.of(2021, 1, 3);
- right = Duration.of(25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
-
- left = LocalDate.of(2020, 12, 30);
- right = Duration.of(-25, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
-
- left = LocalDate.of(2020, 12, 31);
- right = Duration.of(-1, ChronoUnit.HOURS);
- retrieved = (LocalDate) InfixOpNode.sub(left, right, null);
- assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
- }
- @Test
- public void mulDurationAndDuration() {
- Object left = Duration.of(5, DAYS);
- Object right = Duration.of(5, DAYS);
- assertThat(InfixOpNode.mult(left, right,
mock(EvaluationContext.class))).isNull();
- }
-
-
- @Test
- public void isAllowedMultiplicationBasedOnSpec() {
- EvaluationContext evaluationContext = mock(EvaluationContext.class);
- Object left = 23;
- Object right = 354.5;
- assertThat(InfixOpNode.isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isTrue();
- verify(evaluationContext, never()).notifyEvt(any());
- right = Duration.of(5, DAYS);
- assertThat(InfixOpNode.isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isTrue();
- verify(evaluationContext, never()).notifyEvt(any());
- left = Duration.of(5, DAYS);
- right = 354.5;
- assertThat(InfixOpNode.isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isTrue();
- verify(evaluationContext, never()).notifyEvt(any());
- left = Duration.of(5, DAYS);
- right = Duration.of(5, DAYS);
- assertThat(InfixOpNode.isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isFalse();
- verify(evaluationContext, times(1)).notifyEvt(any(Supplier.class));
- }
-}
\ No newline at end of file
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/InfixOperatorTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/InfixOperatorTest.java
new file mode 100644
index 0000000000..080ff45e44
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/InfixOperatorTest.java
@@ -0,0 +1,127 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast;
+
+import org.junit.Test;
+import org.kie.dmn.feel.lang.EvaluationContext;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class InfixOperatorTest {
+
+ @Test
+ public void addLocalDateAndDuration() {
+ LocalDate left = LocalDate.of(2021, 1, 1);
+ Duration right = Duration.of(-1, ChronoUnit.HOURS);
+ LocalDate retrieved = (LocalDate) InfixOperator.ADD.evaluate(left,
right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
+ right = Duration.of(-24, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
+ right = Duration.of(-25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 30));
+ right = Duration.of(1, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
+
+ left = LocalDate.of(2021, 1, 2);
+ right = Duration.of(1, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 2));
+ right = Duration.of(24, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 3));
+ right = Duration.of(25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 3));
+
+ left = LocalDate.of(2021, 1, 3);
+ right = Duration.of(25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 4));
+
+ left = LocalDate.of(2020, 12, 30);
+ right = Duration.of(-25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 28));
+
+ left = LocalDate.of(2020, 12, 31);
+ right = Duration.of(-1, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.ADD.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 30));
+ }
+
+ @Test
+ public void subLocalDateAndDuration() {
+ LocalDate left = LocalDate.of(2021, 1, 1);
+ Duration right = Duration.of(-1, ChronoUnit.HOURS);
+ LocalDate retrieved = (LocalDate) InfixOperator.SUB.evaluate(left,
right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
+ right = Duration.of(-24, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 2));
+ right = Duration.of(-25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 2));
+ right = Duration.of(1, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
+
+ left = LocalDate.of(2021, 1, 2);
+ right = Duration.of(1, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
+ right = Duration.of(24, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
+ right = Duration.of(25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
+
+ left = LocalDate.of(2021, 1, 3);
+ right = Duration.of(25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2021, 1, 1));
+
+ left = LocalDate.of(2020, 12, 30);
+ right = Duration.of(-25, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
+
+ left = LocalDate.of(2020, 12, 31);
+ right = Duration.of(-1, ChronoUnit.HOURS);
+ retrieved = (LocalDate) InfixOperator.SUB.evaluate(left, right, null);
+ assertThat(retrieved).isEqualTo(LocalDate.of(2020, 12, 31));
+ }
+
+ @Test
+ public void mulDurationAndDuration() {
+ Object left = Duration.of(5, DAYS);
+ Object right = Duration.of(5, DAYS);
+ assertThat(InfixOperator.MULT.evaluate(left, right,
mock(EvaluationContext.class))).isNull();
+ }
+
+}
\ No newline at end of file
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/infixexecutors/ClassidentifierTupleTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/infixexecutors/ClassidentifierTupleTest.java
new file mode 100644
index 0000000000..70ecd6b7d2
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/infixexecutors/ClassidentifierTupleTest.java
@@ -0,0 +1,35 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import org.junit.Test;
+import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
+
+import java.time.chrono.ChronoPeriod;
+
+import static org.junit.Assert.assertTrue;
+
+
+public class ClassidentifierTupleTest {
+
+ @Test
+ public void testClassidentifierTuple_isEquals() {
+ assertTrue(ClassIdentifierTuple.isEquals(ComparablePeriod.class,
ChronoPeriod.class));
+ }
+}
\ No newline at end of file
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtilsTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtilsTest.java
new file mode 100644
index 0000000000..cce73e0cd5
--- /dev/null
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtilsTest.java
@@ -0,0 +1,101 @@
+/**
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.dmn.feel.lang.ast.infixexecutors;
+
+import ch.obermuhlner.math.big.BigDecimalMath;
+import org.junit.Before;
+import org.junit.Test;
+import org.kie.dmn.feel.lang.EvaluationContext;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.function.BinaryOperator;
+import java.util.function.Supplier;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static
org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.isAllowedMultiplicationBasedOnSpec;
+import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+public class InfixExecutorUtilsTest {
+
+ private static List<BinaryOperator<BigDecimal>> MATH_OPERATORS;
+
+ @Before
+ public void setUp() throws Exception {
+ MATH_OPERATORS = new ArrayList<>();
+ MATH_OPERATORS.add((l, r) -> l.add(r, MathContext.DECIMAL128));
+ MATH_OPERATORS.add((l, r) -> l.subtract(r, MathContext.DECIMAL128));
+ MATH_OPERATORS.add((l, r) -> l.multiply(r, MathContext.DECIMAL128));
+ MATH_OPERATORS.add((l, r) -> l.divide(r, MathContext.DECIMAL128));
+ MATH_OPERATORS.add((l, r) -> BigDecimalMath.pow(l, r,
MathContext.DECIMAL128));
+ }
+
+ @Test
+ public void math_BothNumbers() {
+ final Random rnd = new Random();
+ MATH_OPERATORS.forEach(operator -> {
+ BigDecimal left = BigDecimal.valueOf(rnd.nextDouble());
+ BigDecimal right = BigDecimal.valueOf(rnd.nextDouble());
+ BigDecimal expected = operator.apply(left, right);
+ Object retrieved = math(left, right, null, operator);
+ assertThat(retrieved).isNotNull()
+ .isInstanceOf(BigDecimal.class)
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ public void math_NumberAndString() {
+ final Random rnd = new Random();
+ MATH_OPERATORS.forEach(operator -> {
+ BigDecimal left = BigDecimal.valueOf(rnd.nextDouble());
+ String right = String.valueOf(rnd.nextDouble());
+ Object retrieved = math(left, right, null, operator);
+ assertThat(retrieved).isNull();
+ });
+ }
+
+ @Test
+ public void isAllowedMultiplicationBasedOnSpecTest() {
+ EvaluationContext evaluationContext = mock(EvaluationContext.class);
+ Object left = 23;
+ Object right = 354.5;
+ assertThat(isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isTrue();
+ verify(evaluationContext, never()).notifyEvt(any());
+ right = Duration.of(5, DAYS);
+ assertThat(isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isTrue();
+ verify(evaluationContext, never()).notifyEvt(any());
+ left = Duration.of(5, DAYS);
+ right = 354.5;
+ assertThat(isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isTrue();
+ verify(evaluationContext, never()).notifyEvt(any());
+ left = Duration.of(5, DAYS);
+ right = Duration.of(5, DAYS);
+ assertThat(isAllowedMultiplicationBasedOnSpec(left, right,
evaluationContext)).isFalse();
+ verify(evaluationContext, times(1)).notifyEvt(any(Supplier.class));
+ }
+
+}
\ No newline at end of file
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserTest.java
index 1b65990a72..5206b3d440 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/parser/feel11/FEELParserTest.java
@@ -26,35 +26,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
import org.junit.Ignore;
import org.junit.Test;
import org.kie.dmn.feel.lang.Type;
-import org.kie.dmn.feel.lang.ast.ASTNode;
-import org.kie.dmn.feel.lang.ast.AtLiteralNode;
-import org.kie.dmn.feel.lang.ast.BaseNode;
-import org.kie.dmn.feel.lang.ast.BetweenNode;
-import org.kie.dmn.feel.lang.ast.BooleanNode;
-import org.kie.dmn.feel.lang.ast.ContextEntryNode;
-import org.kie.dmn.feel.lang.ast.ContextNode;
-import org.kie.dmn.feel.lang.ast.FilterExpressionNode;
-import org.kie.dmn.feel.lang.ast.ForExpressionNode;
-import org.kie.dmn.feel.lang.ast.FunctionDefNode;
-import org.kie.dmn.feel.lang.ast.FunctionInvocationNode;
-import org.kie.dmn.feel.lang.ast.IfExpressionNode;
-import org.kie.dmn.feel.lang.ast.InNode;
-import org.kie.dmn.feel.lang.ast.InfixOpNode;
-import org.kie.dmn.feel.lang.ast.InstanceOfNode;
-import org.kie.dmn.feel.lang.ast.IterationContextNode;
-import org.kie.dmn.feel.lang.ast.ListNode;
-import org.kie.dmn.feel.lang.ast.NameDefNode;
-import org.kie.dmn.feel.lang.ast.NameRefNode;
-import org.kie.dmn.feel.lang.ast.NamedParameterNode;
-import org.kie.dmn.feel.lang.ast.NullNode;
-import org.kie.dmn.feel.lang.ast.NumberNode;
-import org.kie.dmn.feel.lang.ast.PathExpressionNode;
-import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
-import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
-import org.kie.dmn.feel.lang.ast.RangeNode;
-import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
-import org.kie.dmn.feel.lang.ast.StringNode;
-import org.kie.dmn.feel.lang.ast.TypeNode;
+import org.kie.dmn.feel.lang.ast.*;
import org.kie.dmn.feel.lang.impl.MapBackedType;
import org.kie.dmn.feel.lang.types.BuiltInType;
import org.kie.dmn.feel.util.Msg;
@@ -294,7 +266,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(NumberNode.class);
assertThat( mult.getLeft().getText()).isEqualTo("10");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(NameRefNode.class);
assertThat( mult.getRight().getText()).isEqualTo("x");
@@ -317,12 +289,12 @@ public class FEELParserTest {
assertThat( div.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( div.getLeft().getText()).isEqualTo("y");
- assertThat(
div.getOperator()).isEqualTo(InfixOpNode.InfixOperator.DIV);
+ assertThat( div.getOperator()).isEqualTo(InfixOperator.DIV);
assertThat( div.getRight()).isInstanceOf(NumberNode.class);
assertThat( div.getRight().getText()).isEqualTo("5");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(NameRefNode.class);
assertThat( mult.getRight().getText()).isEqualTo("x");
@@ -341,7 +313,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( mult.getLeft().getText()).isEqualTo("y");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(InfixOpNode.class);
assertThat( mult.getRight().getText()).isEqualTo( "5 ** 3");
@@ -350,7 +322,7 @@ public class FEELParserTest {
assertThat( exp.getLeft()).isInstanceOf(NumberNode.class);
assertThat( exp.getLeft().getText()).isEqualTo("5");
- assertThat(
exp.getOperator()).isEqualTo(InfixOpNode.InfixOperator.POW);
+ assertThat( exp.getOperator()).isEqualTo(InfixOperator.POW);
assertThat( exp.getRight()).isInstanceOf(NumberNode.class);
assertThat( exp.getRight().getText()).isEqualTo("3");
@@ -369,7 +341,7 @@ public class FEELParserTest {
assertThat( exp.getLeft()).isInstanceOf(InfixOpNode.class);
assertThat( exp.getLeft().getText()).isEqualTo( "y * 5");
- assertThat(
exp.getOperator()).isEqualTo(InfixOpNode.InfixOperator.POW);
+ assertThat( exp.getOperator()).isEqualTo(InfixOperator.POW);
assertThat( exp.getRight()).isInstanceOf(NumberNode.class);
assertThat( exp.getRight().getText()).isEqualTo("3");
@@ -378,7 +350,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( mult.getLeft().getText()).isEqualTo("y");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(NumberNode.class);
assertThat( mult.getRight().getText()).isEqualTo("5");
@@ -397,7 +369,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(InfixOpNode.class);
assertThat( mult.getLeft().getText()).isEqualTo( "y ** 5");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(NumberNode.class);
assertThat( mult.getRight().getText()).isEqualTo("3");
@@ -406,7 +378,7 @@ public class FEELParserTest {
assertThat( exp.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( exp.getLeft().getText()).isEqualTo("y");
- assertThat(
exp.getOperator()).isEqualTo(InfixOpNode.InfixOperator.POW);
+ assertThat( exp.getOperator()).isEqualTo(InfixOperator.POW);
assertThat( exp.getRight()).isInstanceOf(NumberNode.class);
assertThat( exp.getRight().getText()).isEqualTo("5");
@@ -425,7 +397,7 @@ public class FEELParserTest {
assertThat( exp.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( exp.getLeft().getText()).isEqualTo("y");
- assertThat(
exp.getOperator()).isEqualTo(InfixOpNode.InfixOperator.POW);
+ assertThat( exp.getOperator()).isEqualTo(InfixOperator.POW);
assertThat( exp.getRight()).isInstanceOf(InfixOpNode.class);
assertThat( exp.getRight().getText()).isEqualTo( "5 * 3");
@@ -434,7 +406,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(NumberNode.class);
assertThat( mult.getLeft().getText()).isEqualTo("5");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(NumberNode.class);
assertThat( mult.getRight().getText()).isEqualTo("3");
@@ -453,7 +425,7 @@ public class FEELParserTest {
assertThat( add.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( add.getLeft().getText()).isEqualTo("y");
- assertThat(
add.getOperator()).isEqualTo(InfixOpNode.InfixOperator.ADD);
+ assertThat( add.getOperator()).isEqualTo(InfixOperator.ADD);
assertThat( add.getRight()).isInstanceOf(InfixOpNode.class);
assertThat( add.getRight().getText()).isEqualTo( "5 * 3");
@@ -462,7 +434,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(NumberNode.class);
assertThat( mult.getLeft().getText()).isEqualTo("5");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.MULT);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.MULT);
assertThat( mult.getRight()).isInstanceOf(NumberNode.class);
assertThat( mult.getRight().getText()).isEqualTo("3");
@@ -481,7 +453,7 @@ public class FEELParserTest {
assertThat( sub.getLeft()).isInstanceOf(InfixOpNode.class);
assertThat( sub.getLeft().getText()).isEqualTo( "y - 5");
- assertThat(
sub.getOperator()).isEqualTo(InfixOpNode.InfixOperator.POW);
+ assertThat( sub.getOperator()).isEqualTo(InfixOperator.POW);
assertThat( sub.getRight()).isInstanceOf(NumberNode.class);
assertThat( sub.getRight().getText()).isEqualTo("3");
@@ -490,7 +462,7 @@ public class FEELParserTest {
assertThat( mult.getLeft()).isInstanceOf(NameRefNode.class);
assertThat( mult.getLeft().getText()).isEqualTo("y");
- assertThat(
mult.getOperator()).isEqualTo(InfixOpNode.InfixOperator.SUB);
+ assertThat( mult.getOperator()).isEqualTo(InfixOperator.SUB);
assertThat( mult.getRight()).isInstanceOf(NumberNode.class);
assertThat( mult.getRight().getText()).isEqualTo("5");
@@ -655,7 +627,7 @@ public class FEELParserTest {
assertThat( or.getLeft()).isInstanceOf(InfixOpNode.class);
assertThat( or.getLeft().getText()).isEqualTo( "foo < 10 and bar =
\"x\"");
- assertThat( or.getOperator()).isEqualTo(InfixOpNode.InfixOperator.OR);
+ assertThat( or.getOperator()).isEqualTo(InfixOperator.OR);
assertThat( or.getRight()).isInstanceOf(NameRefNode.class);
assertThat( or.getRight().getText()).isEqualTo("baz");
@@ -664,7 +636,7 @@ public class FEELParserTest {
assertThat( and.getLeft()).isInstanceOf(InfixOpNode.class);
assertThat( and.getLeft().getText()).isEqualTo( "foo < 10");
- assertThat(
and.getOperator()).isEqualTo(InfixOpNode.InfixOperator.AND);
+ assertThat( and.getOperator()).isEqualTo(InfixOperator.AND);
assertThat( and.getRight()).isInstanceOf(InfixOpNode.class);
assertThat( and.getRight().getText()).isEqualTo( "bar = \"x\"");
@@ -1052,7 +1024,7 @@ public class FEELParserTest {
assertThat( andExpr.getResultType()).isEqualTo(BuiltInType.BOOLEAN);
InfixOpNode and = (InfixOpNode) andExpr;
- assertThat(
and.getOperator()).isEqualTo(InfixOpNode.InfixOperator.AND);
+ assertThat( and.getOperator()).isEqualTo(InfixOperator.AND);
assertThat( and.getLeft()).isInstanceOf(InstanceOfNode.class);
assertThat( and.getRight()).isInstanceOf(InstanceOfNode.class);
assertThat( and.getLeft().getText()).isEqualTo( "\"foo\" instance of
string");
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELNumberCoercionTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELNumberCoercionTest.java
index 6647149ac0..38ac0869c6 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELNumberCoercionTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELNumberCoercionTest.java
@@ -25,7 +25,7 @@ import java.util.Map;
import org.junit.Test;
import org.kie.dmn.feel.FEEL;
-import org.kie.dmn.feel.lang.ast.InfixOpNode.InfixOperator;
+import org.kie.dmn.feel.lang.ast.InfixOperator;
import static org.assertj.core.api.Assertions.assertThat;
import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull;
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 7394fd6781..37521c58ae 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
@@ -47,7 +47,7 @@ import org.kie.dmn.feel.lang.SimpleType;
import org.kie.dmn.feel.lang.ast.BaseNode;
import org.kie.dmn.feel.lang.ast.DashNode;
import org.kie.dmn.feel.lang.ast.InfixOpNode;
-import org.kie.dmn.feel.lang.ast.InfixOpNode.InfixOperator;
+import org.kie.dmn.feel.lang.ast.InfixOperator;
import org.kie.dmn.feel.lang.ast.NameRefNode;
import org.kie.dmn.feel.lang.ast.NullNode;
import org.kie.dmn.feel.lang.ast.RangeNode;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]