From 18c116c2132842e71c5a1cb48424e5e7334784b0 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Wed, 8 May 2024 14:36:28 +0200 Subject: [PATCH 01/10] [incubator-kie-issues#1659] Implemented FEELBuilder. Removing FEEL static methods. Add usage of FEELDialect inside BaseFEELTest --- .../DMNFeelExpressionEvaluator.java | 3 +- .../jsr223/JSR223DTExpressionEvaluator.java | 9 ++- .../dmn/core/ast/DMNInvocationEvaluator.java | 3 +- .../kie/dmn/core/compiler/DMNFEELHelper.java | 13 ++-- .../org/kie/dmn/core/DMNCompilerTest.java | 5 +- .../java/org/kie/dmn/core/DMNTypeTest.java | 8 +-- .../impl/DMNContextFEELCtxWrapperTest.java | 7 ++ .../src/main/java/org/kie/dmn/feel/FEEL.java | 47 +++++-------- .../dmn/feel/codegen/feel11/Functions.java | 4 +- .../codegen/feel11/ProcessedExpression.java | 2 +- .../kie/dmn/feel/lang/EvaluationContext.java | 1 + .../org/kie/dmn/feel/lang/FEELDialect.java | 47 +++++++++++++ .../feel/lang/impl/EvaluationContextImpl.java | 26 ++++--- .../kie/dmn/feel/lang/impl/FEELBuilder.java | 69 +++++++++++++++++++ .../org/kie/dmn/feel/lang/impl/FEELImpl.java | 33 +++------ .../SilentWrappingEvaluationContextImpl.java | 6 ++ .../feel/marshaller/FEELCodeMarshaller.java | 3 +- .../runtime/functions/BaseFEELFunction.java | 61 +++++++--------- .../functions/DecisionTableFunction.java | 5 +- .../functions/extended/RangeFunction.java | 4 +- .../feel/codegen/feel11/CodegenTestUtil.java | 7 +- .../documentation/ADocFEELExamplesTest.java | 3 +- .../FromSpecificationNotInAdocTest.java | 5 +- .../lang/examples/CompileEvaluateTest.java | 3 +- .../dmn/feel/lang/examples/ExamplesTest.java | 3 +- .../dmn/feel/lang/impl/FEELProfileTest.java | 2 +- .../TemporalConstantFoldingParserTest.java | 4 +- .../org/kie/dmn/feel/runtime/BFEELTest.java | 48 +++++++++++++ .../feel/runtime/BaseFEELCompilerTest.java | 3 +- .../kie/dmn/feel/runtime/BaseFEELTest.java | 40 +++++++++-- .../runtime/FEEL12ExtendedForLoopTest.java | 5 +- .../runtime/FEEL12ExtendedFunctionsTest.java | 5 +- .../runtime/FEELConditionsAndLoopsTest.java | 5 +- .../dmn/feel/runtime/FEELContextsTest.java | 5 +- .../runtime/FEELDateTimeDurationTest.java | 5 +- .../feel/runtime/FEELErrorMessagesTest.java | 11 +-- .../feel/runtime/FEELEventListenerTest.java | 3 +- .../dmn/feel/runtime/FEELExpressionsTest.java | 5 +- .../runtime/FEELFunctionDefinitionTest.java | 5 +- .../dmn/feel/runtime/FEELFunctionsTest.java | 5 +- .../kie/dmn/feel/runtime/FEELListsTest.java | 5 +- .../feel/runtime/FEELMathOperationsTest.java | 5 +- .../feel/runtime/FEELNumberCoercionTest.java | 3 +- .../dmn/feel/runtime/FEELOperatorsTest.java | 5 +- .../kie/dmn/feel/runtime/FEELRangesTest.java | 5 +- .../runtime/FEELStringOperationsTest.java | 5 +- .../feel/runtime/FEELTernaryLogicTest.java | 5 +- .../runtime/FEELValuesComparisonTest.java | 5 +- .../feel/runtime/FEELValuesConstantsTest.java | 5 +- .../runtime/KieFEELExtendedFunctionsTest.java | 5 +- .../dmn/feel/runtime/TCFoldNotTCFoldTest.java | 5 +- .../interval/FEELTemporalFunctionsTest.java | 5 +- .../tests/core/v1_1/DMNCompilerTest.java | 4 +- .../openapi/impl/BaseNodeSchemaMapper.java | 4 +- .../dmn/openapi/impl/DMNUnaryTestsMapper.java | 3 +- .../kie/dmn/openapi/impl/MapperHelper.java | 7 +- .../impl/RangeNodeSchemaMapperTest.java | 3 +- .../openapi/impl/SchemaMapperTestUtils.java | 3 +- .../ExtendedFunctionsBaseFEELTest.java | 3 +- .../validation/dtanalysis/DMNDTAnalyser.java | 9 +-- .../DMNDTAnalyserValueFromNodeVisitor.java | 3 +- ...DMNDTAnalyserValueFromNodeVisitorTest.java | 7 +- 62 files changed, 435 insertions(+), 197 deletions(-) create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java create mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java diff --git a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java index e6e6b80b734..776f5b7c462 100644 --- a/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java +++ b/drools-scenario-simulation/drools-scenario-simulation-backend/src/main/java/org/drools/scenariosimulation/backend/expression/DMNFeelExpressionEvaluator.java @@ -35,6 +35,7 @@ import org.kie.dmn.core.compiler.profiles.ExtendedDMNProfile; import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.FEELImpl; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.UnaryTest; @@ -66,7 +67,7 @@ public String fromObjectToExpression(Object value) { protected FEEL newFeelEvaluator(AtomicReference errorHolder) { // cleanup existing error errorHolder.set(null); - FEEL feel = FEEL.newInstance(singletonList(new ExtendedDMNProfile())); + FEEL feel = FEELBuilder.builder().withProfiles(singletonList(new ExtendedDMNProfile())).build(); feel.addListener(event -> { FEELEvent feelEvent = errorHolder.get(); if (!(feelEvent instanceof SyntaxErrorEvent) && diff --git a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java index 59d9b38cbab..6554a37bb0d 100644 --- a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java +++ b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java @@ -44,6 +44,7 @@ import org.kie.dmn.core.impl.DMNResultImpl; import org.kie.dmn.core.impl.DMNRuntimeEventManagerUtils; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.decisiontables.HitPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -164,6 +165,8 @@ private static class JSR223WrappingEC implements EvaluationContext { private final Map values; private final List events; + //TODO GC 1659 + private final FEELDialect dialect = FEELDialect.FEEL; public JSR223WrappingEC(Map values, List events) { this.values = Collections.unmodifiableMap(values); @@ -244,7 +247,11 @@ public void setRootObject(Object v) { public Object getRootObject() { throw new UnsupportedOperationException("not implemented for this impl."); } - + + @Override + public FEELDialect getDialect() { + return dialect; + } } } diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java index fc57ee4468a..ec42aa0f1ec 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/ast/DMNInvocationEvaluator.java @@ -39,6 +39,7 @@ import org.kie.dmn.core.util.Msg; import org.kie.dmn.core.util.MsgUtil; import org.kie.dmn.feel.FEEL; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; import org.kie.dmn.feel.lang.impl.FEELEventListenersManager; import org.kie.dmn.feel.lang.impl.FEELImpl; @@ -187,7 +188,7 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult d FEELEventListenersManager listenerMgr = new FEELEventListenersManager(); listenerMgr.addListener(events::add); - EvaluationContextImpl ctx = new EvaluationContextImpl(listenerMgr, eventManager.getRuntime()); + EvaluationContextImpl ctx = new EvaluationContextImpl(listenerMgr, eventManager.getRuntime(), FEELDialect.FEEL); invocationResult = function.invokeReflectively( ctx, namedParams ); diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java index c90326bdde8..da1479572e4 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java @@ -46,9 +46,11 @@ import org.kie.dmn.feel.codegen.feel11.ProcessedUnaryTest; import org.kie.dmn.feel.lang.CompiledExpression; import org.kie.dmn.feel.lang.CompilerContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.FEELProfile; import org.kie.dmn.feel.lang.Type; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.FEELEventListenersManager; import org.kie.dmn.feel.lang.impl.FEELImpl; import org.kie.dmn.feel.runtime.FEELFunction; @@ -84,7 +86,7 @@ public DMNFEELHelper(ClassLoader classLoader, List feelProfiles) { } private FEEL createFEELInstance() { - FEEL feel = FEEL.newInstance(classLoader, feelProfiles); + FEEL feel = FEELBuilder.builder().withClassloader(classLoader).withProfiles(feelProfiles).build(); feel.addListener( listener ); return feel; } @@ -94,14 +96,15 @@ private FEEL createFEELInstance() { * This FEEL instance is potentially not the same shared by the compiler during the compilation phase. */ public FEEL newFEELInstance() { - return FEEL.newInstance(classLoader, feelProfiles); + return FEELBuilder.builder().withClassloader(classLoader).withProfiles(feelProfiles).build(); } public static boolean valueMatchesInUnaryTests(List unaryTests, Object value, DMNContext dmnContext) { FEELEventListenersManager manager = new FEELEventListenersManager(); FEELEventsListenerImpl listener = new FEELEventsListenerImpl(); manager.addListener( listener ); - EvaluationContextImpl ctx = new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), manager); + //TODO GC 1659 + EvaluationContextImpl ctx = new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), manager, FEELDialect.FEEL); try { ctx.enterFrame(); if ( dmnContext != null ) { @@ -282,7 +285,7 @@ private boolean isDuplicateEvent(DMNModelImpl model, Msg.Message error, DMNEleme public ClassOrInterfaceDeclaration generateUnaryTestsSource(CompilerContext compilerContext, String unaryTests, Type inputColumnType, boolean isStatic) { compilerContext.addInputVariableType("?", inputColumnType); - ProcessedUnaryTest compiledUnaryTest = ((FEELImpl) feel).compileUnaryTests(unaryTests, compilerContext); + ProcessedUnaryTest compiledUnaryTest = ((FEELImpl) feel).processUnaryTests(unaryTests, compilerContext); CompilationUnit compilationUnit = compiledUnaryTest.getSourceCode().clone(); return compilationUnit.getType(0) .asClassOrInterfaceDeclaration() @@ -332,6 +335,6 @@ public ClassOrInterfaceDeclaration generateFeelExpressionSource(String input, Co } public CompilationUnit generateFeelExpressionCompilationUnit(String input, CompilerContext compilerContext1) { - return ((FEELImpl) feel).compileExpression(input, compilerContext1).getSourceCode(); + return feel.processExpression(input, compilerContext1).getSourceCode(); } } diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNCompilerTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNCompilerTest.java index 20ca1cbe852..fcaadef883d 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNCompilerTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNCompilerTest.java @@ -40,10 +40,8 @@ import org.kie.dmn.core.impl.SimpleTypeImpl; import org.kie.dmn.core.util.DMNRuntimeUtil; import org.kie.dmn.feel.lang.EvaluationContext; -import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; import org.kie.dmn.feel.lang.types.AliasFEELType; import org.kie.dmn.feel.lang.types.BuiltInType; -import org.kie.dmn.feel.util.ClassLoaderUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,6 +50,7 @@ import static org.kie.dmn.core.util.DynamicTypeUtils.entry; import static org.kie.dmn.core.util.DynamicTypeUtils.mapOf; import static org.kie.dmn.core.util.DynamicTypeUtils.prototype; +import static org.kie.dmn.feel.codegen.feel11.CodegenTestUtil.newEmptyEvaluationContext; public class DMNCompilerTest extends BaseVariantTest { @@ -176,7 +175,7 @@ void itemDefAllowedValuesString(VariantTestConf conf) { final SimpleTypeImpl feelType = (SimpleTypeImpl) type; - final EvaluationContext ctx = new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null); + final EvaluationContext ctx = newEmptyEvaluationContext(); assertThat(feelType.getFeelType()).isInstanceOf(AliasFEELType.class); assertThat(feelType.getFeelType().getName()).isEqualTo("tEmploymentStatus"); assertThat(feelType.getAllowedValuesFEEL()).hasSize(4); diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNTypeTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNTypeTest.java index 6e6ec5b8ba7..584611d5b29 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNTypeTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNTypeTest.java @@ -31,6 +31,7 @@ import org.kie.dmn.core.impl.CompositeTypeImpl; import org.kie.dmn.core.impl.SimpleTypeImpl; import org.kie.dmn.feel.FEEL; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.model.v1_5.KieDMNModelInstrumentedBase; @@ -44,6 +45,8 @@ class DMNTypeTest { private static final DMNType FEEL_STRING = typeRegistry.resolveType(KieDMNModelInstrumentedBase.URI_FEEL, "string"); private static final DMNType FEEL_NUMBER = typeRegistry.resolveType(KieDMNModelInstrumentedBase.URI_FEEL, "number"); + private static final FEEL feel = FEELBuilder.builder().build(); + @Test void drools2147() { // DROOLS-2147 @@ -93,7 +96,6 @@ void allowedValuesForASimpleTypeCollection() { // DROOLS-2357 final String testNS = "testDROOLS2357"; - final FEEL feel = FEEL.newInstance(); final DMNType tDecision1 = typeRegistry.registerType(new SimpleTypeImpl(testNS, "tListOfVowels", null, true, feel.evaluateUnaryTests("\"a\",\"e\",\"i\",\"o\",\"u\""), null, FEEL_STRING, BuiltInType.STRING)); assertThat(tDecision1.isAssignableValue("a")).isTrue(); @@ -111,7 +113,6 @@ void typeConstraintForASimpleTypeCollection() { // incubator-kie-issues#926 final String testNS = "testINCUBATORKIEISSUES926"; - final FEEL feel = FEEL.newInstance(); final DMNType tDecision1 = typeRegistry.registerType(new SimpleTypeImpl(testNS, "tListOfStrings", null, true, null, feel.evaluateUnaryTests("count (?) > 1"), FEEL_STRING, BuiltInType.LIST)); assertThat(tDecision1.isAssignableValue("asdvfsd")).isFalse(); @@ -126,7 +127,6 @@ void typeConstraintForASimpleTypeCollection() { public void testAllowedValuesForSimpleTypeInherited() { final String testNS = "testAllowedValuesForSimpleTypeInherited"; - final FEEL feel = FEEL.newInstance(); final DMNType aStringSimpleType = typeRegistry.registerType(new SimpleTypeImpl(testNS, "AString", null, false, feel.evaluateUnaryTests("string length( ? ) = 3"), null, FEEL_STRING, BuiltInType.STRING)); assertThat(aStringSimpleType.isAssignableValue("abc")).isTrue(); assertThat(aStringSimpleType.isAssignableValue("ab")).isFalse(); @@ -140,7 +140,6 @@ public void testAllowedValuesForSimpleTypeInherited() { @Test public void testAllowedValuesForComplexType() { final String testNS = "testAllowedValuesForComplexType"; - final FEEL feel = FEEL.newInstance(); final Map personPrototype = prototype(entry("name", FEEL_STRING), entry("age", FEEL_NUMBER)); final BaseDMNTypeImpl dmnPerson = (BaseDMNTypeImpl) typeRegistry.registerType(new CompositeTypeImpl(testNS, "Person", null, false, personPrototype, null, null)); dmnPerson.setAllowedValues(feel.evaluateUnaryTests("?.name = \"Bob\", ?.age >= 30")); @@ -159,7 +158,6 @@ public void testAllowedValuesForComplexType() { @Test public void testAllowedValuesForComplexTypeInherited() { final String testNS = "testAllowedValuesForComplexType"; - final FEEL feel = FEEL.newInstance(); final Map personPrototype = prototype(entry("name", FEEL_STRING), entry("age", FEEL_NUMBER)); final BaseDMNTypeImpl dmnAdultPerson = (BaseDMNTypeImpl) typeRegistry.registerType(new CompositeTypeImpl(testNS, "AdultPerson", null, false, personPrototype, null, null)); dmnAdultPerson.setAllowedValues(feel.evaluateUnaryTests("?.age >= 30")); diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java index a0dd83951cd..327d6212ba4 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java @@ -30,6 +30,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEventListener; import org.kie.dmn.core.BaseDMNContextTest; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -160,6 +161,12 @@ public void setRootObject(Object v) { public Object getRootObject() { throw new UnsupportedOperationException(); } + + @Override + public FEELDialect getDialect() { + //TODO GC 1659 + return FEELDialect.FEEL; + } } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java index 33207446fc6..1dd0f2306de 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java @@ -23,12 +23,13 @@ import java.util.Set; import org.kie.dmn.api.feel.runtime.events.FEELEventListener; +import org.kie.dmn.feel.codegen.feel11.ProcessedExpression; import org.kie.dmn.feel.lang.CompiledExpression; import org.kie.dmn.feel.lang.CompilerContext; import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.FEELProfile; import org.kie.dmn.feel.lang.Type; -import org.kie.dmn.feel.lang.impl.FEELImpl; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.runtime.UnaryTest; /** @@ -37,41 +38,14 @@ * This class is the entry point for the engine use */ public interface FEEL { - - /** - * Factory method to create a new FEEL engine instance - * - * @return a newly instantiated FEEL engine instance - */ - static FEEL newInstance() { - return new FEELImpl(); - } - - /** - * Factory method to create a new FEEL engine instance, using the specified classloader. - * - * @return a newly instantiated FEEL engine instance - */ - static FEEL newInstance(ClassLoader cl) { - return new FEELImpl(cl); - } - - /** - * Factory method to create a new FEEL engine instance using custom FEELProfile(s) - * - * @return a newly instantiated FEEL engine instance - */ - static FEEL newInstance(List profiles) { - return new FEELImpl(profiles); - } - + /** * Factory method to create a new FEEL engine instance using custom FEELProfile(s), using the specified classloader. * * @return a newly instantiated FEEL engine instance */ static FEEL newInstance(ClassLoader cl, List profiles) { - return new FEELImpl(cl, profiles); + return FEELBuilder.builder().withClassloader(cl).withProfiles(profiles).build(); } /** @@ -91,6 +65,17 @@ static FEEL newInstance(ClassLoader cl, List profiles) { */ CompiledExpression compile(String expression, CompilerContext ctx); + /** + * Process the string expression using the given + * compiler context. The returned ProcessedExpression + * could be used to retrieve the actual CompiledExpression + * + * @param expression a FEEL expression + * @param ctx a compiler context + * @return the processed expression + */ + ProcessedExpression processExpression(String expression, CompilerContext ctx); + /** * Compiles the string expression using the given * compiler context. @@ -99,7 +84,7 @@ static FEEL newInstance(ClassLoader cl, List profiles) { * @param ctx a compiler context * @return the compiled unary tests */ - CompiledExpression compileUnaryTests(String expression, CompilerContext ctx); + CompiledExpression processUnaryTests(String expression, CompilerContext ctx); /** * Evaluates the given FEEL expression and returns diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Functions.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Functions.java index 1bdae213f28..47b3740e827 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Functions.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Functions.java @@ -28,6 +28,7 @@ import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.ast.BaseNode; import org.kie.dmn.feel.lang.ast.FunctionDefNode; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; @@ -45,8 +46,9 @@ public class Functions { private static final Expression EMPTY_LIST = parseExpression("java.util.Collections.emptyList()"); public static Expression external(List paramNames, BaseNode body) { + //TODO GC 1659 EvaluationContextImpl emptyEvalCtx = - new EvaluationContextImpl(Functions.class.getClassLoader(), new FEELEventListenersManager()); + new EvaluationContextImpl(Functions.class.getClassLoader(), new FEELEventListenersManager(), FEELDialect.FEEL); Map conf = (Map) body.evaluate(emptyEvalCtx); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ProcessedExpression.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ProcessedExpression.java index 7c9762144ff..a0ba1ddfd6d 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ProcessedExpression.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ProcessedExpression.java @@ -76,7 +76,7 @@ public ProcessedExpression( } } - public CompiledFEELExpression getResult() { + public CompiledFEELExpression asCompiledFEELExpression() { if (executionMode == Compiled) { if (CAN_PLATFORM_CLASSLOAD) { executableFEELExpression = getCompiled(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java index 6322ea83f70..faf12356de5 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java @@ -59,4 +59,5 @@ public interface EvaluationContext { Object getRootObject(); + FEELDialect getDialect(); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java new file mode 100644 index 00000000000..4d1d68186cf --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.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; + +import java.util.Arrays; + +public enum FEELDialect { + + FEEL(""), + BFEEL("https://www.omg.org/spec/DMN/20240513/B-FEEL/"); + + private final String namespace; + + FEELDialect(String namespace) { + this.namespace = namespace; + } + + public String getNamespace() {return namespace;} + + /** + * In current implementation, it returns BFEEL if provided namespace matches, otherwise returns FEEL + * @param namespace + * @return + */ + public static FEELDialect fromNamespace(String namespace) { + return Arrays.stream(FEELDialect.values()) + .filter(dialect -> dialect.getNamespace().equals(namespace)) + .findFirst() + .orElse(FEELDialect.FEEL); + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java index 4c7f9b0b215..589756e27ac 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java @@ -30,6 +30,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEventListener; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.util.EvalHelper; public class EvaluationContextImpl implements EvaluationContext { @@ -39,19 +40,21 @@ public class EvaluationContextImpl implements EvaluationContext { private DMNRuntime dmnRuntime; private boolean performRuntimeTypeCheck = false; private ClassLoader rootClassLoader; + private final FEELDialect feelDialect; - private EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsManager, Deque stack) { + private EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsManager, Deque stack, FEELDialect feelDialect) { this.eventsManager = eventsManager; this.rootClassLoader = cl; this.stack = new ArrayDeque<>(stack); + this.feelDialect = feelDialect; } - public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsManager) { - this(cl, eventsManager, 32); + public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsManager, FEELDialect feelDialect) { + this(cl, eventsManager, 32, feelDialect); } - public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsManager, int size) { - this(cl, eventsManager, new ArrayDeque<>()); + public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsManager, int size, FEELDialect feelDialect) { + this(cl, eventsManager, new ArrayDeque<>(), feelDialect); // we create a rootFrame to hold all the built in functions push( RootExecutionFrame.INSTANCE ); // and then create a global frame to be the starting frame @@ -61,18 +64,19 @@ public EvaluationContextImpl(ClassLoader cl, FEELEventListenersManager eventsMan } @Deprecated - public EvaluationContextImpl(FEELEventListenersManager eventsManager, DMNRuntime dmnRuntime) { - this(dmnRuntime.getRootClassLoader(), eventsManager); + public EvaluationContextImpl(FEELEventListenersManager eventsManager, DMNRuntime dmnRuntime, FEELDialect feelDialect) { + this(dmnRuntime.getRootClassLoader(), eventsManager, feelDialect); this.dmnRuntime = dmnRuntime; } - private EvaluationContextImpl(FEELEventListenersManager eventsManager) { + private EvaluationContextImpl(FEELEventListenersManager eventsManager, FEELDialect feelDialect) { this.eventsManager = eventsManager; + this.feelDialect = feelDialect; } @Override public EvaluationContext current() { - EvaluationContextImpl ec = new EvaluationContextImpl(eventsManager); + EvaluationContextImpl ec = new EvaluationContextImpl(eventsManager, feelDialect); ec.stack = stack.clone(); ec.rootClassLoader = this.rootClassLoader; ec.dmnRuntime = this.dmnRuntime; @@ -223,4 +227,8 @@ public Object getRootObject() { return peek().getRootObject(); } + @Override + public FEELDialect getDialect() { + return feelDialect; + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java new file mode 100644 index 00000000000..60d4797cea7 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java @@ -0,0 +1,69 @@ +/** + * 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.impl; + +import java.util.Collections; +import java.util.List; + +import org.kie.dmn.feel.FEEL; +import org.kie.dmn.feel.lang.FEELDialect; +import org.kie.dmn.feel.lang.FEELProfile; +import org.kie.dmn.feel.util.ClassLoaderUtil; + +/** + * FEELImpl builder + */ +public class FEELBuilder { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private ClassLoader classLoader; + private List profiles; + private FEELDialect feelDialect; + + private Builder() { + } + + public Builder withClassloader(ClassLoader classLoader) { + this.classLoader = classLoader; + return this; + } + + public Builder withProfiles(List profiles) { + this.profiles = profiles; + return this; + } + + public Builder withFEELDialect(FEELDialect feelDialect) { + this.feelDialect = feelDialect; + return this; + } + + public FEEL build() { + ClassLoader classLoaderToUse = classLoader != null ? classLoader : ClassLoaderUtil.findDefaultClassLoader(); + List profilesToUse = profiles != null ? profiles : Collections.emptyList(); + FEELDialect feelDialectToUse = feelDialect != null ? feelDialect : FEELDialect.FEEL; + return new FEELImpl(classLoaderToUse, profilesToUse, feelDialectToUse); + } + } +} diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java index d9630b220a7..80024a15564 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELImpl.java @@ -36,12 +36,12 @@ import org.kie.dmn.feel.lang.CompiledExpression; import org.kie.dmn.feel.lang.CompilerContext; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.FEELProfile; import org.kie.dmn.feel.lang.Type; import org.kie.dmn.feel.parser.feel11.profiles.DoCompileFEELProfile; import org.kie.dmn.feel.runtime.FEELFunction; import org.kie.dmn.feel.runtime.UnaryTest; -import org.kie.dmn.feel.util.ClassLoaderUtil; /** * Language runtime entry point @@ -59,20 +59,9 @@ public class FEELImpl private final Optional customFrame; private final Collection customFunctions; private final boolean doCompile; + private final FEELDialect feelDialect; - public FEELImpl() { - this(ClassLoaderUtil.findDefaultClassLoader(), Collections.emptyList()); - } - - public FEELImpl(ClassLoader cl) { - this(cl, Collections.emptyList()); - } - - public FEELImpl(List profiles) { - this(ClassLoaderUtil.findDefaultClassLoader(), profiles); - } - - public FEELImpl(ClassLoader cl, List profiles) { + FEELImpl(ClassLoader cl, List profiles, FEELDialect feelDialect) { this.classLoader = cl; this.profiles = Collections.unmodifiableList(profiles); ExecutionFrameImpl frame = null; @@ -95,6 +84,7 @@ public FEELImpl(ClassLoader cl, List profiles) { doCompile = profiles.stream().anyMatch(DoCompileFEELProfile.class::isInstance); customFrame = Optional.ofNullable(frame); customFunctions = Collections.unmodifiableCollection(functions.values()); + this.feelDialect = feelDialect; } @Override @@ -112,14 +102,11 @@ public Collection getCustomFunctions() { @Override public CompiledExpression compile(String expression, CompilerContext ctx) { - return new ProcessedExpression( - expression, - ctx, - ProcessedFEELUnit.DefaultMode.of(doCompile || ctx.isDoCompile()), - profiles).getResult(); + return processExpression(expression, ctx).asCompiledFEELExpression(); } - public ProcessedExpression compileExpression(String expression, CompilerContext ctx) { + @Override + public ProcessedExpression processExpression(String expression, CompilerContext ctx) { return new ProcessedExpression( expression, ctx, @@ -128,7 +115,7 @@ public ProcessedExpression compileExpression(String expression, CompilerContext } @Override - public ProcessedUnaryTest compileUnaryTests(String expressions, CompilerContext ctx) { + public ProcessedUnaryTest processUnaryTests(String expressions, CompilerContext ctx) { return new ProcessedUnaryTest(expressions, ctx, profiles); } @@ -186,7 +173,7 @@ public EvaluationContextImpl newEvaluationContext(Collection */ public EvaluationContextImpl newEvaluationContext(ClassLoader cl, Collection listeners, Map inputVariables) { FEELEventListenersManager eventsManager = getEventsManager(listeners); - EvaluationContextImpl ctx = new EvaluationContextImpl(cl, eventsManager, inputVariables.size()); + EvaluationContextImpl ctx = new EvaluationContextImpl(cl, eventsManager, inputVariables.size(), feelDialect); if (customFrame.isPresent()) { ExecutionFrameImpl globalFrame = (ExecutionFrameImpl) ctx.pop(); ExecutionFrameImpl interveawedFrame = customFrame.get(); @@ -211,7 +198,7 @@ public List evaluateUnaryTests(String expression, Map v ctx.addInputVariableType( e.getKey(), e.getValue() ); } - return compileUnaryTests(expression, ctx) + return processUnaryTests(expression, ctx) .apply(newEvaluationContext(ctx.getListeners(), EMPTY_INPUT)); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java index 98b16582488..19e3f800d2f 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java @@ -27,6 +27,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEventListener; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; /** * This EvaluationContext should only be used to "try" evaluations @@ -116,4 +117,9 @@ public DMNRuntime getDMNRuntime() { public ClassLoader getRootClassLoader() { return wrapped.getRootClassLoader(); } + + @Override + public FEELDialect getDialect() { + return wrapped.getDialect(); + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/marshaller/FEELCodeMarshaller.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/marshaller/FEELCodeMarshaller.java index 68e0597e589..1c051656b46 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/marshaller/FEELCodeMarshaller.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/marshaller/FEELCodeMarshaller.java @@ -22,6 +22,7 @@ import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.Type; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.runtime.functions.extended.CodeFunction; import org.kie.dmn.feel.runtime.functions.extended.KieExtendedDMNFunctions; @@ -36,7 +37,7 @@ public class FEELCodeMarshaller implements FEELMarshaller { public static final FEELCodeMarshaller INSTANCE = new FEELCodeMarshaller(); - private FEEL feel = FEEL.newInstance(); + private FEEL feel = FEELBuilder.builder().build(); private FEELCodeMarshaller() {} diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java index ae1fbf5e5f6..008d2b59318 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -96,24 +97,10 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { if ( result instanceof Either ) { @SuppressWarnings("unchecked") Either either = (Either) result; - - Object eitherResult = either.cata( (left) -> { - ctx.notifyEvt( () -> { - if ( left instanceof InvalidParametersEvent ) { - InvalidParametersEvent invalidParametersEvent = (InvalidParametersEvent) left; - invalidParametersEvent.setNodeName( getName() ); - invalidParametersEvent.setActualParameters( - Stream.of( cm.apply.getParameters() ).map( p -> p.getAnnotation( ParameterName.class ).value() ).collect( Collectors.toList() ), - Arrays.asList( cm.actualParams ) - ); - } - return left; - } - ); - return null; - }, Function.identity() ); - - return eitherResult; + return getEitherResult(ctx, + either, + () -> Stream.of(cm.apply.getParameters()).map(p -> p.getAnnotation(ParameterName.class).value()).collect(Collectors.toList()), + () -> Arrays.asList(cm.actualParams)); } return result; @@ -121,9 +108,7 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { // CandidateMethod cm could be null also if reflection failed on Platforms not supporting getClass().getDeclaredMethods() String ps = getClass().toString(); logger.error( "Unable to find function '" + getName() + "( " + ps.substring( 1, ps.length() - 1 ) + " )'" ); - ctx.notifyEvt(() -> { - return new FEELEventBase(Severity.ERROR, "Unable to find function '" + getName() + "( " + ps.substring(1, ps.length() - 1) + " )'", null); - }); + ctx.notifyEvt(() -> new FEELEventBase(Severity.ERROR, "Unable to find function '" + getName() + "( " + ps.substring(1, ps.length() - 1) + " )'", null)); } } else { if ( isNamedParams ) { @@ -135,20 +120,10 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { Either either = (Either) result; final Object[] usedParams = params; - - Object eitherResult = either.cata( (left) -> { - ctx.notifyEvt( () -> { - if ( left instanceof InvalidParametersEvent ) { - InvalidParametersEvent invalidParametersEvent = (InvalidParametersEvent) left; - invalidParametersEvent.setNodeName( getName() ); - invalidParametersEvent.setActualParameters( IntStream.of( 0, usedParams.length ).mapToObj( i -> "arg" + i ).collect( Collectors.toList() ), Arrays.asList( usedParams ) ); - } - return left; - } - ); - return null; - }, Function.identity() ); - + Object eitherResult = getEitherResult(ctx, + either, + () -> IntStream.of( 0, usedParams.length ).mapToObj( i -> "arg" + i ).collect( Collectors.toList() ), + () -> Arrays.asList( usedParams )); return normalizeResult( eitherResult ); } return normalizeResult( result ); @@ -170,6 +145,22 @@ public Object invoke(EvaluationContext ctx, Object[] params) { throw new RuntimeException( "This method should be overriden by classes that implement custom feel functions" ); } + private Object getEitherResult(EvaluationContext ctx, Either source, Supplier> parameterNamesSupplier, + Supplier> parameterValuesSupplier) { + return source.cata((left) -> { + ctx.notifyEvt(() -> { + if (left instanceof InvalidParametersEvent invalidParametersEvent) { + invalidParametersEvent.setNodeName(getName()); + invalidParametersEvent.setActualParameters(parameterNamesSupplier.get(), + parameterValuesSupplier.get()); + } + return left; + } + ); + return null; + }, Function.identity()); + } + private Object[] rearrangeParameters(Object[] params, List pnames) { if ( pnames.size() > 0 ) { Object[] actualParams = new Object[pnames.size()]; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java index 44d081af66b..5643ee5922d 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java @@ -30,6 +30,7 @@ import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.CompiledExpression; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.UnaryTest; import org.kie.dmn.feel.runtime.decisiontables.DTDecisionRule; @@ -115,14 +116,14 @@ public Object invoke(@ParameterName("ctx") EvaluationContext ctx, } // TODO parse default output value. - FEEL feel = FEEL.newInstance(); + FEEL feel = FEELBuilder.builder().build(); List decisionRules = IntStream.range( 0, ruleList.size() ) .mapToObj( index -> toDecisionRule( ctx, feel, index, ruleList.get( index ), inputExpressions.size() ) ) .collect( Collectors.toList() ); // TODO is there a way to avoid UUID and get from _evaluation_ ctx the name of the wrapping context? // TODO also in this case it is using an ad-hoc created FEEL instance instead of the "hosted" one. - DecisionTableImpl dti = new DecisionTableImpl(UUID.randomUUID().toString(), inputExpressions, inputs, outputClauses, decisionRules, HitPolicy.fromString(hitPolicy), FEEL.newInstance()); + DecisionTableImpl dti = new DecisionTableImpl(UUID.randomUUID().toString(), inputExpressions, inputs, outputClauses, decisionRules, HitPolicy.fromString(hitPolicy), FEELBuilder.builder().build()); return new DTInvokerFunction( dti ); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java index 8e65dbf6b1d..4f4cce1621f 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java @@ -21,6 +21,7 @@ import org.antlr.v4.runtime.tree.ParseTree; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.ast.*; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; import org.kie.dmn.feel.lang.impl.FEELEventListenersManager; @@ -46,7 +47,8 @@ public class RangeFunction extends BaseFEELFunction { public static final RangeFunction INSTANCE = new RangeFunction(); - private static final EvaluationContext STUBBED = new EvaluationContextImpl(Thread.currentThread().getContextClassLoader(), new FEELEventListenersManager(), 0); + //TODO GC 1659 + private static final EvaluationContext STUBBED = new EvaluationContextImpl(Thread.currentThread().getContextClassLoader(), new FEELEventListenersManager(), 0, FEELDialect.FEEL); private static final List> ALLOWED_NODES = Arrays.asList(baseNode -> baseNode instanceof NullNode, baseNode -> baseNode instanceof NumberNode, diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/CodegenTestUtil.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/CodegenTestUtil.java index 997b04f41db..e6d7d665237 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/CodegenTestUtil.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/CodegenTestUtil.java @@ -19,6 +19,7 @@ package org.kie.dmn.feel.codegen.feel11; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; import org.kie.dmn.feel.lang.impl.FEELEventListenersManager; import org.kie.dmn.feel.util.ClassLoaderUtil; @@ -30,10 +31,12 @@ private CodegenTestUtil() { } public static EvaluationContext newEmptyEvaluationContext(FEELEventListenersManager mgr) { - return new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), mgr); + //TODO GC 1659 + return new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), mgr, FEELDialect.FEEL); } public static EvaluationContext newEmptyEvaluationContext() { - return new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null); + //TODO GC 1659 + return new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null, FEELDialect.FEEL); } } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/ADocFEELExamplesTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/ADocFEELExamplesTest.java index 9570d44e762..fcdd0714c6d 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/ADocFEELExamplesTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/ADocFEELExamplesTest.java @@ -36,6 +36,7 @@ import org.junit.jupiter.api.Test; import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.FEELProfile; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.parser.feel11.profiles.KieExtendedFEELProfile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +51,7 @@ class ADocFEELExamplesTest { profiles.add(new KieExtendedFEELProfile()); } - private final FEEL feel = FEEL.newInstance(profiles); + private final FEEL feel = FEELBuilder.builder().withProfiles(profiles).build(); /** * Dev notes: the availability of the .adoc resource to this test and its refresh is governed by Maven. diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/FromSpecificationNotInAdocTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/FromSpecificationNotInAdocTest.java index f4efed20eca..b28a84d6ff9 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/FromSpecificationNotInAdocTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/documentation/FromSpecificationNotInAdocTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.BaseFEELTest; /** @@ -33,8 +34,8 @@ public class FromSpecificationNotInAdocTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/CompileEvaluateTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/CompileEvaluateTest.java index 4fa44777722..46d6ceced3e 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/CompileEvaluateTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/CompileEvaluateTest.java @@ -32,6 +32,7 @@ import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.CompiledExpression; import org.kie.dmn.feel.lang.CompilerContext; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.MapBackedType; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.lang.types.GenListType; @@ -44,7 +45,7 @@ class CompileEvaluateTest { private static final Logger LOG = LoggerFactory.getLogger(CompileEvaluateTest.class); - private static final FEEL feel = FEEL.newInstance(); + private static final FEEL feel = FEELBuilder.builder().build(); private List errors; private FEELEventListener errorsCountingListener; diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/ExamplesTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/ExamplesTest.java index b05f68c5121..fd82f83a99e 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/ExamplesTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/examples/ExamplesTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.kie.dmn.feel.FEEL; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +41,7 @@ class ExamplesTest @BeforeAll static void setupTest() { String expression = loadExpression( "example_10_6_1.feel" ); - feel = FEEL.newInstance(); + feel = FEELBuilder.builder().build(); context = (Map) feel.evaluate( expression ); } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/FEELProfileTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/FEELProfileTest.java index a091bf74237..c5705268897 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/FEELProfileTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/FEELProfileTest.java @@ -39,7 +39,7 @@ class FEELProfileTest { void feelProfileFunctionsAndValues() { // Instantiate a new FEEL with the profile to try the method that uses the data cache - FEEL feel = FEEL.newInstance(List.of(new TestFEELProfile())); + FEEL feel = FEELBuilder.builder().withProfiles(List.of(new TestFEELProfile())).build(); assertThat(feel.evaluate("use cache(\"val 1\")")).isEqualTo("1"); assertThat(feel.evaluate("use cache(\"val 3\")")).isEqualTo("3"); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/TemporalConstantFoldingParserTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/TemporalConstantFoldingParserTest.java index 0e63e1eb269..2ccaada05c5 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/TemporalConstantFoldingParserTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/impl/TemporalConstantFoldingParserTest.java @@ -46,8 +46,8 @@ public static Iterable data() { } public String expression; - static final FEEL FEEL_STRICT = FEEL.newInstance(); - static final FEEL FEEL_KIE = FEEL.newInstance(List.of(new KieExtendedFEELProfile())); + static final FEEL FEEL_STRICT = FEELBuilder.builder().build(); + static final FEEL FEEL_KIE = FEELBuilder.builder().withProfiles(List.of(new KieExtendedFEELProfile())).build(); @MethodSource("data") @ParameterizedTest(name = "{0}") diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java new file mode 100644 index 00000000000..1fab72f232f --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java @@ -0,0 +1,48 @@ +/** + * 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.runtime; + +import java.util.Collection; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; + +public class BFEELTest/* extends BaseFEELTest*/ { + + /* *//** + * WARNING: do not use as JUNit's @Parameters name the index {1} within this test class, as this would result in invalid character in the XML surefire-report + * Original error was: An invalid XML character (Unicode: 0x8) was found in the value of attribute "name" and element is "testcase". + *//* + @ParameterizedTest + @MethodSource("data") + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); + } + + private static Collection data() { + final Object[][] cases = new Object[][] { + {"lowercase(12)", null, null}, +// {"string(null)", "", null}, +// {"substring(\"a\", \"z\")", "", null}, + }; + return addAdditionalParameters(cases, false, FEELDialect.BFEEL); + }*/ +} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELCompilerTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELCompilerTest.java index 5fd2f0b4557..a9a2d51b36b 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELCompilerTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELCompilerTest.java @@ -27,6 +27,7 @@ import org.kie.dmn.feel.lang.CompiledExpression; import org.kie.dmn.feel.lang.CompilerContext; import org.kie.dmn.feel.lang.Type; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.parser.feel11.profiles.DoCompileFEELProfile; import org.kie.dmn.feel.runtime.BaseFEELTest.FEEL_TARGET; @@ -53,7 +54,7 @@ public void expression(String expression, Map inputTypes, Map profiles = getFEELProfilesForTests(); +// feel = FEELBuilder.builder().withProfiles(profiles).build(); +// final FEELEventListener listener = mock(FEELEventListener.class ); +// feel.addListener( listener ); +// feel.addListener(System.out::println); +// assertResult( expression, result ); +// +// if( severity != null ) { +// final ArgumentCaptor captor = ArgumentCaptor.forClass(FEELEvent.class ); +// verify( listener , atLeastOnce()).onEvent( captor.capture() ); +// assertThat(captor.getValue().getSeverity()).isEqualTo(severity); +// } else { +// verify( listener, never() ).onEvent( any(FEELEvent.class) ); +// } +// } + public void expression(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, - Boolean useExtendedProfile) { + Boolean useExtendedProfile, FEELDialect dialect) { this.expression = expression; this.result = result; this.severity = severity; @@ -65,7 +91,7 @@ public void expression(String expression, Object result, FEELEvent.Severity seve this.useExtendedProfile = useExtendedProfile; final List profiles = getFEELProfilesForTests(); - feel = FEEL.newInstance(profiles); + feel = FEELBuilder.builder().withProfiles(profiles).withFEELDialect(dialect).build(); final FEELEventListener listener = mock(FEELEventListener.class ); feel.addListener( listener ); feel.addListener(System.out::println); @@ -81,7 +107,7 @@ public void expression(String expression, Object result, FEELEvent.Severity seve } protected abstract void instanceTest(String expression, Object result, FEELEvent.Severity severity, - FEEL_TARGET testFEELTarget, Boolean useExtendedProfile); + FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect dialect); protected void assertResult(final String expression, final Object result ) { Object retrieved = feel.evaluate( expression ); @@ -97,10 +123,14 @@ protected void assertResult(final String expression, final Object result ) { } protected static List addAdditionalParameters(final Object[][] cases, final boolean useExtendedProfile) { + return addAdditionalParameters(cases, useExtendedProfile, FEELDialect.FEEL); + } + + protected static List addAdditionalParameters(final Object[][] cases, final boolean useExtendedProfile, FEELDialect feelDialect) { final List toReturn = new ArrayList<>(); for (final Object[] c : cases) { - toReturn.add(new Object[]{c[0], c[1], c[2], FEEL_TARGET.AST_INTERPRETED, useExtendedProfile}); - toReturn.add(new Object[]{c[0], c[1], c[2], FEEL_TARGET.JAVA_TRANSLATED, useExtendedProfile}); + toReturn.add(new Object[]{c[0], c[1], c[2], FEEL_TARGET.AST_INTERPRETED, useExtendedProfile, feelDialect}); + toReturn.add(new Object[]{c[0], c[1], c[2], FEEL_TARGET.JAVA_TRANSLATED, useExtendedProfile, feelDialect}); } return toReturn; } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java index ac46851950b..dafccbe2391 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java @@ -30,6 +30,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.util.EvalHelper; import static org.kie.dmn.feel.util.DynamicTypeUtils.entry; @@ -39,8 +40,8 @@ public class FEEL12ExtendedForLoopTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedFunctionsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedFunctionsTest.java index 56f75ec1d62..6eb25154891 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedFunctionsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedFunctionsTest.java @@ -26,13 +26,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEEL12ExtendedFunctionsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELConditionsAndLoopsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELConditionsAndLoopsTest.java index afaf6b4112d..eca0fe4ef5f 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELConditionsAndLoopsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELConditionsAndLoopsTest.java @@ -26,13 +26,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELConditionsAndLoopsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELContextsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELContextsTest.java index f077115a141..ef03ae47326 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELContextsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELContextsTest.java @@ -28,14 +28,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.impl.RangeImpl; public class FEELContextsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELDateTimeDurationTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELDateTimeDurationTest.java index 149db8271ce..157e96149cb 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELDateTimeDurationTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELDateTimeDurationTest.java @@ -34,14 +34,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; public class FEELDateTimeDurationTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELErrorMessagesTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELErrorMessagesTest.java index ba8f5161342..eca87988c89 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELErrorMessagesTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELErrorMessagesTest.java @@ -23,6 +23,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEventListener; import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.CompilerContext; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.runtime.events.SyntaxErrorEvent; import org.kie.dmn.feel.runtime.events.UnknownVariableErrorEvent; import org.mockito.ArgumentCaptor; @@ -37,7 +38,7 @@ class FEELErrorMessagesTest { @Test void unknownVariable() { - final FEEL feel = FEEL.newInstance(); + final FEEL feel = FEELBuilder.builder().build(); final FEELEventListener fel = Mockito.mock(FEELEventListener.class ); feel.addListener( fel ); @@ -54,7 +55,7 @@ void unknownVariable() { @Test void ifWithoutElse() { - final FEEL feel = FEEL.newInstance(); + final FEEL feel = FEELBuilder.builder().build(); final FEELEventListener fel = Mockito.mock(FEELEventListener.class); feel.addListener(fel); @@ -71,7 +72,7 @@ void ifWithoutElse() { @Test void ifWithoutElse2() { - final FEEL feel = FEEL.newInstance(); + final FEEL feel = FEELBuilder.builder().build(); final FEELEventListener fel = Mockito.mock(FEELEventListener.class); feel.addListener(fel); @@ -88,7 +89,7 @@ void ifWithoutElse2() { @Test void ifWithoutThen() { - final FEEL feel = FEEL.newInstance(); + final FEEL feel = FEELBuilder.builder().build(); final FEELEventListener fel = Mockito.mock(FEELEventListener.class); feel.addListener(fel); @@ -105,7 +106,7 @@ void ifWithoutThen() { @Test void ifWithoutThen2() { - final FEEL feel = FEEL.newInstance(); + final FEEL feel = FEELBuilder.builder().build(); final FEELEventListener fel = Mockito.mock(FEELEventListener.class); feel.addListener(fel); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELEventListenerTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELEventListenerTest.java index 2f8d6cf918c..b60046e863c 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELEventListenerTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELEventListenerTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.FEEL; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import static org.assertj.core.api.Assertions.assertThat; @@ -36,7 +37,7 @@ class FEELEventListenerTest { @BeforeEach void setup() { testVariable = null; - feel = FEEL.newInstance(); + feel = FEELBuilder.builder().build(); feel.addListener(event -> testVariable = LISTENER_OUTPUT); feel.addListener(System.out::println); feel.addListener( (evt) -> { if (evt.getSeverity() == Severity.ERROR) System.err.println(evt); } ); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELExpressionsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELExpressionsTest.java index 5138a41a643..686b5e98122 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELExpressionsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELExpressionsTest.java @@ -25,13 +25,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELExpressionsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionDefinitionTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionDefinitionTest.java index 31e5e78a60e..cef7adff42e 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionDefinitionTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionDefinitionTest.java @@ -24,13 +24,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELFunctionDefinitionTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java index 0e47e64c852..9314eb357b0 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELFunctionsTest.java @@ -28,14 +28,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; public class FEELFunctionsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELListsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELListsTest.java index 5803738dffe..208a1c1fd02 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELListsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELListsTest.java @@ -28,14 +28,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.impl.RangeImpl; public class FEELListsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java index 3e3ad562a39..1d02f60c49f 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java @@ -24,14 +24,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.util.EvalHelper; public class FEELMathOperationsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { 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 de319bc84b1..683b7e42340 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 @@ -26,12 +26,13 @@ import org.junit.jupiter.api.Test; import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.ast.InfixOperator; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull; class FEELNumberCoercionTest { - private final FEEL feel = FEEL.newInstance(); + private final FEEL feel = FEELBuilder.builder().build(); private Object evaluateInfix(final Object x, final InfixOperator op, final Object y) { final Map inputVariables = new HashMap<>(); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELOperatorsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELOperatorsTest.java index 9aba1fed6c6..92258af10bf 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELOperatorsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELOperatorsTest.java @@ -23,13 +23,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELOperatorsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java index 1eda8deb2f8..780e31e96dd 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELRangesTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.runtime.impl.RangeImpl; @@ -35,8 +36,8 @@ public class FEELRangesTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELStringOperationsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELStringOperationsTest.java index 2efb19ebe63..b8d043e284d 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELStringOperationsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELStringOperationsTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELStringOperationsTest extends BaseFEELTest { @@ -32,8 +33,8 @@ public class FEELStringOperationsTest extends BaseFEELTest { */ @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELTernaryLogicTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELTernaryLogicTest.java index 9cfe87923a4..42f779a768f 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELTernaryLogicTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELTernaryLogicTest.java @@ -23,13 +23,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELTernaryLogicTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesComparisonTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesComparisonTest.java index dd12b33bc4f..bd2582d0757 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesComparisonTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesComparisonTest.java @@ -23,13 +23,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELValuesComparisonTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesConstantsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesConstantsTest.java index db32eb69f81..5334fb4065f 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesConstantsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELValuesConstantsTest.java @@ -24,13 +24,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class FEELValuesConstantsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/KieFEELExtendedFunctionsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/KieFEELExtendedFunctionsTest.java index b3e66fb6c6b..9997089de5d 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/KieFEELExtendedFunctionsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/KieFEELExtendedFunctionsTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import static org.kie.dmn.feel.util.DynamicTypeUtils.entry; import static org.kie.dmn.feel.util.DynamicTypeUtils.mapOf; @@ -36,8 +37,8 @@ public class KieFEELExtendedFunctionsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/TCFoldNotTCFoldTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/TCFoldNotTCFoldTest.java index c57037b6955..a09aafccddd 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/TCFoldNotTCFoldTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/TCFoldNotTCFoldTest.java @@ -25,13 +25,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; public class TCFoldNotTCFoldTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/interval/FEELTemporalFunctionsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/interval/FEELTemporalFunctionsTest.java index 0794d4a1e3c..24a8fafc821 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/interval/FEELTemporalFunctionsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/interval/FEELTemporalFunctionsTest.java @@ -23,14 +23,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.BaseFEELTest; public class FEELTemporalFunctionsTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile); + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); } private static Collection data() { diff --git a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNCompilerTest.java b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNCompilerTest.java index e522c4ad8c9..670c2a8327e 100644 --- a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNCompilerTest.java +++ b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNCompilerTest.java @@ -31,6 +31,7 @@ import org.kie.dmn.core.impl.CompositeTypeImpl; import org.kie.dmn.core.impl.SimpleTypeImpl; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; import org.kie.dmn.feel.lang.types.AliasFEELType; import org.kie.dmn.feel.lang.types.BuiltInType; @@ -69,7 +70,8 @@ void itemDefAllowedValuesString(VariantTestConf conf) { final SimpleTypeImpl feelType = (SimpleTypeImpl) type; - final EvaluationContext ctx = new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null); + //TODO GC 1659 + final EvaluationContext ctx = new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null, FEELDialect.FEEL); assertThat(feelType.getFeelType()).isInstanceOf(AliasFEELType.class); assertThat(feelType.getFeelType().getName()).isEqualTo("tEmploymentStatus"); assertThat(feelType.getAllowedValuesFEEL()).hasSize(4); diff --git a/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/BaseNodeSchemaMapper.java b/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/BaseNodeSchemaMapper.java index a82733b1e2b..d9603ed7f40 100644 --- a/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/BaseNodeSchemaMapper.java +++ b/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/BaseNodeSchemaMapper.java @@ -27,6 +27,7 @@ import org.eclipse.microprofile.openapi.models.media.Schema; import org.kie.dmn.feel.codegen.feel11.Functions; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.ast.AtLiteralNode; import org.kie.dmn.feel.lang.ast.BaseNode; import org.kie.dmn.feel.lang.ast.NullNode; @@ -49,8 +50,9 @@ public class BaseNodeSchemaMapper { private static BiConsumer NUMBERNODE_CONSUMER = (node, schema) -> populateEnumSchema(schema, ((NumberNode) node).getValue()); private static BiConsumer ATLITERALNODE_CONSUMER = (node, schema) -> { + //TODO GC 1659 EvaluationContextImpl emptyEvalCtx = - new EvaluationContextImpl(Functions.class.getClassLoader(), new FEELEventListenersManager()); + new EvaluationContextImpl(Functions.class.getClassLoader(), new FEELEventListenersManager(), FEELDialect.FEEL); Object evaluated = node.evaluate(emptyEvalCtx); Object toStore = evaluated != null ? evaluated : ((AtLiteralNode) node).getStringLiteral().toString(); populateEnumSchema(schema, toStore); diff --git a/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/DMNUnaryTestsMapper.java b/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/DMNUnaryTestsMapper.java index c40dd0349f6..885a1e61a60 100644 --- a/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/DMNUnaryTestsMapper.java +++ b/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/DMNUnaryTestsMapper.java @@ -35,6 +35,7 @@ import org.kie.dmn.feel.lang.ast.UnaryTestListNode; import org.kie.dmn.feel.lang.ast.UnaryTestNode; import org.kie.dmn.feel.lang.ast.visitor.ASTTemporalConstantVisitor; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.FEELEventListenersManager; import org.kie.dmn.feel.parser.feel11.ASTBuilderVisitor; import org.kie.dmn.feel.parser.feel11.FEELParser; @@ -89,7 +90,7 @@ static List getUnaryEvaluationNodesFromUnaryTests(List u static BaseNode getBaseNode(String expression) { LOG.debug("getBaseNode {}", expression); - FEEL feelInstance = FEEL.newInstance(); + FEEL feelInstance = FEELBuilder.builder().build(); CompilerContext ctx = feelInstance.newCompilerContext(); ParseTree tree = getFEELParser(expression, ctx).unaryTestsRoot(); ASTBuilderVisitor astVisitor = new ASTBuilderVisitor(ctx.getInputVariableTypes(), diff --git a/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/MapperHelper.java b/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/MapperHelper.java index 83b596c05e0..b510b8f78a5 100644 --- a/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/MapperHelper.java +++ b/kie-dmn/kie-dmn-openapi/src/main/java/org/kie/dmn/openapi/impl/MapperHelper.java @@ -18,6 +18,7 @@ */ package org.kie.dmn.openapi.impl; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.ast.AtLiteralNode; import org.kie.dmn.feel.lang.ast.InfixOpNode; import org.kie.dmn.feel.lang.impl.EvaluationContextImpl; @@ -29,11 +30,13 @@ public class MapperHelper { static Object evaluateInfixOpNode(InfixOpNode toEvaluate) { - return toEvaluate.evaluate(new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null)); + //TODO GC 1659 + return toEvaluate.evaluate(new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null, FEELDialect.FEEL)); } static Object evaluateAtLiteralNode(AtLiteralNode toEvaluate) { - return toEvaluate.evaluate(new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null)); + //TODO GC 1659 + return toEvaluate.evaluate(new EvaluationContextImpl(ClassLoaderUtil.findDefaultClassLoader(), null, FEELDialect.FEEL)); } private MapperHelper() { diff --git a/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/RangeNodeSchemaMapperTest.java b/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/RangeNodeSchemaMapperTest.java index fb4e2369d43..2035dc3f6fb 100644 --- a/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/RangeNodeSchemaMapperTest.java +++ b/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/RangeNodeSchemaMapperTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test; import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.ast.RangeNode; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.impl.RangeImpl; @@ -39,7 +40,7 @@ class RangeNodeSchemaMapperTest { - private static final FEEL feel = FEEL.newInstance(); + private static final FEEL feel = FEELBuilder.builder().build(); @Test void evaluateUnaryTestsForNumberRange() { diff --git a/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/SchemaMapperTestUtils.java b/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/SchemaMapperTestUtils.java index b9a71f51cfb..3162fe04d2b 100644 --- a/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/SchemaMapperTestUtils.java +++ b/kie-dmn/kie-dmn-openapi/src/test/java/org/kie/dmn/openapi/impl/SchemaMapperTestUtils.java @@ -29,13 +29,14 @@ import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.codegen.feel11.ProcessedExpression; import org.kie.dmn.feel.lang.ast.BaseNode; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.UnaryTest; import org.kie.dmn.model.v1_5.KieDMNModelInstrumentedBase; class SchemaMapperTestUtils { - static final FEEL feel = FEEL.newInstance(); + static final FEEL feel = FEELBuilder.builder().build(); static final DMNTypeRegistry typeRegistry = new DMNTypeRegistryV15(Collections.emptyMap()); static final DMNType FEEL_STRING = typeRegistry.resolveType(KieDMNModelInstrumentedBase.URI_FEEL, "string"); diff --git a/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/feel/runtime/ExtendedFunctionsBaseFEELTest.java b/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/feel/runtime/ExtendedFunctionsBaseFEELTest.java index 45c813bf730..cf9e9569d1a 100644 --- a/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/feel/runtime/ExtendedFunctionsBaseFEELTest.java +++ b/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/feel/runtime/ExtendedFunctionsBaseFEELTest.java @@ -23,6 +23,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEventListener; import org.kie.dmn.feel.FEEL; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.signavio.KieDMNSignavioProfile; import org.mockito.ArgumentCaptor; @@ -35,7 +36,7 @@ public abstract class ExtendedFunctionsBaseFEELTest { - private final FEEL feel = FEEL.newInstance(List.of(new KieDMNSignavioProfile())); + private final FEEL feel = FEELBuilder.builder().withProfiles(List.of(new KieDMNSignavioProfile())).build(); public String expression; 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 aaf4fbe81e1..84bdbc3683b 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 @@ -56,6 +56,7 @@ import org.kie.dmn.feel.lang.ast.UnaryTestNode; import org.kie.dmn.feel.lang.ast.UnaryTestNode.UnaryOperator; import org.kie.dmn.feel.lang.ast.Visitor; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.InterpretedExecutableExpression; import org.kie.dmn.feel.lang.impl.UnaryTestInterpretedExecutableExpression; import org.kie.dmn.feel.lang.types.BuiltInType; @@ -100,7 +101,7 @@ public class DMNDTAnalyser implements InternalDMNDTAnalyser { private final DMNDTAnalyserOutputClauseVisitor outputClauseVisitor; public DMNDTAnalyser(List dmnProfiles) { - FEEL = org.kie.dmn.feel.FEEL.newInstance((List) dmnProfiles); + FEEL = FEELBuilder.builder().withProfiles((List) dmnProfiles).build(); valueFromNodeVisitor = new DMNDTAnalyserValueFromNodeVisitor((List) dmnProfiles); outputClauseVisitor = new DMNDTAnalyserOutputClauseVisitor((List) dmnProfiles); } @@ -222,7 +223,7 @@ private void compileTableRules(DMNModel model, DecisionTable dt, DDTATable ddtaT DDTARule ddtaRule = new DDTARule(); int jColIdx = 0; for (UnaryTests ie : r.getInputEntry()) { - ProcessedUnaryTest compileUnaryTests = (ProcessedUnaryTest) FEEL.compileUnaryTests(ie.getText(), feelCtx(model, dt)); + ProcessedUnaryTest compileUnaryTests = (ProcessedUnaryTest) FEEL.processUnaryTests(ie.getText(), feelCtx(model, dt)); UnaryTestInterpretedExecutableExpression interpreted = compileUnaryTests.getInterpreted(); if (interpreted == UnaryTestInterpretedExecutableExpression.EMPTY) { throw new DMNDTAnalysisException("Gaps/Overlaps analysis cannot be performed for InputEntry with unary test containing: " + ie.getText(), dt); @@ -330,7 +331,7 @@ private void compileTableInputClauses(DMNModel model, DecisionTable dt, DDTATabl allowedValues = findAllowedValues(model, typeRef); } if (allowedValues != null) { - ProcessedUnaryTest compileUnaryTests = (ProcessedUnaryTest) FEEL.compileUnaryTests(allowedValues, FEEL.newCompilerContext()); + ProcessedUnaryTest compileUnaryTests = (ProcessedUnaryTest) FEEL.processUnaryTests(allowedValues, FEEL.newCompilerContext()); UnaryTestInterpretedExecutableExpression interpreted = compileUnaryTests.getInterpreted(); UnaryTestListNode utln = (UnaryTestListNode) interpreted.getASTNode(); List utlnElements = new ArrayList<>(utln.getElements()); @@ -389,7 +390,7 @@ private void compileTableOutputClauses(DMNModel model, DecisionTable dt, DDTATab } } if (allowedValues != null) { - ProcessedUnaryTest compileUnaryTests = (ProcessedUnaryTest) FEEL.compileUnaryTests(allowedValues, FEEL.newCompilerContext()); + ProcessedUnaryTest compileUnaryTests = (ProcessedUnaryTest) FEEL.processUnaryTests(allowedValues, FEEL.newCompilerContext()); UnaryTestInterpretedExecutableExpression interpreted = compileUnaryTests.getInterpreted(); UnaryTestListNode utln = (UnaryTestListNode) interpreted.getASTNode(); List utlnElements = new ArrayList<>(utln.getElements()); diff --git a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java index ac2a56f9c48..ebce9941874 100644 --- a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java +++ b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java @@ -34,6 +34,7 @@ import org.kie.dmn.feel.lang.ast.SignedUnaryNode.Sign; import org.kie.dmn.feel.lang.ast.StringNode; import org.kie.dmn.feel.lang.ast.visitor.DefaultedVisitor; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.FEELImpl; import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.validation.dtanalysis.model.DDTAOutputEntryExpression; @@ -51,7 +52,7 @@ public class DMNDTAnalyserValueFromNodeVisitor extends DefaultedVisitor feelProfiles) { - FEEL = (FEELImpl) org.kie.dmn.feel.FEEL.newInstance(feelProfiles); + FEEL = (FEELImpl) FEELBuilder.builder().withProfiles(feelProfiles).build(); } @Override diff --git a/kie-dmn/kie-dmn-validation/src/test/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitorTest.java b/kie-dmn/kie-dmn-validation/src/test/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitorTest.java index 40698a1cbf6..2c7a56f6e33 100644 --- a/kie-dmn/kie-dmn-validation/src/test/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitorTest.java +++ b/kie-dmn/kie-dmn-validation/src/test/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitorTest.java @@ -21,14 +21,15 @@ import java.util.Collections; import org.junit.jupiter.api.Test; +import org.kie.dmn.feel.FEEL; import org.kie.dmn.feel.lang.ast.FunctionInvocationNode; -import org.kie.dmn.feel.lang.impl.FEELImpl; +import org.kie.dmn.feel.lang.impl.FEELBuilder; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; class DMNDTAnalyserValueFromNodeVisitorTest { - private final FEELImpl tFEEL = (FEELImpl) org.kie.dmn.feel.FEEL.newInstance(); + private final FEEL tFEEL = FEELBuilder.builder().build(); /** * None of these are valid FEEL expression ootb and cannot be used to determine discrete value in the domain @@ -47,6 +48,6 @@ void smokeTest() { } private FunctionInvocationNode compile(String fnInvFEEL) { - return (FunctionInvocationNode) tFEEL.compileExpression(fnInvFEEL, tFEEL.newCompilerContext()).getInterpreted().getASTNode(); + return (FunctionInvocationNode) tFEEL.processExpression(fnInvFEEL, tFEEL.newCompilerContext()).getInterpreted().getASTNode(); } } From b08b4f7f5939558e102561bfbb93d68fc6f3141e Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Fri, 10 May 2024 12:20:51 +0200 Subject: [PATCH 02/10] [incubator-kie-issues#1187] Split EvalHelper --- .../jsr223/JSR223ScriptEngineEvaluator.java | 4 +- .../kie/dmn/core/impl/BaseDMNTypeImpl.java | 4 +- .../kie/dmn/core/impl/CompositeTypeImpl.java | 3 +- .../utils/DynamicDMNContextBuilder.java | 4 +- .../DMNKiePMMLTrustyInvocationEvaluator.java | 6 +- .../org/kie/dmn/core/util/CoerceUtil.java | 4 +- .../java/org/kie/dmn/core/DMNRuntimeTest.java | 7 +- .../compiler/profiles/Just47Function.java | 4 +- ...NKiePMMLTrustyInvocationEvaluatorTest.java | 6 +- .../stronglytyped/DMNRuntimeTypesTest.java | 35 +- .../codegen/feel11/ASTCompilerVisitor.java | 6 +- .../feel11/CompiledFEELSemanticMappings.java | 25 +- .../codegen/feel11/CompiledFEELSupport.java | 24 +- .../dmn/feel/codegen/feel11/Constants.java | 2 +- .../dmn/feel/codegen/feel11/Expressions.java | 9 +- .../kie/dmn/feel/lang/ast/BetweenNode.java | 12 +- .../kie/dmn/feel/lang/ast/ContextNode.java | 4 +- .../kie/dmn/feel/lang/ast/NameDefNode.java | 8 +- .../org/kie/dmn/feel/lang/ast/NumberNode.java | 8 +- .../dmn/feel/lang/ast/QualifiedNameNode.java | 13 +- .../dmn/feel/lang/ast/SignedUnaryNode.java | 10 +- .../org/kie/dmn/feel/lang/ast/StringNode.java | 4 +- .../kie/dmn/feel/lang/ast/UnaryTestNode.java | 11 +- .../lang/ast/infixexecutors/AddExecutor.java | 2 +- .../lang/ast/infixexecutors/AndExecutor.java | 8 +- .../lang/ast/infixexecutors/DivExecutor.java | 2 +- .../lang/ast/infixexecutors/EqExecutor.java | 4 +- .../lang/ast/infixexecutors/GtExecutor.java | 4 +- .../lang/ast/infixexecutors/GteExecutor.java | 8 +- .../infixexecutors/InfixExecutorUtils.java | 33 +- .../lang/ast/infixexecutors/LtExecutor.java | 4 +- .../lang/ast/infixexecutors/LteExecutor.java | 8 +- .../lang/ast/infixexecutors/MultExecutor.java | 2 +- .../lang/ast/infixexecutors/NeExecutor.java | 4 +- .../lang/ast/infixexecutors/OrExecutor.java | 7 +- .../lang/ast/infixexecutors/SubExecutor.java | 2 +- .../visitor/ASTTemporalConstantVisitor.java | 10 +- .../feel/lang/impl/EvaluationContextImpl.java | 4 +- .../feel/lang/impl/ExecutionFrameImpl.java | 7 +- .../feel/lang/impl/RootExecutionFrame.java | 8 +- .../kie/dmn/feel/lang/types/ScopeImpl.java | 9 +- .../feel/parser/feel11/ASTBuilderVisitor.java | 4 +- .../dmn/feel/parser/feel11/ParserHelper.java | 4 +- .../runtime/functions/BaseFEELFunction.java | 6 +- .../runtime/functions/DayOfYearFunction.java | 4 +- .../feel/runtime/functions/IsFunction.java | 7 +- .../functions/ListContainsFunction.java | 9 +- .../functions/ListReplaceFunction.java | 6 +- .../feel/runtime/functions/MeanFunction.java | 5 +- .../feel/runtime/functions/ModeFunction.java | 4 +- .../runtime/functions/NumberFunction.java | 4 +- .../runtime/functions/ProductFunction.java | 6 +- .../feel/runtime/functions/SqrtFunction.java | 10 +- .../runtime/functions/StddevFunction.java | 5 +- .../functions/StringLengthFunction.java | 4 +- .../feel/runtime/functions/SumFunction.java | 5 +- .../runtime/functions/WeekOfYearFunction.java | 3 +- .../twovaluelogic/NNMeanFunction.java | 16 +- .../twovaluelogic/NNMedianFunction.java | 16 +- .../twovaluelogic/NNModeFunction.java | 16 +- .../twovaluelogic/NNStddevFunction.java | 6 +- .../twovaluelogic/NNSumFunction.java | 14 +- .../kie/dmn/feel/runtime/impl/RangeImpl.java | 4 +- .../kie/dmn/feel/util/BooleanEvalHelper.java | 224 +++++++++ .../org/kie/dmn/feel/util/CoerceUtil.java | 4 +- .../kie/dmn/feel/util/DateTimeEvalHelper.java | 73 +++ .../org/kie/dmn/feel/util/EvalHelper.java | 471 +----------------- .../kie/dmn/feel/util/NumberEvalHelper.java | 77 +++ .../kie/dmn/feel/util/StringEvalHelper.java | 216 ++++++++ .../feel11/DirectCompilerUnaryTestsTest.java | 4 +- .../codegen/feel11/ManualUnaryTestsTest.java | 4 +- .../org/kie/dmn/feel/runtime/BFEELTest.java | 48 -- .../runtime/FEEL12ExtendedForLoopTest.java | 4 +- .../feel/runtime/FEELMathOperationsTest.java | 4 +- .../feel/runtime/FEELNumberCoercionTest.java | 2 +- .../dmn/feel/util/BooleanEvalHelperTest.java | 47 ++ .../org/kie/dmn/feel/util/EvalHelperTest.java | 51 -- .../dmn/feel/util/NumberEvalHelperTest.java | 37 ++ .../dmn/feel/util/StringEvalHelperTest.java | 54 ++ .../tests/core/v1_1/DMNRuntimeTest.java | 6 +- .../org/kie/dmn/ruleset2dmn/Converter.java | 6 +- .../signavio/MultiInstanceDecisionLogic.java | 5 +- .../runtime/functions/DayDiffFunction.java | 4 +- .../feel/runtime/functions/DayFunction.java | 18 +- .../runtime/functions/HourDiffFunction.java | 18 +- .../feel/runtime/functions/HourFunction.java | 16 +- .../runtime/functions/MinuteFunction.java | 16 +- .../functions/MinutesDiffFunction.java | 18 +- .../runtime/functions/MonthDiffFunction.java | 4 +- .../feel/runtime/functions/MonthFunction.java | 18 +- .../runtime/functions/ProductFunction.java | 14 +- .../runtime/functions/SecondFunction.java | 16 +- .../functions/SecondsDiffFunction.java | 18 +- .../functions/TextOccurrencesFunction.java | 4 +- .../runtime/functions/WeekdayFunction.java | 18 +- .../runtime/functions/YearDiffFunction.java | 4 +- .../feel/runtime/functions/YearFunction.java | 18 +- .../DMNDTAnalyserValueFromNodeVisitor.java | 4 +- 98 files changed, 1116 insertions(+), 926 deletions(-) create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/StringEvalHelper.java delete mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java create mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java create mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java create mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/StringEvalHelperTest.java diff --git a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223ScriptEngineEvaluator.java b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223ScriptEngineEvaluator.java index 950526a97bc..55e60faa5cd 100644 --- a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223ScriptEngineEvaluator.java +++ b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223ScriptEngineEvaluator.java @@ -30,7 +30,7 @@ import javax.script.ScriptException; import org.kie.dmn.feel.runtime.FEELFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,7 +62,7 @@ public Object eval(Map ins) throws ScriptException { Bindings engineScope = createBindings(ins); Object result = scriptEngine.eval(expression, engineScope); LOG.debug("Script eval of '{}' result: {}", expression, result); - return EvalHelper.coerceNumber(result); + return NumberEvalHelper.coerceNumber(result); } /** diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/BaseDMNTypeImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/BaseDMNTypeImpl.java index d83039246e1..f2342219b88 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/BaseDMNTypeImpl.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/BaseDMNTypeImpl.java @@ -28,7 +28,7 @@ import org.kie.dmn.core.compiler.DMNFEELHelper; import org.kie.dmn.feel.lang.Type; import org.kie.dmn.feel.runtime.UnaryTest; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; /** * @see DMNType @@ -190,7 +190,7 @@ private boolean valueMatchesInUnaryTests(List unaryTests, Object o) if ( unaryTests == null || unaryTests.isEmpty() ) { return true; } else { - return DMNFEELHelper.valueMatchesInUnaryTests(unaryTests, EvalHelper.coerceNumber(o), null); + return DMNFEELHelper.valueMatchesInUnaryTests(unaryTests, NumberEvalHelper.coerceNumber(o), null); } } diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java index 3f82ad85b47..7f426ed51de 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/CompositeTypeImpl.java @@ -32,6 +32,7 @@ import org.kie.dmn.feel.lang.types.GenListType; import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.EvalHelper.PropertyValueResult; +import org.kie.dmn.feel.util.NumberEvalHelper; /** * @see DMNType @@ -120,7 +121,7 @@ protected boolean internalIsInstanceOf(Object o) { } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { return false; } - Object fieldValue = EvalHelper.coerceNumber( invoked ); + Object fieldValue = NumberEvalHelper.coerceNumber(invoked ); if ( !f.getValue().isInstanceOf( fieldValue ) ) { return false; } diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/internal/utils/DynamicDMNContextBuilder.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/internal/utils/DynamicDMNContextBuilder.java index de44fc053bd..f225180cbf1 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/internal/utils/DynamicDMNContextBuilder.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/internal/utils/DynamicDMNContextBuilder.java @@ -41,7 +41,7 @@ import org.kie.dmn.feel.runtime.functions.DateFunction; import org.kie.dmn.feel.runtime.functions.DurationFunction; import org.kie.dmn.feel.runtime.functions.TimeFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.typesafe.DMNTypeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -190,7 +190,7 @@ private Object getAsFEELBuiltinType(Object value, DMNType resultType) { case BOOLEAN: return value; case NUMBER: - return EvalHelper.getBigDecimalOrNull(value); + return NumberEvalHelper.getBigDecimalOrNull(value); case STRING: return value; case DURATION: diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluator.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluator.java index b7b15c9a130..9c989c6a1a2 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluator.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluator.java @@ -34,7 +34,7 @@ import org.kie.dmn.core.impl.DMNResultImpl; import org.kie.dmn.core.util.Msg; import org.kie.dmn.core.util.MsgUtil; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.model.api.DMNElement; import org.kie.efesto.common.api.identifiers.LocalUri; import org.kie.efesto.common.api.identifiers.ModelLocalUriId; @@ -105,7 +105,7 @@ protected Map getPredictedValues(PMML4Result pmml4Result, DMNRes Map toReturn = new HashMap<>(); String resultName = pmml4Result.getResultObjectName(); Object value = pmml4Result.getResultVariables().get(resultName); - toReturn.put(resultName, EvalHelper.coerceNumber(value)); + toReturn.put(resultName, NumberEvalHelper.coerceNumber(value)); return toReturn; } @@ -114,7 +114,7 @@ private void populateWithObject(Map toPopulate, String resultNam if (outputFieldNameFromInfo.isPresent()) { String name = outputFieldNameFromInfo.get(); try { - toPopulate.put(name, EvalHelper.coerceNumber(r)); + toPopulate.put(name, NumberEvalHelper.coerceNumber(r)); } catch (Exception e) { MsgUtil.reportMessage(LOG, DMNMessage.Severity.WARN, diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java index 0d59e4563fc..ca59a837874 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/util/CoerceUtil.java @@ -24,7 +24,7 @@ import org.kie.dmn.api.core.DMNType; import org.kie.dmn.core.impl.SimpleTypeImpl; import org.kie.dmn.feel.lang.types.BuiltInType; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.DateTimeEvalHelper; /** * Class used to centralize all coercion-related behavior @@ -51,7 +51,7 @@ static Object actualCoerceValue(DMNType requiredType, Object valueToCoerce) { if (valueToCoerce instanceof LocalDate localDate && requiredType instanceof SimpleTypeImpl simpleType && simpleType.getFeelType() == BuiltInType.DATE_TIME) { - return EvalHelper.coerceDateTime(localDate); + return DateTimeEvalHelper.coerceDateTime(localDate); } return toReturn; } diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java index 990c6bc1584..54891131773 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNRuntimeTest.java @@ -41,7 +41,6 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -74,7 +73,7 @@ import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.marshaller.FEELStringMarshaller; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.model.api.Decision; import org.kie.dmn.model.api.Definitions; import org.kie.dmn.model.api.ItemDefinition; @@ -1543,8 +1542,8 @@ void typeInferenceForNestedContextAnonymousEntry(boolean useExecModelCompiler) { final DMNContext result = dmnResult.getContext(); assertThat(dmnResult.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult.getMessages())).isFalse(); - assertThat( (List)result.get("My Decision")).asList().containsExactly( prototype( entry("Full Name", "Prof. John Doe"), entry("Age", EvalHelper.coerceNumber(33)) ), - prototype( entry("Full Name", "Prof. 47"), entry("Age", EvalHelper.coerceNumber(47)))); + assertThat( (List)result.get("My Decision")).asList().containsExactly( prototype( entry("Full Name", "Prof. John Doe"), entry("Age", NumberEvalHelper.coerceNumber(33)) ), + prototype( entry("Full Name", "Prof. 47"), entry("Age", NumberEvalHelper.coerceNumber(47)))); } @ParameterizedTest diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/profiles/Just47Function.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/profiles/Just47Function.java index 2ab2e453717..c4d8fdfee70 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/profiles/Just47Function.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/profiles/Just47Function.java @@ -22,7 +22,7 @@ import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class Just47Function extends BaseFEELFunction { @@ -31,7 +31,7 @@ public Just47Function() { } public FEELFnResult invoke(@ParameterName("ctx") EvaluationContext ctx) { - return FEELFnResult.ofResult(EvalHelper.coerceNumber(47)); + return FEELFnResult.ofResult(NumberEvalHelper.coerceNumber(47)); } @Override diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluatorTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluatorTest.java index d87c0e5bdb3..343f81eeee2 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluatorTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/pmml/DMNKiePMMLTrustyInvocationEvaluatorTest.java @@ -38,7 +38,7 @@ import org.kie.dmn.api.core.DMNResult; import org.kie.dmn.api.core.DMNRuntime; import org.kie.dmn.api.core.event.DMNRuntimeEventManager; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.model.api.DMNElement; import org.kie.efesto.common.api.model.GeneratedResources; import org.mockito.Mockito; @@ -112,7 +112,7 @@ void getOutputFieldValues() { resultVariables.forEach((s, value) -> { assertThat(retrieved).containsKey(s); Object retObject = retrieved.get(s); - Object expected = EvalHelper.coerceNumber(value); + Object expected = NumberEvalHelper.coerceNumber(value); assertThat(retObject).isEqualTo(expected); }); } @@ -125,7 +125,7 @@ void getPredictedValues() { Map retrieved = dmnKiePMMLTrustyInvocationEvaluator.getPredictedValues(result, null); assertThat(retrieved).containsKey(result.getResultObjectName()); Object retObject = retrieved.get(result.getResultObjectName()); - Object expected = EvalHelper.coerceNumber(value); + Object expected = NumberEvalHelper.coerceNumber(value); assertThat(retObject).isEqualTo(expected); }); } diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/stronglytyped/DMNRuntimeTypesTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/stronglytyped/DMNRuntimeTypesTest.java index 452c6cd2709..2e14a803bc3 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/stronglytyped/DMNRuntimeTypesTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/stronglytyped/DMNRuntimeTypesTest.java @@ -33,7 +33,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.core.DMNContext; @@ -50,7 +49,7 @@ import org.kie.dmn.core.v1_2.DMNDecisionServicesTest; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.runtime.FEELFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +57,7 @@ import static org.kie.dmn.core.util.DynamicTypeUtils.entry; import static org.kie.dmn.core.util.DynamicTypeUtils.mapOf; import static org.kie.dmn.core.util.DynamicTypeUtils.prototype; -import static org.kie.dmn.feel.util.EvalHelper.coerceNumber; +import static org.kie.dmn.feel.util.NumberEvalHelper.coerceNumber; public class DMNRuntimeTypesTest extends BaseVariantTest { @@ -606,11 +605,11 @@ void capitalLetterConflict(VariantTestConf conf) { FEELPropertyAccessible myPersonOut = (FEELPropertyAccessible) allProperties.get("myPerson"); assertThat(myPersonOut.getClass().getSimpleName()).isEqualTo("TPerson"); assertThat(myPersonOut.getFEELProperty("name").toOptional().get()).isEqualTo("John"); - assertThat(EvalHelper.coerceNumber(myPersonOut.getFEELProperty("age").toOptional().get())).isEqualTo(EvalHelper.coerceNumber(28)); + assertThat(NumberEvalHelper.coerceNumber(myPersonOut.getFEELProperty("age").toOptional().get())).isEqualTo(NumberEvalHelper.coerceNumber(28)); FEELPropertyAccessible myPersonCapitalOut = (FEELPropertyAccessible) allProperties.get("MyPerson"); assertThat(myPersonCapitalOut.getClass().getSimpleName()).isEqualTo("TPerson"); assertThat(myPersonCapitalOut.getFEELProperty("name").toOptional().get()).isEqualTo("Paul"); - assertThat(EvalHelper.coerceNumber(myPersonCapitalOut.getFEELProperty("age").toOptional().get())).isEqualTo(EvalHelper.coerceNumber(26)); + assertThat(NumberEvalHelper.coerceNumber(myPersonCapitalOut.getFEELProperty("age").toOptional().get())).isEqualTo(NumberEvalHelper.coerceNumber(26)); Object myDecision = allProperties.get("myDecision"); assertThat(myDecision).isEqualTo("myDecision is John"); Object myDecisionCapital = allProperties.get("MyDecision"); @@ -644,7 +643,7 @@ void capitalLetterConflictWithInputAndDecision(VariantTestConf conf) { FEELPropertyAccessible myPersonOut = (FEELPropertyAccessible) allProperties.get("myNode"); assertThat(myPersonOut.getClass().getSimpleName()).isEqualTo("TPerson"); assertThat(myPersonOut.getFEELProperty("name").toOptional().get()).isEqualTo("John"); - assertThat(EvalHelper.coerceNumber(myPersonOut.getFEELProperty("age").toOptional().get())).isEqualTo(EvalHelper.coerceNumber(28)); + assertThat(NumberEvalHelper.coerceNumber(myPersonOut.getFEELProperty("age").toOptional().get())).isEqualTo(NumberEvalHelper.coerceNumber(28)); Object myDecision = allProperties.get("MyNode"); assertThat(myDecision).isEqualTo("MyNode is John"); } @@ -746,13 +745,13 @@ void topLevelTypeCollection(VariantTestConf conf) { FEELPropertyAccessible person1 = personList.get(0); FEELPropertyAccessible person2 = personList.get(1); assertThat(person1.getFEELProperty("Full Name").toOptional().get()).isIn("Prof. John Doe", "Prof. 47"); - assertThat(person1.getFEELProperty("Age").toOptional().get()).isIn(EvalHelper.coerceNumber(33), EvalHelper.coerceNumber(47)); + assertThat(person1.getFEELProperty("Age").toOptional().get()).isIn(NumberEvalHelper.coerceNumber(33), NumberEvalHelper.coerceNumber(47)); assertThat(person2.getFEELProperty("Full Name").toOptional().get()).isIn("Prof. John Doe", "Prof. 47"); - assertThat(person2.getFEELProperty("Age").toOptional().get()).isIn(EvalHelper.coerceNumber(33), EvalHelper.coerceNumber(47)); + assertThat(person2.getFEELProperty("Age").toOptional().get()).isIn(NumberEvalHelper.coerceNumber(33), NumberEvalHelper.coerceNumber(47)); } else { assertThat((List) dmnResult.getContext().get("My Decision")).asList(). - contains(prototype(entry("Full Name", "Prof. John Doe"), entry("Age", EvalHelper.coerceNumber(33))), - prototype(entry("Full Name", "Prof. 47"), entry("Age", EvalHelper.coerceNumber(47)))); + contains(prototype(entry("Full Name", "Prof. John Doe"), entry("Age", NumberEvalHelper.coerceNumber(33))), + prototype(entry("Full Name", "Prof. 47"), entry("Age", NumberEvalHelper.coerceNumber(47)))); } } @@ -784,13 +783,13 @@ void topLevelCompositeCollection(VariantTestConf conf) { FEELPropertyAccessible pair1 = pairList.get(0); FEELPropertyAccessible pair2 = pairList.get(1); assertThat(pair1.getFEELProperty("letter").toOptional().get()).isIn("ABC", "DEF"); - assertThat(pair1.getFEELProperty("num").toOptional().get()).isIn(EvalHelper.coerceNumber(123), EvalHelper.coerceNumber(456)); + assertThat(pair1.getFEELProperty("num").toOptional().get()).isIn(NumberEvalHelper.coerceNumber(123), NumberEvalHelper.coerceNumber(456)); assertThat(pair2.getFEELProperty("letter").toOptional().get()).isIn("ABC", "DEF"); - assertThat(pair2.getFEELProperty("num").toOptional().get()).isIn(EvalHelper.coerceNumber(123), EvalHelper.coerceNumber(456)); + assertThat(pair2.getFEELProperty("num").toOptional().get()).isIn(NumberEvalHelper.coerceNumber(123), NumberEvalHelper.coerceNumber(456)); } else { assertThat((List) dmnResult.getContext().get("Decision-1")).asList(). - contains(mapOf(entry("letter", "ABC"), entry("num", EvalHelper.coerceNumber(123))), - mapOf(entry("letter", "DEF"), entry("num", EvalHelper.coerceNumber(456)))); + contains(mapOf(entry("letter", "ABC"), entry("num", NumberEvalHelper.coerceNumber(123))), + mapOf(entry("letter", "DEF"), entry("num", NumberEvalHelper.coerceNumber(456)))); } } @@ -913,13 +912,13 @@ void evaluateByIdAndName(VariantTestConf conf) { FEELPropertyAccessible person = (FEELPropertyAccessible)allProperties.get("Decision-1"); assertThat(person.getClass().getSimpleName()).isEqualTo("TPerson"); assertThat(person.getFEELProperty("name").toOptional().get()).isEqualTo("Paul"); - assertThat(person.getFEELProperty("age").toOptional().get()).isEqualTo(EvalHelper.coerceNumber(28)); + assertThat(person.getFEELProperty("age").toOptional().get()).isEqualTo(NumberEvalHelper.coerceNumber(28)); assertThat(allProperties.get("Decision-2")).isNull(); } else { Map person = (Map)dmnResult1.getContext().get("Decision-1"); assertThat(person.get("name")).isEqualTo("Paul"); - assertThat(person.get("age")).isEqualTo(EvalHelper.coerceNumber(28)); + assertThat(person.get("age")).isEqualTo(NumberEvalHelper.coerceNumber(28)); assertThat(dmnResult1.getContext().get("Decision-2")).isNull(); } @@ -934,13 +933,13 @@ void evaluateByIdAndName(VariantTestConf conf) { FEELPropertyAccessible person = (FEELPropertyAccessible)allProperties.get("Decision-2"); assertThat(person.getClass().getSimpleName()).isEqualTo("TPerson"); assertThat(person.getFEELProperty("name").toOptional().get()).isEqualTo("George"); - assertThat(person.getFEELProperty("age").toOptional().get()).isEqualTo(EvalHelper.coerceNumber(27)); + assertThat(person.getFEELProperty("age").toOptional().get()).isEqualTo(NumberEvalHelper.coerceNumber(27)); assertThat(allProperties.get("Decision-1")).isNull(); } else { Map person = (Map)dmnResult2.getContext().get("Decision-2"); assertThat(person.get("name")).isEqualTo("George"); - assertThat(person.get("age")).isEqualTo(EvalHelper.coerceNumber(27)); + assertThat(person.get("age")).isEqualTo(NumberEvalHelper.coerceNumber(27)); assertThat(dmnResult2.getContext().get("Decision-1")).isNull(); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java index 7a6824a116a..da960bd7990 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/ASTCompilerVisitor.java @@ -90,8 +90,8 @@ import org.kie.dmn.feel.lang.impl.MapBackedType; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.parser.feel11.ScopeHelper; -import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.Msg; +import org.kie.dmn.feel.util.StringEvalHelper; import static org.kie.dmn.feel.codegen.feel11.DirectCompilerResult.mergeFDs; @@ -181,13 +181,13 @@ public DirectCompilerResult visit(NullNode n) { @Override public DirectCompilerResult visit(NameDefNode n) { - StringLiteralExpr expr = Expressions.stringLiteral(EvalHelper.normalizeVariableName(n.getText())); + StringLiteralExpr expr = Expressions.stringLiteral(StringEvalHelper.normalizeVariableName(n.getText())); return DirectCompilerResult.of(expr, BuiltInType.STRING); } @Override public DirectCompilerResult visit(NameRefNode n) { - String nameRef = EvalHelper.normalizeVariableName(n.getText()); + String nameRef = StringEvalHelper.normalizeVariableName(n.getText()); Type type = scopeHelper.resolve(nameRef).orElse(BuiltInType.UNKNOWN); return DirectCompilerResult.of(FeelCtx.getValue(nameRef), type); } 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 78326a136ff..21247c33311 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,6 +18,12 @@ */ package org.kie.dmn.feel.codegen.feel11; +import java.time.Period; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOperator; @@ -27,15 +33,10 @@ import org.kie.dmn.feel.runtime.events.ASTEventBase; import org.kie.dmn.feel.runtime.functions.ListContainsFunction; import org.kie.dmn.feel.runtime.impl.RangeImpl; +import org.kie.dmn.feel.util.BooleanEvalHelper; 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 @@ -286,7 +287,7 @@ public static Boolean and(Boolean left, Supplier right) { public static Boolean and(boolean left, Object right) { if (left == true) { - return EvalHelper.getBooleanOrNull(right); + return BooleanEvalHelper.getBooleanOrNull(right); } else { return false; } @@ -324,7 +325,7 @@ public static Boolean or(Object left, boolean right) { if (right == true) { return true; } else { - return EvalHelper.getBooleanOrNull(left); + return BooleanEvalHelper.getBooleanOrNull(left); } } @@ -382,7 +383,7 @@ public static Boolean lte(Object left, Object right) { * Delegates to {@link EvalHelper} except evaluationcontext */ public static Boolean lt(Object left, Object right) { - return EvalHelper.compare(left, right, null, (l, r) -> l.compareTo(r) < 0); + return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) < 0); } /** @@ -399,7 +400,7 @@ public static Boolean gte(Object left, Object right) { * Delegates to {@link EvalHelper} except evaluationcontext */ public static Boolean gt(Object left, Object right) { - return EvalHelper.compare(left, right, null, (l, r) -> l.compareTo(r) > 0); + return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) > 0); } /** @@ -407,7 +408,7 @@ public static Boolean gt(Object left, Object right) { * Delegates to {@link EvalHelper} except evaluationcontext */ public static Boolean eq(Object left, Object right) { - return EvalHelper.isEqual(left, right, null); + return BooleanEvalHelper.isEqual(left, right); } public static Boolean gracefulEq(EvaluationContext ctx, Object left, Object right) { @@ -448,7 +449,7 @@ public static Boolean between(EvaluationContext ctx, * FEEL spec Table 39 */ public static Boolean ne(Object left, Object right) { - return not(EvalHelper.isEqual(left, right, null)); + return not(BooleanEvalHelper.isEqual(left, right)); } public static Object negateTest(Object param) { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java index 7b64e8000ba..aed762f5d36 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java @@ -18,6 +18,16 @@ */ package org.kie.dmn.feel.codegen.feel11; +import java.math.BigDecimal; +import java.math.MathContext; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import ch.obermuhlner.math.big.BigDecimalMath; import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.NodeList; @@ -56,17 +66,7 @@ import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.Msg; import org.kie.dmn.feel.util.MsgUtil; - -import java.math.BigDecimal; -import java.math.MathContext; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; import static com.github.javaparser.StaticJavaParser.parseClassOrInterfaceType; import static org.kie.dmn.feel.codegen.feel11.Expressions.compiledFeelSemanticMappingsFQN; @@ -460,7 +460,7 @@ public static Object notifyCompilationError(EvaluationContext feelExprCtx, Strin } public static Object coerceNumber(Object value) { - return EvalHelper.coerceNumber(value); + return NumberEvalHelper.coerceNumber(value); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Constants.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Constants.java index 411934f4dca..b3319d8137f 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Constants.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/Constants.java @@ -64,7 +64,7 @@ public static FieldDeclaration numeric(String name, String numericValue) { String originalText = numericValue; try { Long.parseLong(originalText); - initializer.addArgument(originalText.replaceFirst("^0+(?!$)", "")); // see EvalHelper.getBigDecimalOrNull + initializer.addArgument(originalText.replaceFirst("^0+(?!$)", "")); // see NumberEvalHelper.getBigDecimalOrNull } catch (Throwable t) { initializer.addArgument(new StringLiteralExpr(originalText)); } 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 b2ae13201f2..404db681118 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,13 +39,16 @@ 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.*; +import org.kie.dmn.feel.lang.ast.InfixOperator; +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.impl.MapBackedType; import org.kie.dmn.feel.lang.impl.NamedParameter; import org.kie.dmn.feel.lang.types.GenFnType; import org.kie.dmn.feel.lang.types.GenListType; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; import static com.github.javaparser.StaticJavaParser.parseClassOrInterfaceType; import static com.github.javaparser.StaticJavaParser.parseExpression; @@ -440,7 +443,7 @@ public static Expression contains(Expression expr, Expression value) { public static StringLiteralExpr stringLiteral(String text) { if (text.startsWith("\"") && text.endsWith("\"")) { String actualStringContent = text.substring(1, text.length() - 1); // remove start/end " from the FEEL text expression. - String unescaped = EvalHelper.unescapeString(actualStringContent); // unescapes String, FEEL-style + String unescaped = StringEvalHelper.unescapeString(actualStringContent); // unescapes String, FEEL-style return new StringLiteralExpr().setString(unescaped); // setString escapes the contents Java-style } else { return new StringLiteralExpr().setString(text); 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 383c107cb83..bc8d5c50bcf 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 @@ -24,7 +24,7 @@ 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.BooleanEvalHelper; import org.kie.dmn.feel.util.Msg; public class BetweenNode @@ -99,15 +99,15 @@ public Object evaluate(EvaluationContext ctx) { } if (problem) return null; - 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. + Object gte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_s, (l, r) -> l.compareTo(r) > 0), + BooleanEvalHelper.isEqual(o_val, o_s), + 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 = InfixExecutorUtils.or(EvalHelper.compare(o_val, o_e, ctx, (l, r) -> l.compareTo(r) < 0), - EvalHelper.isEqual(o_val, o_e, ctx), + Object lte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_e, (l, r) -> l.compareTo(r) < 0), + BooleanEvalHelper.isEqual(o_val, o_e), 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"))); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ContextNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ContextNode.java index b344841fc27..898d0d705b8 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ContextNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/ContextNode.java @@ -31,8 +31,8 @@ import org.kie.dmn.feel.runtime.functions.CustomFEELFunction; import org.kie.dmn.feel.runtime.functions.DTInvokerFunction; import org.kie.dmn.feel.runtime.functions.JavaFunction; -import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.Msg; +import org.kie.dmn.feel.util.StringEvalHelper; public class ContextNode extends BaseNode { @@ -67,7 +67,7 @@ public Object evaluate(EvaluationContext ctx) { ctx.enterFrame(); Map c = new LinkedHashMap<>(); for( ContextEntryNode cen : entries ) { - String name = EvalHelper.normalizeVariableName( cen.evaluateName( ctx ) ); + String name = StringEvalHelper.normalizeVariableName(cen.evaluateName(ctx ) ); if (c.containsKey(name)) { ctx.notifyEvt( astEvent( FEELEvent.Severity.ERROR, Msg.createMessage( Msg.DUPLICATE_KEY_CTX, name)) ); return null; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NameDefNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NameDefNode.java index d16e9ef6c93..7633981c136 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NameDefNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NameDefNode.java @@ -18,11 +18,11 @@ */ package org.kie.dmn.feel.lang.ast; +import java.util.List; + import org.antlr.v4.runtime.ParserRuleContext; import org.kie.dmn.feel.lang.EvaluationContext; -import org.kie.dmn.feel.util.EvalHelper; - -import java.util.List; +import org.kie.dmn.feel.util.StringEvalHelper; /** * A name is defined either as a sequence of @@ -64,7 +64,7 @@ public void setName(String name) { @Override public String evaluate(EvaluationContext ctx) { - return EvalHelper.normalizeVariableName( getText() ); + return StringEvalHelper.normalizeVariableName(getText() ); } @Override diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NumberNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NumberNode.java index 83be6d4e3aa..c03f7f585c3 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NumberNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/NumberNode.java @@ -18,13 +18,13 @@ */ package org.kie.dmn.feel.lang.ast; +import java.math.BigDecimal; + import org.antlr.v4.runtime.ParserRuleContext; 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.util.EvalHelper; - -import java.math.BigDecimal; +import org.kie.dmn.feel.util.NumberEvalHelper; public class NumberNode extends BaseNode { @@ -33,7 +33,7 @@ public class NumberNode public NumberNode(ParserRuleContext ctx) { super( ctx ); - value = EvalHelper.getBigDecimalOrNull( ctx.getText() ); + value = NumberEvalHelper.getBigDecimalOrNull(ctx.getText() ); } public BigDecimal getValue() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/QualifiedNameNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/QualifiedNameNode.java index 79a12fb0e70..e36d821f5f7 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/QualifiedNameNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/QualifiedNameNode.java @@ -18,16 +18,17 @@ */ package org.kie.dmn.feel.lang.ast; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + 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.util.EvalHelper; import org.kie.dmn.feel.util.Msg; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import org.kie.dmn.feel.util.StringEvalHelper; public class QualifiedNameNode extends BaseNode { @@ -65,11 +66,11 @@ public Object evaluate(EvaluationContext ctx) { // can't use Stream API as from EvalHelper.getValue I need to listen for checked exception Collection result = new ArrayList<>(); for ( Object e : (Collection) current ) { - result.add( EvalHelper.getValue( e, EvalHelper.normalizeVariableName( n ) ) ); + result.add( EvalHelper.getValue(e, StringEvalHelper.normalizeVariableName(n ) ) ); } current = result; } else { - current = EvalHelper.getValue( current, EvalHelper.normalizeVariableName( n ) ); + current = EvalHelper.getValue( current, StringEvalHelper.normalizeVariableName( n ) ); } } return current; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/SignedUnaryNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/SignedUnaryNode.java index be40367eafb..e0d64f2c48b 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/SignedUnaryNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/SignedUnaryNode.java @@ -18,16 +18,16 @@ */ package org.kie.dmn.feel.lang.ast; +import java.math.BigDecimal; +import java.time.Duration; + 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.types.impl.ComparablePeriod; -import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.Msg; - -import java.math.BigDecimal; -import java.time.Duration; +import org.kie.dmn.feel.util.NumberEvalHelper; public class SignedUnaryNode extends BaseNode { @@ -76,7 +76,7 @@ public Object evaluate(EvaluationContext ctx) { if (expressionResult instanceof Duration duration) { return Sign.NEGATIVE == sign ? duration.negated() : expressionResult; } - BigDecimal result = EvalHelper.getBigDecimalOrNull( expressionResult ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull(expressionResult ); if ( result == null ) { ctx.notifyEvt( astEvent(Severity.WARN, Msg.createMessage(Msg.NEGATING_A_NULL))); return null; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/StringNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/StringNode.java index c179d203c58..627f8c6c840 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/StringNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/StringNode.java @@ -22,14 +22,14 @@ 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.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; public class StringNode extends BaseNode { private final String value; public StringNode(ParserRuleContext ctx) { super( ctx ); - this.value = EvalHelper.unescapeString(getText()); + this.value = StringEvalHelper.unescapeString(getText()); } @Override diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java index 58b0ae473d5..a3dafdd8818 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java @@ -28,6 +28,7 @@ import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.UnaryTest; import org.kie.dmn.feel.runtime.UnaryTestImpl; +import org.kie.dmn.feel.util.BooleanEvalHelper; import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.Msg; @@ -129,7 +130,7 @@ public UnaryTest evaluate(EvaluationContext ctx) { private UnaryTest createCompareUnaryTest( BiPredicate op ) { return (context, left) -> { Object right = value.evaluate( context ); - return EvalHelper.compare( left, right, context, op ); + return BooleanEvalHelper.compare(left, right, op ); }; } @@ -138,26 +139,26 @@ private UnaryTest createCompareUnaryTest( BiPredicate op * If the RIGHT is NOT a list, then standard equals semantic applies * If the RIGHT is a LIST, then the semantic is "right contains left" */ - private Boolean utEqualSemantic(Object left, Object right, EvaluationContext context) { + private Boolean utEqualSemantic(Object left, Object right) { if (right instanceof Collection) { return ((Collection) right).contains(left); } else { // evaluate single entity - return EvalHelper.isEqual(left, right, context); + return BooleanEvalHelper.isEqual(left, right); } } private UnaryTest createIsEqualUnaryTest( ) { return (context, left) -> { Object right = value.evaluate( context ); - return utEqualSemantic(left, right, context); + return utEqualSemantic(left, right); }; } private UnaryTest createIsNotEqualUnaryTest( ) { return (context, left) -> { Object right = value.evaluate( context ); - Boolean result = utEqualSemantic(left, right, context); + Boolean result = utEqualSemantic(left, right); return result != null ? ! result : null; }; } 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 index 9f4a6324620..a7bb6c668d0 100644 --- 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 @@ -34,7 +34,7 @@ import org.kie.dmn.feel.util.Msg; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.addLocalDateAndDuration; -import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull; +import static org.kie.dmn.feel.util.NumberEvalHelper.getBigDecimalOrNull; public class AddExecutor implements InfixExecutor { 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 index 01bc99c19c3..cb49008c14a 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.and; @@ -42,15 +42,15 @@ public Object evaluate(Object left, Object right, EvaluationContext ctx) { @Override public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) { - Boolean leftAND = EvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx)); + Boolean leftAND = BooleanEvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx)); if (leftAND != null) { if (leftAND.booleanValue()) { - return EvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx)); + return BooleanEvalHelper.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)); + Boolean rightAND = BooleanEvalHelper.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/DivExecutor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/DivExecutor.java index 5b8e577da77..98adaf1dd01 100644 --- 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 @@ -33,7 +33,7 @@ import org.kie.dmn.feel.util.Msg; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.math; -import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull; +import static org.kie.dmn.feel.util.NumberEvalHelper.getBigDecimalOrNull; public class DivExecutor implements InfixExecutor { 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 index 144d12019ff..dd592a8ed93 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; public class EqExecutor implements InfixExecutor { @@ -35,7 +35,7 @@ public static EqExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return EvalHelper.isEqual(left, right, ctx); + return BooleanEvalHelper.isEqual(left, right); } @Override 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 index 86a289ce5be..f69ba4b21ba 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; public class GtExecutor implements InfixExecutor { @@ -35,7 +35,7 @@ public static GtExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return EvalHelper.compare(left, right, ctx, (l, r) -> l.compareTo(r) > 0); + return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) > 0); } @Override 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 index 9a50dd40c29..b2147d296d0 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or; @@ -37,9 +37,9 @@ public static GteExecutor 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. + return or(BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) > 0), + BooleanEvalHelper.isEqual(left, right), + ctx); // do not use Java || to avoid potential NPE due to FEEL 3vl. } @Override 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 index 2ebd96768e3..71c73483906 100644 --- 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 @@ -18,19 +18,26 @@ */ 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.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAmount; import java.util.function.BinaryOperator; +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.BooleanEvalHelper; +import org.kie.dmn.feel.util.Msg; +import org.kie.dmn.feel.util.NumberEvalHelper; + public class InfixExecutorUtils { /** @@ -40,8 +47,8 @@ public class InfixExecutorUtils { */ @Deprecated public static Object or(Object left, Object right, EvaluationContext ctx) { - Boolean l = EvalHelper.getBooleanOrNull(left); - Boolean r = EvalHelper.getBooleanOrNull(right); + Boolean l = BooleanEvalHelper.getBooleanOrNull(left); + Boolean r = BooleanEvalHelper.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; @@ -58,8 +65,8 @@ public static Object or(Object left, Object right, EvaluationContext ctx) { */ @Deprecated public static Object and(Object left, Object right, EvaluationContext ctx) { - Boolean l = EvalHelper.getBooleanOrNull(left); - Boolean r = EvalHelper.getBooleanOrNull(right); + Boolean l = BooleanEvalHelper.getBooleanOrNull(left); + Boolean r = BooleanEvalHelper.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; @@ -70,8 +77,8 @@ public static Object and(Object left, Object right, EvaluationContext ctx) { } static Object math(Object left, Object right, EvaluationContext ctx, BinaryOperator op) { - BigDecimal l = left instanceof String ? null : EvalHelper.getBigDecimalOrNull(left); - BigDecimal r = right instanceof String ? null : EvalHelper.getBigDecimalOrNull(right); + BigDecimal l = left instanceof String ? null : NumberEvalHelper.getBigDecimalOrNull(left); + BigDecimal r = right instanceof String ? null : NumberEvalHelper.getBigDecimalOrNull(right); if (l == null || r == null) { return null; } 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 index 0db56818b9f..2481d435c9f 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; public class LtExecutor implements InfixExecutor { @@ -35,7 +35,7 @@ public static LtExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return EvalHelper.compare(left, right, ctx, (l, r) -> l.compareTo(r) < 0); + return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) < 0); } @Override 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 index d4f9d908860..4a1ba7f0444 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or; @@ -37,9 +37,9 @@ public static LteExecutor 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. + return or(BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) < 0), + BooleanEvalHelper.isEqual(left, right), + ctx); // do not use Java || to avoid potential NPE due to FEEL 3vl. } @Override 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 index 2fcab1286cf..45c0c23b8fb 100644 --- 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 @@ -28,7 +28,7 @@ import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.isAllowedMultiplicationBasedOnSpec; -import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull; +import static org.kie.dmn.feel.util.NumberEvalHelper.getBigDecimalOrNull; public class MultExecutor implements InfixExecutor { 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 index 4e285dae103..a3607335ed7 100644 --- 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 @@ -20,7 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; public class NeExecutor implements InfixExecutor { @@ -35,7 +35,7 @@ public static NeExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - Boolean result = EvalHelper.isEqual(left, right, ctx); + Boolean result = BooleanEvalHelper.isEqual(left, right); return result != null ? !result : null; } 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 index 832e472b644..4cdcc30ee01 100644 --- 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 @@ -20,6 +20,7 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; +import org.kie.dmn.feel.util.BooleanEvalHelper; import org.kie.dmn.feel.util.EvalHelper; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or; @@ -42,15 +43,15 @@ public Object evaluate(Object left, Object right, EvaluationContext ctx) { @Override public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) { - Boolean leftOR = EvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx)); + Boolean leftOR = BooleanEvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx)); if (leftOR != null) { if (!leftOR.booleanValue()) { - return EvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx)); + return BooleanEvalHelper.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)); + Boolean rightOR = BooleanEvalHelper.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/SubExecutor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/SubExecutor.java index 46d7c0b6255..7ae50a55350 100644 --- 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 @@ -33,7 +33,7 @@ import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.subtractTemporals; -import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull; +import static org.kie.dmn.feel.util.NumberEvalHelper.getBigDecimalOrNull; public class SubExecutor implements InfixExecutor { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTTemporalConstantVisitor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTTemporalConstantVisitor.java index ae251e78326..631101b68fc 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTTemporalConstantVisitor.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/visitor/ASTTemporalConstantVisitor.java @@ -54,7 +54,7 @@ import org.kie.dmn.feel.runtime.functions.DurationFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.TimeFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.DATE; import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.DATE_AND_TIME; @@ -109,7 +109,7 @@ public ASTNode visit(ForExpressionNode n) { scopeHelper.pushScope(); for (IterationContextNode ic : n.getIterationContexts()) { ic.accept(this); - scopeHelper.addInScope(EvalHelper.normalizeVariableName(ic.getName().getText()), MASKED); + scopeHelper.addInScope(StringEvalHelper.normalizeVariableName(ic.getName().getText()), MASKED); } n.getExpression().accept(this); scopeHelper.popScope(); @@ -132,7 +132,7 @@ public ASTNode visit(QuantifiedExpressionNode n) { scopeHelper.pushScope(); for (IterationContextNode ic : n.getIterationContexts()) { ic.accept(this); - scopeHelper.addInScope(EvalHelper.normalizeVariableName(ic.getName().getText()), MASKED); + scopeHelper.addInScope(StringEvalHelper.normalizeVariableName(ic.getName().getText()), MASKED); } n.getExpression().accept(this); scopeHelper.popScope(); @@ -143,7 +143,7 @@ public ASTNode visit(QuantifiedExpressionNode n) { public ASTNode visit(FunctionDefNode n) { scopeHelper.pushScope(); for (FormalParameterNode fp : n.getFormalParameters()) { - scopeHelper.addInScope(EvalHelper.normalizeVariableName(fp.getName().getText()), MASKED); + scopeHelper.addInScope(StringEvalHelper.normalizeVariableName(fp.getName().getText()), MASKED); } n.getBody().accept(this); scopeHelper.popScope(); @@ -303,5 +303,5 @@ public List> getParameters() { public Object invokeReflectively(EvaluationContext ctx, Object[] params) { throw new UnsupportedOperationException(); } - }; + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java index 589756e27ac..47759d0aefa 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java @@ -31,7 +31,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEventListener; import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.FEELDialect; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class EvaluationContextImpl implements EvaluationContext { @@ -116,7 +116,7 @@ public void exitFrame() { @Override public void setValue(String name, Object value) { - peek().setValue( name, EvalHelper.coerceNumber( value ) ); + peek().setValue(name, NumberEvalHelper.coerceNumber(value ) ); } public void setValues(Map values) { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/ExecutionFrameImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/ExecutionFrameImpl.java index 654a9f99700..efc04489971 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/ExecutionFrameImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/ExecutionFrameImpl.java @@ -23,6 +23,7 @@ import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.EvalHelper.PropertyValueResult; +import org.kie.dmn.feel.util.StringEvalHelper; public class ExecutionFrameImpl implements ExecutionFrame { @@ -52,7 +53,7 @@ public void setParentFrame(ExecutionFrame parentFrame) { @Override public Object getValue(String symbol) { - symbol = EvalHelper.normalizeVariableName( symbol ); + symbol = StringEvalHelper.normalizeVariableName(symbol ); if (rootObject != null) { PropertyValueResult dv = EvalHelper.getDefinedValue(rootObject, symbol); if (dv.isDefined()) { @@ -70,7 +71,7 @@ public Object getValue(String symbol) { @Override public boolean isDefined(String symbol) { - symbol = EvalHelper.normalizeVariableName( symbol ); + symbol = StringEvalHelper.normalizeVariableName( symbol ); if (rootObject != null) { if (EvalHelper.getDefinedValue(rootObject, symbol).isDefined()) { return true; @@ -89,7 +90,7 @@ public boolean isDefined(String symbol) { @Override public void setValue(String symbol, Object value) { - this.variables.put( EvalHelper.normalizeVariableName( symbol ), value ); + this.variables.put( StringEvalHelper.normalizeVariableName( symbol ), value ); } @Override diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/RootExecutionFrame.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/RootExecutionFrame.java index 902d7f06d60..234e29612e4 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/RootExecutionFrame.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/RootExecutionFrame.java @@ -24,7 +24,7 @@ import org.kie.dmn.feel.runtime.FEELFunction; import org.kie.dmn.feel.runtime.functions.BuiltInFunctions; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; /** * This is a thread safe implementation of a root @@ -40,13 +40,13 @@ public class RootExecutionFrame implements ExecutionFrame { private RootExecutionFrame() { Map builtIn = new ConcurrentHashMap<>( ); for( FEELFunction f : BuiltInFunctions.getFunctions() ) { - builtIn.put( EvalHelper.normalizeVariableName( f.getName() ), f ); + builtIn.put(StringEvalHelper.normalizeVariableName(f.getName() ), f ); } functions = Collections.unmodifiableMap( builtIn ); } public Object getValue(String symbol) { - symbol = EvalHelper.normalizeVariableName( symbol ); + symbol = StringEvalHelper.normalizeVariableName( symbol ); if ( functions.containsKey( symbol ) ) { return functions.get( symbol ); } @@ -54,7 +54,7 @@ public Object getValue(String symbol) { } public boolean isDefined( String symbol ) { - symbol = EvalHelper.normalizeVariableName( symbol ); + symbol = StringEvalHelper.normalizeVariableName( symbol ); return functions.containsKey( symbol ); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/types/ScopeImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/types/ScopeImpl.java index 321786eedb3..b0497e56703 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/types/ScopeImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/types/ScopeImpl.java @@ -31,6 +31,7 @@ import org.kie.dmn.feel.lang.Type; import org.kie.dmn.feel.parser.feel11.FEEL_1_1Lexer; import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; import org.kie.dmn.feel.util.TokenTree; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,7 +79,7 @@ public boolean define(Symbol symbol) { // duplicate symbol definition return false; } - symbols.put( EvalHelper.normalizeVariableName( symbol.getId() ), symbol ); + symbols.put(StringEvalHelper.normalizeVariableName(symbol.getId() ), symbol ); if( tokenTree != null ) { // also load the symbol into the token tree tokenTree.addName( tokenize( symbol.getId() ) ); @@ -87,7 +88,7 @@ public boolean define(Symbol symbol) { } public Symbol resolve(String id) { - Symbol s = symbols.get( EvalHelper.normalizeVariableName( id ) ); + Symbol s = symbols.get( StringEvalHelper.normalizeVariableName( id ) ); if (s == null && getParentScope() != null) { return getParentScope().resolve(id); } @@ -95,13 +96,13 @@ public Symbol resolve(String id) { } public Symbol resolve(String[] qualifiedName) { - Symbol root = symbols.get( EvalHelper.normalizeVariableName( qualifiedName[0] ) ); + Symbol root = symbols.get( StringEvalHelper.normalizeVariableName( qualifiedName[0] ) ); if (root == null && getParentScope() != null) { return getParentScope().resolve(qualifiedName); } else if( root != null ) { Symbol currentSymbol = root; for( int i = 1; i < qualifiedName.length && currentSymbol != null; i++ ) { - currentSymbol = currentSymbol.getScope().resolve( EvalHelper.normalizeVariableName( qualifiedName[i] ) ); + currentSymbol = currentSymbol.getScope().resolve( StringEvalHelper.normalizeVariableName( qualifiedName[i] ) ); } return currentSymbol; } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java index a7f7b51c29b..62ce7781a5a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ASTBuilderVisitor.java @@ -60,7 +60,7 @@ import org.kie.dmn.feel.lang.types.FEELTypeRegistry; import org.kie.dmn.feel.parser.feel11.FEEL_1_1Parser.RelExpressionValueContext; import org.kie.dmn.feel.parser.feel11.FEEL_1_1Parser.TypeContext; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; public class ASTBuilderVisitor extends FEEL_1_1BaseVisitor { @@ -571,7 +571,7 @@ private BaseNode buildNotCall(ParserRuleContext ctx, BaseNode name, ListNode par public TypeNode visitQnType(FEEL_1_1Parser.QnTypeContext ctx) { List qns = new ArrayList<>(); if (ctx.qualifiedName() != null) { - ctx.qualifiedName().nameRef().forEach(nr -> qns.add(EvalHelper.normalizeVariableName(ParserHelper.getOriginalText(nr)))); + ctx.qualifiedName().nameRef().forEach(nr -> qns.add(StringEvalHelper.normalizeVariableName(ParserHelper.getOriginalText(nr)))); } else if (ctx.FUNCTION() != null) { qns.add("function"); } else { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ParserHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ParserHelper.java index 012f2f0c84b..3ac1ca33150 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ParserHelper.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/parser/feel11/ParserHelper.java @@ -48,7 +48,7 @@ import org.kie.dmn.feel.parser.feel11.FEEL_1_1Parser.FilterPathExpressionContext; import org.kie.dmn.feel.parser.feel11.FEEL_1_1Parser.QualifiedNameContext; import org.kie.dmn.feel.runtime.events.UnknownVariableErrorEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -115,7 +115,7 @@ public void pushName(ParserRuleContext ctx) { private String getName(ParserRuleContext ctx) { String key = getOriginalText(ctx); if (ctx instanceof FEEL_1_1Parser.KeyStringContext) { - key = EvalHelper.unescapeString(key); + key = StringEvalHelper.unescapeString(key); } return key; } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java index 008d2b59318..7dcb0a5b26a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java @@ -43,7 +43,7 @@ import org.kie.dmn.feel.runtime.events.FEELEventBase; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.Either; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -349,11 +349,11 @@ private Object normalizeResult(Object result) { if (result != null && result.getClass().isArray()) { List objs = new ArrayList<>(); for (int i = 0; i < Array.getLength(result); i++) { - objs.add(EvalHelper.coerceNumber(Array.get(result, i))); + objs.add(NumberEvalHelper.coerceNumber(Array.get(result, i))); } return objs; } else { - return EvalHelper.coerceNumber(result); + return NumberEvalHelper.coerceNumber(result); } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java index 50bd273a6d8..9a218dcbefd 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java @@ -24,7 +24,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class DayOfYearFunction extends BaseFEELFunction { public static final DayOfYearFunction INSTANCE = new DayOfYearFunction(); @@ -38,7 +38,7 @@ public FEELFnResult invoke(@ParameterName("date") TemporalAccessor d return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "date", "cannot be null")); } - BigDecimal result = EvalHelper.getBigDecimalOrNull(ChronoField.DAY_OF_YEAR.getFrom(date)); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull(ChronoField.DAY_OF_YEAR.getFrom(date)); return FEELFnResult.ofResult(result); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java index 84bf087c020..b45d128ae43 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java @@ -22,6 +22,7 @@ import java.time.temporal.TemporalAccessor; import org.kie.dmn.feel.lang.types.BuiltInType; +import org.kie.dmn.feel.util.BooleanEvalHelper; import org.kie.dmn.feel.util.EvalHelper; public class IsFunction extends BaseFEELFunction { @@ -40,12 +41,12 @@ public FEELFnResult invoke(@ParameterName("value1") Object value1, @Par TemporalAccessor left = (TemporalAccessor) value1; TemporalAccessor right = (TemporalAccessor) value2; if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) { - return FEELFnResult.ofResult(EvalHelper.isEqualTimeInSemanticD(left, right)); + return FEELFnResult.ofResult(BooleanEvalHelper.isEqualTimeInSemanticD(left, right)); } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) { - return FEELFnResult.ofResult(EvalHelper.isEqualDateTimeInSemanticD(left, right)); + return FEELFnResult.ofResult(BooleanEvalHelper.isEqualDateTimeInSemanticD(left, right)); } // fallback; continue: } - Boolean fallback = EvalHelper.isEqual(value1, value2, null); // if null implying they are not the same semantic domain value. + Boolean fallback = BooleanEvalHelper.isEqual(value1, value2); // if null implying they are not the same semantic domain value. return FEELFnResult.ofResult(fallback != null ? fallback : Boolean.FALSE); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java index dd8f10b318d..d4e92df21ee 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java @@ -23,7 +23,8 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class ListContainsFunction extends BaseFEELFunction { @@ -41,11 +42,11 @@ public FEELFnResult invoke(@ParameterName("list") List list, @Parameter if (element == null) { return FEELFnResult.ofResult(list.contains(element)); } - Object e = EvalHelper.coerceNumber(element); + Object e = NumberEvalHelper.coerceNumber(element); boolean found = false; ListIterator it = list.listIterator(); while (it.hasNext() && !found) { - Object next = EvalHelper.coerceNumber(it.next()); + Object next = NumberEvalHelper.coerceNumber(it.next()); found = itemEqualsSC(e, next); } return FEELFnResult.ofResult(found); @@ -55,7 +56,7 @@ public static boolean itemEqualsSC(Object value, Object itemFromList) { if (value instanceof String) { return value.equals(itemFromList); } else { - Boolean dmnEqual = EvalHelper.isEqual(value, itemFromList, null); + Boolean dmnEqual = BooleanEvalHelper.isEqual(value, itemFromList); return dmnEqual != null && dmnEqual; } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java index 1ef80e1cbd1..1b55434e265 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListReplaceFunction.java @@ -24,7 +24,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class ListReplaceFunction extends BaseFEELFunction { @@ -50,7 +50,7 @@ public FEELFnResult invoke(@ParameterName("list") List list, @ParameterNam String paramProblem = String.format("%s outside valid boundaries (1-%s)", intPosition, list.size()); return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "position", paramProblem)); } - Object e = EvalHelper.coerceNumber(newItem); + Object e = NumberEvalHelper.coerceNumber(newItem); List toReturn = new ArrayList(list); int replacementPosition = intPosition > 0 ? intPosition -1 : list.size() - Math.abs(intPosition); toReturn.set(replacementPosition, e); @@ -66,7 +66,7 @@ public FEELFnResult invoke(@ParameterName("list") List list, if (match == null) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "match", CANNOT_BE_NULL)); } - Object e = EvalHelper.coerceNumber(newItem); + Object e = NumberEvalHelper.coerceNumber(newItem); List toReturn = new ArrayList(); for (Object o : list) { Object matched = match.invokeReflectively(match.getEvaluationContext(), new Object[]{o, e}); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java index 9c4faa09232..c53dc339952 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java @@ -23,10 +23,11 @@ import java.util.Arrays; import java.util.List; import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class MeanFunction extends BaseFEELFunction { @@ -69,7 +70,7 @@ public FEELFnResult invoke(@ParameterName( "list" ) Number single) { if( single instanceof BigDecimal ) { return FEELFnResult.ofResult((BigDecimal) single ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( single ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull(single ); if ( result != null ) { return FEELFnResult.ofResult( result ); } else { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java index 547654c0b5d..09224dcc621 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java @@ -29,7 +29,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class ModeFunction extends BaseFEELFunction { @@ -47,7 +47,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { return FEELFnResult.ofResult( Collections.emptyList() ); } - Map collect = list.stream().map(EvalHelper::getBigDecimalOrNull).collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); + Map collect = list.stream().map(NumberEvalHelper::getBigDecimalOrNull).collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); long maxFreq = collect.values().stream().mapToLong(Long::longValue).max().orElse(-1); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NumberFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NumberFunction.java index 921c819c7b2..822b592ba7c 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NumberFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NumberFunction.java @@ -22,7 +22,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class NumberFunction extends BaseFEELFunction { @@ -55,7 +55,7 @@ public FEELFnResult invoke(@ParameterName("from") String from, @Para from = from.replaceAll( "\\" + decimal, "." ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( from ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull(from ); if( from != null && result == null ) { // conversion failed return FEELFnResult.ofError( new InvalidParametersEvent(Severity.ERROR, "unable to calculate final number result" ) ); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java index 665b582d7cf..689dfafe3af 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java @@ -24,7 +24,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class ProductFunction extends BaseFEELFunction { @@ -46,7 +46,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { if ( element instanceof BigDecimal ) { product = product.multiply( (BigDecimal) element ); } else if ( element instanceof Number ) { - product = product.multiply( EvalHelper.getBigDecimalOrNull( element ) ); + product = product.multiply(NumberEvalHelper.getBigDecimalOrNull(element ) ); } else { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "an element in the list is not suitable for the product")); } @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("list") Number single) { if( single instanceof BigDecimal ) { return FEELFnResult.ofResult((BigDecimal) single ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( single ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull( single ); if ( result != null ) { return FEELFnResult.ofResult( result ); } else { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SqrtFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SqrtFunction.java index c8cd47e98cb..90e0521157e 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SqrtFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SqrtFunction.java @@ -18,13 +18,13 @@ */ package org.kie.dmn.feel.runtime.functions; +import java.math.BigDecimal; +import java.math.MathContext; + import ch.obermuhlner.math.big.BigDecimalMath; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.math.MathContext; +import org.kie.dmn.feel.util.NumberEvalHelper; public class SqrtFunction extends BaseFEELFunction { @@ -41,7 +41,7 @@ public FEELFnResult invoke(@ParameterName( "number" ) BigDecimal num if ( number.signum() < 0 ) { return FEELFnResult.ofError( new InvalidParametersEvent( FEELEvent.Severity.ERROR, "number", "is negative" ) ); } - return FEELFnResult.ofResult( sqrt( EvalHelper.getBigDecimalOrNull( number ) ) ); + return FEELFnResult.ofResult( sqrt(NumberEvalHelper.getBigDecimalOrNull(number ) ) ); } public static BigDecimal sqrt( BigDecimal arg ) { // can be modified later to short-circuit if precision is not needed diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java index 9982d8b94f4..88a3484e9a6 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java @@ -26,6 +26,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; // based on the examples of calculations, stddev is supposed to return sample standard deviation, not population standard deviation public class StddevFunction @@ -49,7 +50,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { int n = list.size(); BigDecimal[] numbers = new BigDecimal[n]; for ( int i = 0; i < n; i++ ) { - final BigDecimal val = EvalHelper.getBigDecimalOrNull( list.get( i ) ); + final BigDecimal val = NumberEvalHelper.getBigDecimalOrNull(list.get(i ) ); if ( val == null ) { return FEELFnResult.ofError( new InvalidParametersEvent( FEELEvent.Severity.ERROR, "list", "an element in the list is not suitable for the stddev" ) ); } @@ -73,7 +74,7 @@ public FEELFnResult invoke(@ParameterName("list") Object sole) { if ( sole == null ) { // Arrays.asList does not accept null as parameter return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "list", "the single value list cannot be null")); - } else if (EvalHelper.getBigDecimalOrNull(sole) == null) { + } else if (NumberEvalHelper.getBigDecimalOrNull(sole) == null) { return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "list", "the value can not be converted to a number")); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java index dfbfd5e86e4..e1c673102a7 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java @@ -22,7 +22,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class StringLengthFunction extends BaseFEELFunction { @@ -37,7 +37,7 @@ public FEELFnResult invoke(@ParameterName("string") String string) { if ( string == null ) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "string", "cannot be null")); } else { - return FEELFnResult.ofResult(EvalHelper.getBigDecimalOrNull(string.codePointCount(0, string.length()))); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(string.codePointCount(0, string.length()))); } } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java index 7f61e9ab90e..aa2e30013c7 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java @@ -25,6 +25,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class SumFunction extends BaseFEELFunction { @@ -47,7 +48,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { if ( element instanceof BigDecimal ) { sum = sum.add( (BigDecimal) element ); } else if ( element instanceof Number ) { - BigDecimal value = EvalHelper.getBigDecimalOrNull( element ); + BigDecimal value = NumberEvalHelper.getBigDecimalOrNull(element ); if (value == null) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "an element in the list is not suitable for the sum")); } else { @@ -69,7 +70,7 @@ public FEELFnResult invoke(@ParameterName("list") Number single) { if( single instanceof BigDecimal ) { return FEELFnResult.ofResult((BigDecimal) single ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( single ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull( single ); if ( result != null ) { return FEELFnResult.ofResult( result ); } else { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java index 829482de7ab..a01aeeae339 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java @@ -25,6 +25,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class WeekOfYearFunction extends BaseFEELFunction { public static final WeekOfYearFunction INSTANCE = new WeekOfYearFunction(); @@ -37,7 +38,7 @@ public FEELFnResult invoke(@ParameterName("date") TemporalAccessor d if (date == null) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "date", "cannot be null")); } - BigDecimal result = EvalHelper.getBigDecimalOrNull(date.get(WeekFields.ISO.weekOfWeekBasedYear())); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull(date.get(WeekFields.ISO.weekOfWeekBasedYear())); return FEELFnResult.ofResult(result); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMeanFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMeanFunction.java index 310f028c035..e84c767c8c8 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMeanFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMeanFunction.java @@ -18,17 +18,17 @@ */ package org.kie.dmn.feel.runtime.functions.twovaluelogic; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Arrays; +import java.util.List; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Arrays; -import java.util.List; +import org.kie.dmn.feel.util.NumberEvalHelper; public class NNMeanFunction extends BaseFEELFunction { @@ -52,7 +52,7 @@ public FEELFnResult invoke(@ParameterName( "list" ) List list) { } else if ( element instanceof BigDecimal ) { sum = sum.add( (BigDecimal) element ); } else if ( element instanceof Number ) { - BigDecimal value = EvalHelper.getBigDecimalOrNull( element ); + BigDecimal value = NumberEvalHelper.getBigDecimalOrNull(element ); if (value == null) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "an element in the list is not suitable for the sum")); } else { @@ -73,7 +73,7 @@ public FEELFnResult invoke(@ParameterName( "list" ) Number single) { if( single instanceof BigDecimal ) { return FEELFnResult.ofResult((BigDecimal) single ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( single ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull( single ); if ( result != null ) { return FEELFnResult.ofResult( result ); } else { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMedianFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMedianFunction.java index f310f18e0d8..c6af85b7ab9 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMedianFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNMedianFunction.java @@ -18,13 +18,6 @@ */ package org.kie.dmn.feel.runtime.functions.twovaluelogic; -import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; -import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.FEELFnResult; -import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - import java.math.BigDecimal; import java.math.MathContext; import java.util.ArrayList; @@ -32,6 +25,13 @@ import java.util.Collections; import java.util.List; +import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; +import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; +import org.kie.dmn.feel.runtime.functions.FEELFnResult; +import org.kie.dmn.feel.runtime.functions.ParameterName; +import org.kie.dmn.feel.util.NumberEvalHelper; + public class NNMedianFunction extends BaseFEELFunction { @@ -50,7 +50,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { for( int i = 0; i < list.size(); i++ ) { Object element = list.get( i ); if(element instanceof Number) { - sorted.add(EvalHelper.getBigDecimalOrNull( element ) ); + sorted.add(NumberEvalHelper.getBigDecimalOrNull(element ) ); } else if( element != null ) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "contains element that is not a number")); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNModeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNModeFunction.java index c11a0e86e6c..f4e30e5c8e2 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNModeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNModeFunction.java @@ -18,13 +18,6 @@ */ package org.kie.dmn.feel.runtime.functions.twovaluelogic; -import org.kie.dmn.api.feel.runtime.events.FEELEvent; -import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.FEELFnResult; -import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - import java.math.BigDecimal; import java.util.Arrays; import java.util.HashMap; @@ -32,6 +25,13 @@ import java.util.Map; import java.util.stream.Collectors; +import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; +import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; +import org.kie.dmn.feel.runtime.functions.FEELFnResult; +import org.kie.dmn.feel.runtime.functions.ParameterName; +import org.kie.dmn.feel.util.NumberEvalHelper; + public class NNModeFunction extends BaseFEELFunction { public static final NNModeFunction INSTANCE = new NNModeFunction(); @@ -49,7 +49,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { long maxFreq = 0; for( int i = 0; i < list.size(); i++ ) { Object original = list.get( i ); - BigDecimal value = EvalHelper.getBigDecimalOrNull( original ); + BigDecimal value = NumberEvalHelper.getBigDecimalOrNull(original ); if( original != null && value == null ) { // conversion error return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "list", "contains items that are not numbers")); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNStddevFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNStddevFunction.java index 0d36ef65a9f..c07410ec4fa 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNStddevFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNStddevFunction.java @@ -30,7 +30,7 @@ import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; import org.kie.dmn.feel.runtime.functions.SqrtFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; // based on the examples of calculations, stddev is supposed to return sample standard deviation, not population standard deviation public class NNStddevFunction @@ -52,7 +52,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { // ignore null elements continue; } - final BigDecimal val = EvalHelper.getBigDecimalOrNull(value); + final BigDecimal val = NumberEvalHelper.getBigDecimalOrNull(value); if ( val == null ) { // coercion to number failed return FEELFnResult.ofError( new InvalidParametersEvent( FEELEvent.Severity.ERROR, "list", "an element in the list is not suitable for the stddev" ) ); @@ -80,7 +80,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { public FEELFnResult invoke(@ParameterName("list") Object sole) { if ( sole == null ) { return FEELFnResult.ofResult( null ); - } else if( EvalHelper.getBigDecimalOrNull( sole ) == null ) { + } else if( NumberEvalHelper.getBigDecimalOrNull( sole ) == null ) { return FEELFnResult.ofError( new InvalidParametersEvent( FEELEvent.Severity.ERROR, "list", "the value can not be converted to a number" ) ); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNSumFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNSumFunction.java index 7560f10f6a3..0ed8d289c75 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNSumFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/twovaluelogic/NNSumFunction.java @@ -18,16 +18,16 @@ */ package org.kie.dmn.feel.runtime.functions.twovaluelogic; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.List; +import org.kie.dmn.feel.util.NumberEvalHelper; public class NNSumFunction extends BaseFEELFunction { @@ -49,7 +49,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { } else if ( element instanceof BigDecimal ) { sum = sum.add( (BigDecimal) element ); } else if ( element instanceof Number ) { - BigDecimal value = EvalHelper.getBigDecimalOrNull( element ); + BigDecimal value = NumberEvalHelper.getBigDecimalOrNull(element ); if (value == null) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "an element in the list is not suitable for the sum")); } else { @@ -69,7 +69,7 @@ public FEELFnResult invoke(@ParameterName("list") Number single) { if( single instanceof BigDecimal ) { return FEELFnResult.ofResult((BigDecimal) single ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( single ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull( single ); if ( result != null ) { return FEELFnResult.ofResult( result ); } else { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java index 3aa123b45f5..f16ee87dd3a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java @@ -21,7 +21,7 @@ import java.util.function.BiPredicate; import org.kie.dmn.feel.runtime.Range; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.BooleanEvalHelper; public class RangeImpl implements Range { @@ -126,7 +126,7 @@ private static Boolean compare(Comparable left, Object right, BiPredicate op) { + if ( left == null || right == null ) { + return null; + } + if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) { + // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared + Long l = ComparablePeriod.toTotalMonths((ChronoPeriod) left); + Long r = ComparablePeriod.toTotalMonths((ChronoPeriod) right); + return op.test( l, r ); + } + if (left instanceof TemporalAccessor && right instanceof TemporalAccessor) { + // Handle specific cases when both time / datetime + TemporalAccessor l = (TemporalAccessor) left; + TemporalAccessor r = (TemporalAccessor) right; + if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) { + return op.test(valuet(l), valuet(r)); + } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) { + return op.test(valuedt(l, r.query(TemporalQueries.zone())), valuedt(r, l.query(TemporalQueries.zone()))); + } + } + if (left instanceof Number && right instanceof Number) { + // Handle specific cases when both are Number, converting both to BigDecimal + BigDecimal l = getBigDecimalOrNull(left); + BigDecimal r = getBigDecimalOrNull(right); + return op.test(l, r); + } + // last fallback: + if ((left instanceof String && right instanceof String) || + (left instanceof Boolean && right instanceof Boolean) || + (left instanceof Comparable && left.getClass().isAssignableFrom(right.getClass()))) { + Comparable l = (Comparable) left; + Comparable r = (Comparable) right; + return op.test(l, r); + } + return null; + } + + /** + * Compares left and right for equality applying FEEL semantics to specific data types + * + * @param left + * @param right + * @return + */ + public static Boolean isEqual(Object left, Object right) { + if ( left == null || right == null ) { + return left == right; + } + + // spec defines that "a=[a]", i.e., singleton collections should be treated as the single element + // and vice-versa + if( left instanceof Collection && !(right instanceof Collection) && ((Collection)left).size() == 1 ) { + left = ((Collection)left).toArray()[0]; + } else if( right instanceof Collection && !(left instanceof Collection) && ((Collection)right).size()==1 ) { + right = ((Collection) right).toArray()[0]; + } + + if( left instanceof Range && right instanceof Range ) { + return isEqual( (Range)left, (Range) right ); + } else if( left instanceof Iterable && right instanceof Iterable ) { + return isEqual( (Iterable)left, (Iterable) right ); + } else if( left instanceof Map && right instanceof Map ) { + return isEqual( (Map)left, (Map) right ); + } else if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) { + // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared + Long l = ComparablePeriod.toTotalMonths((ChronoPeriod) left); + Long r = ComparablePeriod.toTotalMonths((ChronoPeriod) right); + return isEqual(l, r); + } else if (left instanceof TemporalAccessor && right instanceof TemporalAccessor) { + // Handle specific cases when both time / datetime + TemporalAccessor l = (TemporalAccessor) left; + TemporalAccessor r = (TemporalAccessor) right; + if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) { + return isEqual(valuet(l), valuet(r)); + } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) { + return isEqual(valuedt(l, r.query(TemporalQueries.zone())), valuedt(r, l.query(TemporalQueries.zone()))); + } // fallback; continue: + } + return compare( left, right, (l, r) -> l.compareTo( r ) == 0 ); + } + + /** + * DMNv1.2 Table 48: Specific semantics of equality + * DMNv1.3 Table 71: Semantic of date and time functions + */ + public static Boolean isEqualDateTimeInSemanticD(TemporalAccessor left, TemporalAccessor right) { + boolean result = true; + Optional lY = Optional.ofNullable(left.isSupported(ChronoField.YEAR) ? left.get(ChronoField.YEAR) : null); + Optional rY = Optional.ofNullable(right.isSupported(ChronoField.YEAR) ? right.get(ChronoField.YEAR) : null); + result &= lY.equals(rY); + Optional lM = Optional.ofNullable(left.isSupported(ChronoField.MONTH_OF_YEAR) ? left.get(ChronoField.MONTH_OF_YEAR) : null); + Optional rM = Optional.ofNullable(right.isSupported(ChronoField.MONTH_OF_YEAR) ? right.get(ChronoField.MONTH_OF_YEAR) : null); + result &= lM.equals(rM); + Optional lD = Optional.ofNullable(left.isSupported(ChronoField.DAY_OF_MONTH) ? left.get(ChronoField.DAY_OF_MONTH) : null); + Optional rD = Optional.ofNullable(right.isSupported(ChronoField.DAY_OF_MONTH) ? right.get(ChronoField.DAY_OF_MONTH) : null); + result &= lD.equals(rD); + result &= isEqualTimeInSemanticD(left, right); + return result; + } + + /** + * DMNv1.2 Table 48: Specific semantics of equality + * DMNv1.3 Table 71: Semantic of date and time functions + */ + public static Boolean isEqualTimeInSemanticD(TemporalAccessor left, TemporalAccessor right) { + boolean result = true; + Optional lH = Optional.ofNullable(left.isSupported(ChronoField.HOUR_OF_DAY) ? left.get(ChronoField.HOUR_OF_DAY) : null); + Optional rH = Optional.ofNullable(right.isSupported(ChronoField.HOUR_OF_DAY) ? right.get(ChronoField.HOUR_OF_DAY) : null); + result &= lH.equals(rH); + Optional lM = Optional.ofNullable(left.isSupported(ChronoField.MINUTE_OF_HOUR) ? left.get(ChronoField.MINUTE_OF_HOUR) : null); + Optional rM = Optional.ofNullable(right.isSupported(ChronoField.MINUTE_OF_HOUR) ? right.get(ChronoField.MINUTE_OF_HOUR) : null); + result &= lM.equals(rM); + Optional lS = Optional.ofNullable(left.isSupported(ChronoField.SECOND_OF_MINUTE) ? left.get(ChronoField.SECOND_OF_MINUTE) : null); + Optional rS = Optional.ofNullable(right.isSupported(ChronoField.SECOND_OF_MINUTE) ? right.get(ChronoField.SECOND_OF_MINUTE) : null); + result &= lS.equals(rS); + Optional lTZ = Optional.ofNullable(left.query(TemporalQueries.zone())); + Optional rTZ = Optional.ofNullable(right.query(TemporalQueries.zone())); + result &= lTZ.equals(rTZ); + return result; + } + + static Boolean isEqual(Range left, Range right) { + return left.equals( right ); + } + + static Boolean isEqual(Iterable left, Iterable right) { + Iterator li = left.iterator(); + Iterator ri = right.iterator(); + while( li.hasNext() && ri.hasNext() ) { + Object l = li.next(); + Object r = ri.next(); + if ( !isEqualObject(l, r ) ) return false; + } + return li.hasNext() == ri.hasNext(); + } + + static Boolean isEqual(Map left, Map right) { + if( left.size() != right.size() ) { + return false; + } + for( Map.Entry le : left.entrySet() ) { + Object l = le.getValue(); + Object r = right.get( le.getKey() ); + if ( !isEqualObject( l, r ) ) return false; + } + return true; + } + + static Boolean isEqualObject(Object l, Object r) { + if( l instanceof Iterable && r instanceof Iterable && !isEqual( (Iterable) l, (Iterable) r ) ) { + return false; + } else if( l instanceof Map && r instanceof Map && !isEqual( (Map) l, (Map) r ) ) { + return false; + } else if( l != null && r != null && !l.equals( r ) ) { + return false; + } else if( ( l == null || r == null ) && l != r ) { + return false; + } + return true; + } + +} diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java index 4672de1b397..421f7282491 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CoerceUtil.java @@ -64,7 +64,7 @@ static Optional coerceParam(Class currentIdxActualParameterType, Clas } if (actualObject instanceof LocalDate localDate && ZonedDateTime.class.isAssignableFrom(expectedParameterType)) { - Object coercedObject = EvalHelper.coerceDateTime(localDate); + Object coercedObject = DateTimeEvalHelper.coerceDateTime(localDate); return Optional.of(coercedObject); } return Optional.empty(); @@ -74,7 +74,7 @@ static Object actualCoerceParameter(Type requiredType, Object valueToCoerce) { Object toReturn = valueToCoerce; if (valueToCoerce instanceof LocalDate localDate && requiredType == BuiltInType.DATE_TIME) { - return EvalHelper.coerceDateTime(localDate); + return DateTimeEvalHelper.coerceDateTime(localDate); } return toReturn; } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java new file mode 100644 index 00000000000..3ba39f9a883 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java @@ -0,0 +1,73 @@ +/** + * 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.util; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.Optional; +import java.util.function.BiPredicate; + +import org.kie.dmn.feel.lang.EvaluationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DateTimeEvalHelper { + public static final Logger LOG = LoggerFactory.getLogger( DateTimeEvalHelper.class ); + + public static ZonedDateTime coerceDateTime(final LocalDate value) { + return ZonedDateTime.of(value, LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); + } + + /** + * DMNv1.2 10.3.2.3.6 date-time, valuedt(date and time), for use in this {@link BooleanEvalHelper#compare(Object, Object, EvaluationContext, BiPredicate)} + * DMNv1.3 also used for equality DMN13-35 + */ + static long valuedt(TemporalAccessor datetime, ZoneId otherTimezoneOffset) { + ZoneId alternativeTZ = Optional.ofNullable(otherTimezoneOffset).orElse(ZoneOffset.UTC); + if (datetime instanceof LocalDateTime) { + return ((LocalDateTime) datetime).atZone(alternativeTZ).toEpochSecond(); + } else if (datetime instanceof ZonedDateTime) { + return ((ZonedDateTime) datetime).toEpochSecond(); + } else if (datetime instanceof OffsetDateTime) { + return ((OffsetDateTime) datetime).toEpochSecond(); + } else { + throw new RuntimeException("valuedt() for " + datetime + " but is not a FEEL date and time " + datetime.getClass()); + } + } + + /** + * DMNv1.2 10.3.2.3.4 time, valuet(time), for use in this {@link BooleanEvalHelper#compare(Object, Object, EvaluationContext, BiPredicate)} + * DMNv1.3 also used for equality DMN13-35 + */ + static long valuet(TemporalAccessor time) { + long result = 0; + result += time.get(ChronoField.HOUR_OF_DAY) * (60 * 60); + result += time.get(ChronoField.MINUTE_OF_HOUR) * (60); + result += time.get(ChronoField.SECOND_OF_MINUTE); + return result; + } + +} diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java index 8a85cef4ed2..ddd788b19d1 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java @@ -20,37 +20,22 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; import java.time.chrono.ChronoPeriod; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; -import java.util.Collection; -import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BiPredicate; import java.util.stream.Stream; import org.kie.dmn.api.core.FEELPropertyAccessible; -import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.FEELProperty; -import org.kie.dmn.feel.lang.types.BuiltInType; -import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.Range.RangeBoundary; import org.slf4j.Logger; @@ -61,230 +46,6 @@ public class EvalHelper { private static final Map accessorCache = new ConcurrentHashMap<>(); - public static String normalizeVariableName(String name) { - // private static final Pattern SPACES_PATTERN = Pattern.compile( "[\\s\u00A0]+" ); - // return SPACES_PATTERN.matcher( name.trim() ).replaceAll( " " ); - - // The above code was refactored for performance reasons - // Check org.drools.benchmarks.dmn.runtime.DMNEvaluateDecisionNameLengthBenchmark - // This method tries to return the original String whenever possible to avoid allocation of char[] - - if (name == null || name.isEmpty()) { - return name; - } - - // Find the first valid char, used to skip leading spaces - int firstValid = 0, size = name.length(); - - for (; firstValid < size; firstValid++) { - if (isValidChar(name.charAt(firstValid))) { - break; - } - } - if (firstValid == size) { - return ""; - } - - // Finds the last valid char, either before a non-regular space, the first of multiple spaces or the last char - int lastValid = 0, trailing = 0; - boolean inWhitespace = false; - - for (int i = firstValid; i < size; i++) { - if (isValidChar(name.charAt(i))) { - lastValid = i + 1; - inWhitespace = false; - } else { - if (inWhitespace) { - break; - } - inWhitespace = true; - if (name.charAt(i) != ' ') { - break; - } - } - } - - // Counts the number of spaces after 'lastValid' (to remove possible trailing spaces) - for (int i = lastValid; i < size && !isValidChar(name.charAt(i)); i++) { - trailing++; - } - if (lastValid + trailing == size) { - return firstValid != 0 || trailing != 0 ? name.substring(firstValid, lastValid) : name; - } - - // There are valid chars after 'lastValid' and substring won't do (full normalization is required) - int pos = 0; - char[] target = new char[size-firstValid]; - - // Copy the chars know to be valid to the new array - for (int i = firstValid; i < lastValid; i++) { - target[pos++] = name.charAt(i); - } - - // Copy valid chars after 'lastValid' to new array - // Many whitespaces are collapsed into one and trailing spaces are ignored - for (int i = lastValid + 1; i < size; i++) { - char c = name.charAt(i); - if (isValidChar(c)) { - if (inWhitespace) { - target[pos++] = ' '; - } - target[pos++] = c; - inWhitespace = false; - } else { - inWhitespace = true; - } - } - return new String(target, 0, pos); - } - - /** - * This method defines what characters are valid for the output of normalizeVariableName. Spaces and control characters are invalid. - * There is a fast-path for well known characters - */ - private static boolean isValidChar(char c) { - if ( c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' ) { - return true; - } - return c != ' ' && c != '\u00A0' && !Character.isWhitespace(c); - } - - public static BigDecimal getBigDecimalOrNull(Object value) { - if ( value instanceof BigDecimal ) { - return (BigDecimal) value; - } - - if ( value instanceof BigInteger ) { - return new BigDecimal((BigInteger) value, MathContext.DECIMAL128); - } - - if ( value instanceof Double || value instanceof Float ) { - String stringVal = value.toString(); - if (stringVal.equals("NaN") || stringVal.equals("Infinity") || stringVal.equals("-Infinity")) { - return null; - } - // doubleValue() sometimes produce rounding errors, so we need to use toString() instead - // We also need to remove trailing zeros, if there are some so for 10d we get BigDecimal.valueOf(10) - // instead of BigDecimal.valueOf(10.0). - return new BigDecimal( removeTrailingZeros(value.toString()), MathContext.DECIMAL128 ); - } - - if ( value instanceof Number ) { - return new BigDecimal( ((Number) value).longValue(), MathContext.DECIMAL128 ); - } - - if ( value instanceof String ) { - try { - // we need to remove leading zeros to prevent octal conversion - return new BigDecimal(((String) value).replaceFirst("^0+(?!$)", ""), MathContext.DECIMAL128); - } catch (NumberFormatException e) { - return null; - } - } - - return null; - } - - public static Object coerceNumber(Object value) { - if ( value instanceof Number && !(value instanceof BigDecimal) ) { - return getBigDecimalOrNull( value ); - } else { - return value; - } - } - - public static ZonedDateTime coerceDateTime(final LocalDate value) { - return ZonedDateTime.of(value, LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC); - } - - public static Boolean getBooleanOrNull(Object value) { - if (!(value instanceof Boolean)) { - return null; - } - return (Boolean) value; - } - - public static String unescapeString(String text) { - if ( text == null ) { - return null; - } - if ( text.length() >= 2 && text.startsWith( "\"" ) && text.endsWith( "\"" ) ) { - // remove the quotes - text = text.substring( 1, text.length() - 1 ); - } - if ( text.indexOf( '\\' ) >= 0 ) { - // might require un-escaping - StringBuilder r = new StringBuilder(); - for ( int i = 0; i < text.length(); i++ ) { - char c = text.charAt( i ); - if ( c == '\\' ) { - if ( text.length() > i + 1 ) { - i++; - char cn = text.charAt( i ); - switch ( cn ) { - case 'b': - r.append( '\b' ); - break; - case 't': - r.append( '\t' ); - break; - case 'n': - r.append( '\n' ); - break; - case 'f': - r.append( '\f' ); - break; - case 'r': - r.append( '\r' ); - break; - case '"': - r.append( '"' ); - break; - case '\'': - r.append( '\'' ); - break; - case '\\': - r.append( '\\' ); - break; - case 'u': - if ( text.length() >= i + 5 ) { - // escape unicode - String hex = text.substring( i + 1, i + 5 ); - char[] chars = Character.toChars( Integer.parseInt( hex, 16 ) ); - r.append( chars ); - i += 4; - } else { - // not really unicode - r.append( "\\" ).append( cn ); - } - break; - case 'U': - if ( text.length() >= i + 7 ) { - // escape unicode - String hex = text.substring( i + 1, i + 7 ); - char[] chars = Character.toChars( Integer.parseInt( hex, 16 ) ); - r.append( chars ); - i += 6; - } else { - // not really unicode - r.append( "\\" ).append( cn ); - } - break; - default: - r.append( "\\" ).append( cn ); - } - } else { - r.append( c ); - } - } else { - r.append( c ); - } - } - text = r.toString(); - } - return text; - } - public static class PropertyValueResult implements FEELPropertyAccessible.AbstractPropertyValueResult { // This exception is used to signal an undefined property for notDefined(). This method may be many times when @@ -446,7 +207,7 @@ public static PropertyValueResult getDefinedValue(final Object current, final St } // before returning, coerce "result" into number. - result = coerceNumber(result); + result = NumberEvalHelper.coerceNumber(result); return PropertyValueResult.ofValue(result); } @@ -495,13 +256,13 @@ public static void clearGenericAccessorCache() { public static Method getAccessor(Class clazz, String field) { LOG.trace( "getAccessor({}, {})", clazz, field ); try { - return clazz.getMethod( "get" + ucFirst( field ) ); + return clazz.getMethod( "get" + StringEvalHelper.ucFirst( field ) ); } catch ( NoSuchMethodException e ) { try { return clazz.getMethod( field ); } catch ( NoSuchMethodException e1 ) { try { - return clazz.getMethod( "is" + ucFirst( field ) ); + return clazz.getMethod( "is" + StringEvalHelper.ucFirst( field ) ); } catch ( NoSuchMethodException e2 ) { return null; } @@ -518,231 +279,11 @@ public static Optional propertyFromAccessor(Method accessor) { } String methodName = accessor.getName(); if ( methodName.startsWith( "get" ) ) { - return Optional.of( lcFirst( methodName.substring( 3))); + return Optional.of( StringEvalHelper.lcFirst( methodName.substring( 3))); } else if ( methodName.startsWith( "is" ) ) { - return Optional.of( lcFirst( methodName.substring( 2))); - } else { - return Optional.of( lcFirst( methodName ) ); - } - } - - public static String ucFirst(final String name) { - return name.toUpperCase().charAt( 0 ) + name.substring( 1 ); - } - - public static String lcFirst(final String name) { - return name.toLowerCase().charAt( 0 ) + name.substring( 1 ); - } - - /** - * Compares left and right operands using the given predicate and returns TRUE/FALSE accordingly - * - * @param left - * @param right - * @param ctx - * @param op - * @return - */ - public static Boolean compare(Object left, Object right, EvaluationContext ctx, BiPredicate op) { - if ( left == null || right == null ) { - return null; - } - if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) { - // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared - Long l = ComparablePeriod.toTotalMonths((ChronoPeriod) left); - Long r = ComparablePeriod.toTotalMonths((ChronoPeriod) right); - return op.test( l, r ); - } - if (left instanceof TemporalAccessor && right instanceof TemporalAccessor) { - // Handle specific cases when both time / datetime - TemporalAccessor l = (TemporalAccessor) left; - TemporalAccessor r = (TemporalAccessor) right; - if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) { - return op.test(valuet(l), valuet(r)); - } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) { - return op.test(valuedt(l, r.query(TemporalQueries.zone())), valuedt(r, l.query(TemporalQueries.zone()))); - } - } - if (left instanceof Number && right instanceof Number) { - // Handle specific cases when both are Number, converting both to BigDecimal - BigDecimal l = getBigDecimalOrNull(left); - BigDecimal r = getBigDecimalOrNull(right); - return op.test(l, r); - } - // last fallback: - if ((left instanceof String && right instanceof String) || - (left instanceof Boolean && right instanceof Boolean) || - (left instanceof Comparable && left.getClass().isAssignableFrom(right.getClass()))) { - Comparable l = (Comparable) left; - Comparable r = (Comparable) right; - return op.test(l, r); - } - return null; - } - - /** - * Compares left and right for equality applying FEEL semantics to specific data types - * - * @param left - * @param right - * @param ctx - * @return - */ - public static Boolean isEqual(Object left, Object right, EvaluationContext ctx ) { - if ( left == null || right == null ) { - return left == right; - } - - // spec defines that "a=[a]", i.e., singleton collections should be treated as the single element - // and vice-versa - if( left instanceof Collection && !(right instanceof Collection) && ((Collection)left).size() == 1 ) { - left = ((Collection)left).toArray()[0]; - } else if( right instanceof Collection && !(left instanceof Collection) && ((Collection)right).size()==1 ) { - right = ((Collection) right).toArray()[0]; - } - - if( left instanceof Range && right instanceof Range ) { - return isEqual( (Range)left, (Range) right ); - } else if( left instanceof Iterable && right instanceof Iterable ) { - return isEqual( (Iterable)left, (Iterable) right ); - } else if( left instanceof Map && right instanceof Map ) { - return isEqual( (Map)left, (Map) right ); - } else if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) { - // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared - Long l = ComparablePeriod.toTotalMonths((ChronoPeriod) left); - Long r = ComparablePeriod.toTotalMonths((ChronoPeriod) right); - return isEqual(l, r); - } else if (left instanceof TemporalAccessor && right instanceof TemporalAccessor) { - // Handle specific cases when both time / datetime - TemporalAccessor l = (TemporalAccessor) left; - TemporalAccessor r = (TemporalAccessor) right; - if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) { - return isEqual(valuet(l), valuet(r)); - } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) { - return isEqual(valuedt(l, r.query(TemporalQueries.zone())), valuedt(r, l.query(TemporalQueries.zone()))); - } // fallback; continue: - } - return compare( left, right, ctx, (l, r) -> l.compareTo( r ) == 0 ); - } - - /** - * DMNv1.2 10.3.2.3.6 date-time, valuedt(date and time), for use in this {@link EvalHelper#compare(Object, Object, EvaluationContext, BiPredicate)} - * DMNv1.3 also used for equality DMN13-35 - */ - private static long valuedt(TemporalAccessor datetime, ZoneId otherTimezoneOffset) { - ZoneId alternativeTZ = Optional.ofNullable(otherTimezoneOffset).orElse(ZoneOffset.UTC); - if (datetime instanceof LocalDateTime) { - return ((LocalDateTime) datetime).atZone(alternativeTZ).toEpochSecond(); - } else if (datetime instanceof ZonedDateTime) { - return ((ZonedDateTime) datetime).toEpochSecond(); - } else if (datetime instanceof OffsetDateTime) { - return ((OffsetDateTime) datetime).toEpochSecond(); - } else { - throw new RuntimeException("valuedt() for " + datetime + " but is not a FEEL date and time " + datetime.getClass()); - } - } - - /** - * DMNv1.2 10.3.2.3.4 time, valuet(time), for use in this {@link EvalHelper#compare(Object, Object, EvaluationContext, BiPredicate)} - * DMNv1.3 also used for equality DMN13-35 - */ - private static long valuet(TemporalAccessor time) { - long result = 0; - result += time.get(ChronoField.HOUR_OF_DAY) * (60 * 60); - result += time.get(ChronoField.MINUTE_OF_HOUR) * (60); - result += time.get(ChronoField.SECOND_OF_MINUTE); - return result; - } - - /** - * DMNv1.2 Table 48: Specific semantics of equality - * DMNv1.3 Table 71: Semantic of date and time functions - */ - public static Boolean isEqualDateTimeInSemanticD(TemporalAccessor left, TemporalAccessor right) { - boolean result = true; - Optional lY = Optional.ofNullable(left.isSupported(ChronoField.YEAR) ? left.get(ChronoField.YEAR) : null); - Optional rY = Optional.ofNullable(right.isSupported(ChronoField.YEAR) ? right.get(ChronoField.YEAR) : null); - result &= lY.equals(rY); - Optional lM = Optional.ofNullable(left.isSupported(ChronoField.MONTH_OF_YEAR) ? left.get(ChronoField.MONTH_OF_YEAR) : null); - Optional rM = Optional.ofNullable(right.isSupported(ChronoField.MONTH_OF_YEAR) ? right.get(ChronoField.MONTH_OF_YEAR) : null); - result &= lM.equals(rM); - Optional lD = Optional.ofNullable(left.isSupported(ChronoField.DAY_OF_MONTH) ? left.get(ChronoField.DAY_OF_MONTH) : null); - Optional rD = Optional.ofNullable(right.isSupported(ChronoField.DAY_OF_MONTH) ? right.get(ChronoField.DAY_OF_MONTH) : null); - result &= lD.equals(rD); - result &= isEqualTimeInSemanticD(left, right); - return result; - } - - /** - * DMNv1.2 Table 48: Specific semantics of equality - * DMNv1.3 Table 71: Semantic of date and time functions - */ - public static Boolean isEqualTimeInSemanticD(TemporalAccessor left, TemporalAccessor right) { - boolean result = true; - Optional lH = Optional.ofNullable(left.isSupported(ChronoField.HOUR_OF_DAY) ? left.get(ChronoField.HOUR_OF_DAY) : null); - Optional rH = Optional.ofNullable(right.isSupported(ChronoField.HOUR_OF_DAY) ? right.get(ChronoField.HOUR_OF_DAY) : null); - result &= lH.equals(rH); - Optional lM = Optional.ofNullable(left.isSupported(ChronoField.MINUTE_OF_HOUR) ? left.get(ChronoField.MINUTE_OF_HOUR) : null); - Optional rM = Optional.ofNullable(right.isSupported(ChronoField.MINUTE_OF_HOUR) ? right.get(ChronoField.MINUTE_OF_HOUR) : null); - result &= lM.equals(rM); - Optional lS = Optional.ofNullable(left.isSupported(ChronoField.SECOND_OF_MINUTE) ? left.get(ChronoField.SECOND_OF_MINUTE) : null); - Optional rS = Optional.ofNullable(right.isSupported(ChronoField.SECOND_OF_MINUTE) ? right.get(ChronoField.SECOND_OF_MINUTE) : null); - result &= lS.equals(rS); - Optional lTZ = Optional.ofNullable(left.query(TemporalQueries.zone())); - Optional rTZ = Optional.ofNullable(right.query(TemporalQueries.zone())); - result &= lTZ.equals(rTZ); - return result; - } - - private static Boolean isEqual(Range left, Range right) { - return left.equals( right ); - } - - private static Boolean isEqual(Iterable left, Iterable right) { - Iterator li = left.iterator(); - Iterator ri = right.iterator(); - while( li.hasNext() && ri.hasNext() ) { - Object l = li.next(); - Object r = ri.next(); - if ( !isEqual( l, r ) ) return false; - } - return li.hasNext() == ri.hasNext(); - } - - private static Boolean isEqual(Map left, Map right) { - if( left.size() != right.size() ) { - return false; - } - for( Map.Entry le : left.entrySet() ) { - Object l = le.getValue(); - Object r = right.get( le.getKey() ); - if ( !isEqual( l, r ) ) return false; - } - return true; - } - - private static Boolean isEqual(Object l, Object r) { - if( l instanceof Iterable && r instanceof Iterable && !isEqual( (Iterable) l, (Iterable) r ) ) { - return false; - } else if( l instanceof Map && r instanceof Map && !isEqual( (Map) l, (Map) r ) ) { - return false; - } else if( l != null && r != null && !l.equals( r ) ) { - return false; - } else if( ( l == null || r == null ) && l != r ) { - return false; - } - return true; - } - - private static String removeTrailingZeros(final String stringNumber) { - if(stringNumber.contains("E")) { - return stringNumber; - } - final String stringWithoutZeros = stringNumber.replaceAll("0*$", ""); - if (Character.isDigit(stringWithoutZeros.charAt(stringWithoutZeros.length() - 1))) { - return stringWithoutZeros; + return Optional.of( StringEvalHelper.lcFirst( methodName.substring( 2))); } else { - return stringWithoutZeros.substring(0, stringWithoutZeros.length() - 1); + return Optional.of( StringEvalHelper.lcFirst( methodName ) ); } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java new file mode 100644 index 00000000000..f5920416f43 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java @@ -0,0 +1,77 @@ +/** + * 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.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.kie.dmn.feel.util.StringEvalHelper.removeTrailingZeros; + +public class NumberEvalHelper { + public static final Logger LOG = LoggerFactory.getLogger( NumberEvalHelper.class ); + + public static BigDecimal getBigDecimalOrNull(Object value) { + if ( value instanceof BigDecimal ) { + return (BigDecimal) value; + } + + if ( value instanceof BigInteger ) { + return new BigDecimal((BigInteger) value, MathContext.DECIMAL128); + } + + if ( value instanceof Double || value instanceof Float ) { + String stringVal = value.toString(); + if (stringVal.equals("NaN") || stringVal.equals("Infinity") || stringVal.equals("-Infinity")) { + return null; + } + // doubleValue() sometimes produce rounding errors, so we need to use toString() instead + // We also need to remove trailing zeros, if there are some so for 10d we get BigDecimal.valueOf(10) + // instead of BigDecimal.valueOf(10.0). + return new BigDecimal( removeTrailingZeros(value.toString()), MathContext.DECIMAL128 ); + } + + if ( value instanceof Number ) { + return new BigDecimal( ((Number) value).longValue(), MathContext.DECIMAL128 ); + } + + if ( value instanceof String ) { + try { + // we need to remove leading zeros to prevent octal conversion + return new BigDecimal(((String) value).replaceFirst("^0+(?!$)", ""), MathContext.DECIMAL128); + } catch (NumberFormatException e) { + return null; + } + } + + return null; + } + + public static Object coerceNumber(Object value) { + if ( value instanceof Number && !(value instanceof BigDecimal) ) { + return getBigDecimalOrNull( value ); + } else { + return value; + } + } + +} diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/StringEvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/StringEvalHelper.java new file mode 100644 index 00000000000..21e28e3249d --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/StringEvalHelper.java @@ -0,0 +1,216 @@ +/** + * 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.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StringEvalHelper { + public static final Logger LOG = LoggerFactory.getLogger( StringEvalHelper.class ); + + public static String normalizeVariableName(String name) { + // private static final Pattern SPACES_PATTERN = Pattern.compile( "[\\s\u00A0]+" ); + // return SPACES_PATTERN.matcher( name.trim() ).replaceAll( " " ); + + // The above code was refactored for performance reasons + // Check org.drools.benchmarks.dmn.runtime.DMNEvaluateDecisionNameLengthBenchmark + // This method tries to return the original String whenever possible to avoid allocation of char[] + + if (name == null || name.isEmpty()) { + return name; + } + + // Find the first valid char, used to skip leading spaces + int firstValid = 0, size = name.length(); + + for (; firstValid < size; firstValid++) { + if (isValidChar(name.charAt(firstValid))) { + break; + } + } + if (firstValid == size) { + return ""; + } + + // Finds the last valid char, either before a non-regular space, the first of multiple spaces or the last char + int lastValid = 0, trailing = 0; + boolean inWhitespace = false; + + for (int i = firstValid; i < size; i++) { + if (isValidChar(name.charAt(i))) { + lastValid = i + 1; + inWhitespace = false; + } else { + if (inWhitespace) { + break; + } + inWhitespace = true; + if (name.charAt(i) != ' ') { + break; + } + } + } + + // Counts the number of spaces after 'lastValid' (to remove possible trailing spaces) + for (int i = lastValid; i < size && !isValidChar(name.charAt(i)); i++) { + trailing++; + } + if (lastValid + trailing == size) { + return firstValid != 0 || trailing != 0 ? name.substring(firstValid, lastValid) : name; + } + + // There are valid chars after 'lastValid' and substring won't do (full normalization is required) + int pos = 0; + char[] target = new char[size-firstValid]; + + // Copy the chars know to be valid to the new array + for (int i = firstValid; i < lastValid; i++) { + target[pos++] = name.charAt(i); + } + + // Copy valid chars after 'lastValid' to new array + // Many whitespaces are collapsed into one and trailing spaces are ignored + for (int i = lastValid + 1; i < size; i++) { + char c = name.charAt(i); + if (isValidChar(c)) { + if (inWhitespace) { + target[pos++] = ' '; + } + target[pos++] = c; + inWhitespace = false; + } else { + inWhitespace = true; + } + } + return new String(target, 0, pos); + } + + /** + * This method defines what characters are valid for the output of normalizeVariableName. Spaces and control characters are invalid. + * There is a fast-path for well known characters + */ + private static boolean isValidChar(char c) { + if ( c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' ) { + return true; + } + return c != ' ' && c != '\u00A0' && !Character.isWhitespace(c); + } + + public static String unescapeString(String text) { + if ( text == null ) { + return null; + } + if ( text.length() >= 2 && text.startsWith( "\"" ) && text.endsWith( "\"" ) ) { + // remove the quotes + text = text.substring( 1, text.length() - 1 ); + } + if ( text.indexOf( '\\' ) >= 0 ) { + // might require un-escaping + StringBuilder r = new StringBuilder(); + for ( int i = 0; i < text.length(); i++ ) { + char c = text.charAt( i ); + if ( c == '\\' ) { + if ( text.length() > i + 1 ) { + i++; + char cn = text.charAt( i ); + switch ( cn ) { + case 'b': + r.append( '\b' ); + break; + case 't': + r.append( '\t' ); + break; + case 'n': + r.append( '\n' ); + break; + case 'f': + r.append( '\f' ); + break; + case 'r': + r.append( '\r' ); + break; + case '"': + r.append( '"' ); + break; + case '\'': + r.append( '\'' ); + break; + case '\\': + r.append( '\\' ); + break; + case 'u': + if ( text.length() >= i + 5 ) { + // escape unicode + String hex = text.substring( i + 1, i + 5 ); + char[] chars = Character.toChars( Integer.parseInt( hex, 16 ) ); + r.append( chars ); + i += 4; + } else { + // not really unicode + r.append( "\\" ).append( cn ); + } + break; + case 'U': + if ( text.length() >= i + 7 ) { + // escape unicode + String hex = text.substring( i + 1, i + 7 ); + char[] chars = Character.toChars( Integer.parseInt( hex, 16 ) ); + r.append( chars ); + i += 6; + } else { + // not really unicode + r.append( "\\" ).append( cn ); + } + break; + default: + r.append( "\\" ).append( cn ); + } + } else { + r.append( c ); + } + } else { + r.append( c ); + } + } + text = r.toString(); + } + return text; + } + + + public static String ucFirst(final String name) { + return name.toUpperCase().charAt( 0 ) + name.substring( 1 ); + } + + public static String lcFirst(final String name) { + return name.toLowerCase().charAt( 0 ) + name.substring( 1 ); + } + + static String removeTrailingZeros(final String stringNumber) { + if(stringNumber.contains("E")) { + return stringNumber; + } + final String stringWithoutZeros = stringNumber.replaceAll("0*$", ""); + if (Character.isDigit(stringWithoutZeros.charAt(stringWithoutZeros.length() - 1))) { + return stringWithoutZeros; + } else { + return stringWithoutZeros.substring(0, stringWithoutZeros.length() - 1); + } + } +} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/DirectCompilerUnaryTestsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/DirectCompilerUnaryTestsTest.java index 8e4feea77fd..13f61615b31 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/DirectCompilerUnaryTestsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/DirectCompilerUnaryTestsTest.java @@ -33,7 +33,7 @@ import org.kie.dmn.feel.parser.feel11.ASTBuilderVisitor; import org.kie.dmn.feel.parser.feel11.FEELParser; import org.kie.dmn.feel.parser.feel11.FEEL_1_1Parser; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +44,7 @@ public class DirectCompilerUnaryTestsTest { public static final Logger LOG = LoggerFactory.getLogger(DirectCompilerUnaryTestsTest.class); private List parseCompileEvaluate(String feelLiteralExpression, Object l) { - Object left = EvalHelper.coerceNumber(l); + Object left = NumberEvalHelper.coerceNumber(l); FEELEventListenersManager mgr = new FEELEventListenersManager(); CompiledFEELSupport.SyntaxErrorListener listener = new CompiledFEELSupport.SyntaxErrorListener(); mgr.addListener(listener); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java index 02ae4687722..5d6165f6536 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test; import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.runtime.UnaryTest; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +53,7 @@ public List getUnaryTests() { @Test void manualUnaryTests() { - Object left = EvalHelper.coerceNumber(7); + Object left = NumberEvalHelper.coerceNumber(7); CompiledFEELUnaryTests compiledUnaryTests = new ManualImpl1(); LOG.debug("{}", compiledUnaryTests); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java deleted file mode 100644 index 1fab72f232f..00000000000 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java +++ /dev/null @@ -1,48 +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.runtime; - -import java.util.Collection; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.kie.dmn.api.feel.runtime.events.FEELEvent; -import org.kie.dmn.feel.lang.FEELDialect; - -public class BFEELTest/* extends BaseFEELTest*/ { - - /* *//** - * WARNING: do not use as JUNit's @Parameters name the index {1} within this test class, as this would result in invalid character in the XML surefire-report - * Original error was: An invalid XML character (Unicode: 0x8) was found in the value of attribute "name" and element is "testcase". - *//* - @ParameterizedTest - @MethodSource("data") - protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); - } - - private static Collection data() { - final Object[][] cases = new Object[][] { - {"lowercase(12)", null, null}, -// {"string(null)", "", null}, -// {"substring(\"a\", \"z\")", "", null}, - }; - return addAdditionalParameters(cases, false, FEELDialect.BFEEL); - }*/ -} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java index dafccbe2391..3b7cb5b728e 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEEL12ExtendedForLoopTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.FEELDialect; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import static org.kie.dmn.feel.util.DynamicTypeUtils.entry; import static org.kie.dmn.feel.util.DynamicTypeUtils.mapOf; @@ -69,7 +69,7 @@ private static Collection data() { private static List l(final Object... args) { final List coerced = new ArrayList<>(); for ( final Object a : args ) { - coerced.add(EvalHelper.coerceNumber(a)); + coerced.add(NumberEvalHelper.coerceNumber(a)); } return coerced; } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java index 1d02f60c49f..28e14009e46 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/FEELMathOperationsTest.java @@ -25,7 +25,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.FEELDialect; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class FEELMathOperationsTest extends BaseFEELTest { @@ -91,7 +91,7 @@ private static Collection data() { { "-1", BigDecimal.valueOf( -1 ), null }, { "--1", BigDecimal.valueOf( 1 ), null }, { "---1", BigDecimal.valueOf( -1 ), null }, - { "{ amount : 100000.00, rate : 0.25, term : 36, PMT : (amount *rate/12) / (1 - (1 + rate/12)**-term) }.PMT", EvalHelper.getBigDecimalOrNull( "3975.982590125552338278440100112431" ), null} + { "{ amount : 100000.00, rate : 0.25, term : 36, PMT : (amount *rate/12) / (1 - (1 + rate/12)**-term) }.PMT", NumberEvalHelper.getBigDecimalOrNull("3975.982590125552338278440100112431" ), null} }; return addAdditionalParameters(cases, false); } 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 683b7e42340..fa2571b0394 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 @@ -29,7 +29,7 @@ import org.kie.dmn.feel.lang.impl.FEELBuilder; import static org.assertj.core.api.Assertions.assertThat; -import static org.kie.dmn.feel.util.EvalHelper.getBigDecimalOrNull; +import static org.kie.dmn.feel.util.NumberEvalHelper.getBigDecimalOrNull; class FEELNumberCoercionTest { private final FEEL feel = FEELBuilder.builder().build(); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java new file mode 100644 index 00000000000..675cd3f4d89 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.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.util; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class BooleanEvalHelperTest { + + + @Test + void numericValuesComparative() { + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(1.0, 2.0, (l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(1, 2, (l, r) -> l.compareTo(r) > 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2, (l, r) -> l.compareTo(r) > 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(1, BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2.3, (l, r) -> l.compareTo(r) == 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(1.2, BigDecimal.valueOf(1.2), (l, r) -> l.compareTo(r) == 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 0L, (l, r) -> l.compareTo(r) > 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(10L, BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), BigInteger.valueOf(2), (l, r) -> l.compareTo(r) == 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2, (l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2.3, (l, r) -> l.compareTo(r) == 0)).isFalse(); + } + +} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/EvalHelperTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/EvalHelperTest.java index bc1c0fd9f94..9c671683ac2 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/EvalHelperTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/EvalHelperTest.java @@ -19,50 +19,14 @@ package org.kie.dmn.feel.util; import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; import org.junit.jupiter.api.Test; import org.kie.dmn.feel.lang.FEELProperty; import static org.assertj.core.api.Assertions.assertThat; -import static org.kie.dmn.feel.util.EvalHelper.normalizeVariableName; class EvalHelperTest { - @Test - void normalizeSpace() { - assertThat(normalizeVariableName(null)).isNull(); - assertThat(normalizeVariableName("")).isEqualTo(""); - assertThat(normalizeVariableName(" ")).isEqualTo(""); - assertThat(normalizeVariableName("\t")).isEqualTo(""); - assertThat(normalizeVariableName("\n")).isEqualTo(""); - assertThat(normalizeVariableName("\u0009")).isEqualTo(""); - assertThat(normalizeVariableName("\u000B")).isEqualTo(""); - assertThat(normalizeVariableName("\u000C")).isEqualTo(""); - assertThat(normalizeVariableName("\u001C")).isEqualTo(""); - assertThat(normalizeVariableName("\u001D")).isEqualTo(""); - assertThat(normalizeVariableName("\u001E")).isEqualTo(""); - assertThat(normalizeVariableName("\u001F")).isEqualTo(""); - assertThat(normalizeVariableName("\f")).isEqualTo(""); - assertThat(normalizeVariableName("\r")).isEqualTo(""); - assertThat(normalizeVariableName(" a ")).isEqualTo("a"); - assertThat(normalizeVariableName(" a b c ")).isEqualTo("a b c"); - assertThat(normalizeVariableName("a\t\f\r b\u000B c\n")).isEqualTo("a b c"); - assertThat(normalizeVariableName("a\t\f\r \u00A0\u00A0b\u000B c\n")).isEqualTo("a b c"); - assertThat(normalizeVariableName(" b")).isEqualTo("b"); - assertThat(normalizeVariableName("b ")).isEqualTo("b"); - assertThat(normalizeVariableName("ab c ")).isEqualTo("ab c"); - assertThat(normalizeVariableName("a\u00A0b")).isEqualTo("a b"); - } - - @Test - void getBigDecimalOrNull() { - assertThat(EvalHelper.getBigDecimalOrNull(10d)).isEqualTo(new BigDecimal("10")); - assertThat(EvalHelper.getBigDecimalOrNull(10.00000000D)).isEqualTo(new BigDecimal("10")); - assertThat(EvalHelper.getBigDecimalOrNull(10000000000.5D)).isEqualTo(new BigDecimal("10000000000.5")); - } - @Test void getGenericAccessor() throws NoSuchMethodException { Method expectedAccessor = TestPojo.class.getMethod("getAProperty"); @@ -72,21 +36,6 @@ void getGenericAccessor() throws NoSuchMethodException { assertThat(EvalHelper.getGenericAccessor(TestPojo.class, "feelPropertyIdentifier")).as("getGenericAccessor should work for methods annotated with '@FEELProperty'.").isEqualTo(expectedAccessor); } - @Test - void numericValuesComparative() { - assertThat(EvalHelper.compare(BigDecimal.valueOf(1), BigDecimal.valueOf(2), null, (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(EvalHelper.compare(1.0, 2.0, null, (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(EvalHelper.compare(1, 2, null, (l, r) -> l.compareTo(r) > 0)).isFalse(); - assertThat(EvalHelper.compare(BigDecimal.valueOf(1), 2, null, (l, r) -> l.compareTo(r) > 0)).isFalse(); - assertThat(EvalHelper.compare(1, BigDecimal.valueOf(2), null, (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(EvalHelper.compare(BigDecimal.valueOf(1), 2.3, null, (l, r) -> l.compareTo(r) == 0)).isFalse(); - assertThat(EvalHelper.compare(1.2, BigDecimal.valueOf(1.2), null, (l, r) -> l.compareTo(r) == 0)).isTrue(); - assertThat(EvalHelper.compare(BigDecimal.valueOf(1), 0L, null, (l, r) -> l.compareTo(r) > 0)).isTrue(); - assertThat(EvalHelper.compare(10L, BigDecimal.valueOf(2), null, (l, r) -> l.compareTo(r) < 0)).isFalse(); - assertThat(EvalHelper.compare(BigInteger.valueOf(1), BigInteger.valueOf(2), null, (l, r) -> l.compareTo(r) == 0)).isFalse(); - assertThat(EvalHelper.compare(BigInteger.valueOf(1), 2, null, (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(EvalHelper.compare(BigInteger.valueOf(1), 2.3, null, (l, r) -> l.compareTo(r) == 0)).isFalse(); - } private static class TestPojo { @FEELProperty("feelPropertyIdentifier") diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java new file mode 100644 index 00000000000..e619069768b --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java @@ -0,0 +1,37 @@ +/** + * 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.util; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class NumberEvalHelperTest { + + + @Test + void getBigDecimalOrNull() { + assertThat(NumberEvalHelper.getBigDecimalOrNull(10d)).isEqualTo(new BigDecimal("10")); + assertThat(NumberEvalHelper.getBigDecimalOrNull(10.00000000D)).isEqualTo(new BigDecimal("10")); + assertThat(NumberEvalHelper.getBigDecimalOrNull(10000000000.5D)).isEqualTo(new BigDecimal("10000000000.5")); + } + +} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/StringEvalHelperTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/StringEvalHelperTest.java new file mode 100644 index 00000000000..898a57a2ae4 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/StringEvalHelperTest.java @@ -0,0 +1,54 @@ +/** + * 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.util; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.kie.dmn.feel.util.StringEvalHelper.normalizeVariableName; + +class StringEvalHelperTest { + + @Test + void normalizeSpace() { + assertThat(normalizeVariableName(null)).isNull(); + assertThat(normalizeVariableName("")).isEqualTo(""); + assertThat(normalizeVariableName(" ")).isEqualTo(""); + assertThat(normalizeVariableName("\t")).isEqualTo(""); + assertThat(normalizeVariableName("\n")).isEqualTo(""); + assertThat(normalizeVariableName("\u0009")).isEqualTo(""); + assertThat(normalizeVariableName("\u000B")).isEqualTo(""); + assertThat(normalizeVariableName("\u000C")).isEqualTo(""); + assertThat(normalizeVariableName("\u001C")).isEqualTo(""); + assertThat(normalizeVariableName("\u001D")).isEqualTo(""); + assertThat(normalizeVariableName("\u001E")).isEqualTo(""); + assertThat(normalizeVariableName("\u001F")).isEqualTo(""); + assertThat(normalizeVariableName("\f")).isEqualTo(""); + assertThat(normalizeVariableName("\r")).isEqualTo(""); + assertThat(normalizeVariableName(" a ")).isEqualTo("a"); + assertThat(normalizeVariableName(" a b c ")).isEqualTo("a b c"); + assertThat(normalizeVariableName("a\t\f\r b\u000B c\n")).isEqualTo("a b c"); + assertThat(normalizeVariableName("a\t\f\r \u00A0\u00A0b\u000B c\n")).isEqualTo("a b c"); + assertThat(normalizeVariableName(" b")).isEqualTo("b"); + assertThat(normalizeVariableName("b ")).isEqualTo("b"); + assertThat(normalizeVariableName("ab c ")).isEqualTo("ab c"); + assertThat(normalizeVariableName("a\u00A0b")).isEqualTo("a b"); + } + +} diff --git a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNRuntimeTest.java b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNRuntimeTest.java index 70d6109c8ce..8c944344a45 100644 --- a/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNRuntimeTest.java +++ b/kie-dmn/kie-dmn-legacy-tests/src/test/java/org/kie/dmn/legacy/tests/core/v1_1/DMNRuntimeTest.java @@ -67,7 +67,7 @@ import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.marshaller.FEELStringMarshaller; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.model.api.Decision; import org.kie.dmn.model.api.Definitions; import org.kie.dmn.model.api.ItemDefinition; @@ -1410,8 +1410,8 @@ void typeInferenceForNestedContextAnonymousEntry(VariantTestConf conf) { final DMNContext result = dmnResult.getContext(); assertThat(dmnResult.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult.getMessages())).isFalse(); - assertThat( (List)result.get("My Decision")).asList().contains( prototype( entry("Full Name", "Prof. John Doe"), entry("Age", EvalHelper.coerceNumber(33)) ), - prototype( entry("Full Name", "Prof. 47"), entry("Age", EvalHelper.coerceNumber(47)) ) + assertThat( (List)result.get("My Decision")).asList().contains( prototype( entry("Full Name", "Prof. John Doe"), entry("Age", NumberEvalHelper.coerceNumber(33)) ), + prototype( entry("Full Name", "Prof. 47"), entry("Age", NumberEvalHelper.coerceNumber(47)) ) ); } diff --git a/kie-dmn/kie-dmn-ruleset2dmn-parent/kie-dmn-ruleset2dmn/src/main/java/org/kie/dmn/ruleset2dmn/Converter.java b/kie-dmn/kie-dmn-ruleset2dmn-parent/kie-dmn-ruleset2dmn/src/main/java/org/kie/dmn/ruleset2dmn/Converter.java index 06dd73a2396..9842ee5b8e1 100644 --- a/kie-dmn/kie-dmn-ruleset2dmn-parent/kie-dmn-ruleset2dmn/src/main/java/org/kie/dmn/ruleset2dmn/Converter.java +++ b/kie-dmn/kie-dmn-ruleset2dmn-parent/kie-dmn-ruleset2dmn/src/main/java/org/kie/dmn/ruleset2dmn/Converter.java @@ -51,7 +51,7 @@ import org.kie.dmn.api.marshalling.DMNMarshaller; import org.kie.dmn.backend.marshalling.v1x.DMNMarshallerFactory; import org.kie.dmn.feel.codegen.feel11.CodegenStringUtil; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.model.api.DMNElementReference; import org.kie.dmn.model.api.Decision; import org.kie.dmn.model.api.DecisionRule; @@ -400,7 +400,7 @@ private static String feelLiteralValue(Object input, Optional df) { case DOUBLE: case FLOAT: case INTEGER: - BigDecimal bdOrNull = EvalHelper.getBigDecimalOrNull(input); + BigDecimal bdOrNull = NumberEvalHelper.getBigDecimalOrNull(input); if (bdOrNull != null) { return bdOrNull.toPlainString(); } else { @@ -413,7 +413,7 @@ private static String feelLiteralValue(Object input, Optional df) { } } LOG.debug("feelLiteralValue for {} and DD not available", input); - BigDecimal bdOrNull = EvalHelper.getBigDecimalOrNull(input); + BigDecimal bdOrNull = NumberEvalHelper.getBigDecimalOrNull(input); if (bdOrNull != null) { return bdOrNull.toPlainString(); } else { diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java index 10802611ba2..e8ccbc9bf93 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java @@ -19,7 +19,6 @@ package org.kie.dmn.signavio; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -54,7 +53,7 @@ import org.kie.dmn.feel.runtime.functions.MaxFunction; import org.kie.dmn.feel.runtime.functions.MinFunction; import org.kie.dmn.feel.runtime.functions.SumFunction; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import org.kie.dmn.model.api.DMNElement.ExtensionElements; import static java.util.Collections.emptySet; @@ -290,7 +289,7 @@ public EvaluatorResult evaluate(DMNRuntimeEventManager eventManager, DMNResult d r = new MaxFunction().invoke(invokationResults); break; case "COUNT": - r = FEELFnResult.ofResult(EvalHelper.getBigDecimalOrNull(invokationResults.size())); + r = FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(invokationResults.size())); break; case "ALLTRUE": r = new AllFunction().invoke(invokationResults); diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayDiffFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayDiffFunction.java index 54f44459f67..8b9f09d5c43 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayDiffFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayDiffFunction.java @@ -32,7 +32,7 @@ import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; import static java.time.ZoneOffset.UTC; import static java.time.temporal.ChronoField.INSTANT_SECONDS; @@ -54,7 +54,7 @@ public FEELFnResult invoke(@ParameterName("datetime1") TemporalAcces } try { - return FEELFnResult.ofResult(EvalHelper.getBigDecimalOrNull( + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull( Duration.between( convertToInstant(datetime1), convertToInstant(datetime2) diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayFunction.java index 91548366573..2b1fa8ae9e1 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/DayFunction.java @@ -18,20 +18,20 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.extended.DateFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.runtime.functions.extended.DateFunction; +import org.kie.dmn.feel.util.NumberEvalHelper; public class DayFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("datetime") TemporalAccess } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.DAY_OF_MONTH ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.DAY_OF_MONTH ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourDiffFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourDiffFunction.java index 6fca0e4a404..4fd67a61417 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourDiffFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourDiffFunction.java @@ -18,6 +18,13 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -26,14 +33,7 @@ import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.Duration; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; public class HourDiffFunction extends BaseFEELFunction { @@ -51,7 +51,7 @@ public FEELFnResult invoke(@ParameterName("datetime1") TemporalAcces } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( Duration.between( (Temporal) datetime1, (Temporal) datetime2 ).toHours() ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(Duration.between((Temporal) datetime1, (Temporal) datetime2 ).toHours() ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourFunction.java index 0082985d3ff..0dd71bc7239 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/HourFunction.java @@ -18,6 +18,12 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -25,13 +31,7 @@ import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; import org.kie.dmn.feel.runtime.functions.extended.TimeFunction; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; public class HourFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("timestring") TemporalAcce } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.HOUR_OF_DAY ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.HOUR_OF_DAY ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "timestring", "invalid 'time' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinuteFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinuteFunction.java index e350685fea0..80343e91f6d 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinuteFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinuteFunction.java @@ -18,6 +18,12 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -25,13 +31,7 @@ import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; import org.kie.dmn.feel.runtime.functions.extended.TimeFunction; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; public class MinuteFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("timestring") TemporalAcce } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.MINUTE_OF_HOUR ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.MINUTE_OF_HOUR ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "timestring", "invalid 'time' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinutesDiffFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinutesDiffFunction.java index f78f324195a..96d3f65d0a9 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinutesDiffFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MinutesDiffFunction.java @@ -18,6 +18,13 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -26,14 +33,7 @@ import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.Duration; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; public class MinutesDiffFunction extends BaseFEELFunction { @@ -51,7 +51,7 @@ public FEELFnResult invoke(@ParameterName("datetime1") TemporalAcces } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( Duration.between( (Temporal) datetime1, (Temporal) datetime2 ).toMinutes() ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(Duration.between((Temporal) datetime1, (Temporal) datetime2 ).toMinutes() ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthDiffFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthDiffFunction.java index 85db0f1a7ec..d09d4212933 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthDiffFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthDiffFunction.java @@ -31,7 +31,7 @@ import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class MonthDiffFunction extends BaseFEELFunction { @@ -49,7 +49,7 @@ public FEELFnResult invoke(@ParameterName("datetime1") TemporalAcces } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( Period.between( LocalDate.from( datetime1 ), LocalDate.from( datetime2 ) ).toTotalMonths() ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(Period.between(LocalDate.from(datetime1 ), LocalDate.from(datetime2 ) ).toTotalMonths() ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthFunction.java index 8f42f95a3d3..626b74f1158 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/MonthFunction.java @@ -18,20 +18,20 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.extended.DateFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.runtime.functions.extended.DateFunction; +import org.kie.dmn.feel.util.NumberEvalHelper; public class MonthFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("datetime") TemporalAccess } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.MONTH_OF_YEAR ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.MONTH_OF_YEAR ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/ProductFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/ProductFunction.java index 9b68dbbc69c..3afc1567478 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/ProductFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/ProductFunction.java @@ -18,16 +18,16 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.List; +import org.kie.dmn.feel.util.NumberEvalHelper; public class ProductFunction extends BaseFEELFunction { @@ -46,7 +46,7 @@ public FEELFnResult invoke(@ParameterName("list") List list) { if ( element instanceof BigDecimal ) { product = product.multiply( (BigDecimal) element ); } else if ( element instanceof Number ) { - product = product.multiply( EvalHelper.getBigDecimalOrNull( element ) ); + product = product.multiply(NumberEvalHelper.getBigDecimalOrNull(element ) ); } else { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "list", "an element in the list is not suitable for the product")); } @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("list") Number single) { if( single instanceof BigDecimal ) { return FEELFnResult.ofResult((BigDecimal) single ); } - BigDecimal result = EvalHelper.getBigDecimalOrNull( single ); + BigDecimal result = NumberEvalHelper.getBigDecimalOrNull( single ); if ( result != null ) { return FEELFnResult.ofResult( result ); } else { diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondFunction.java index fe36214fd53..33f68a7fb82 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondFunction.java @@ -18,6 +18,12 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -25,13 +31,7 @@ import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; import org.kie.dmn.feel.runtime.functions.extended.TimeFunction; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; public class SecondFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("timestring") TemporalAcce } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.SECOND_OF_MINUTE ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.SECOND_OF_MINUTE ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "timestring", "invalid 'time' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondsDiffFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondsDiffFunction.java index 4cddad5056a..7cfd4833bf3 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondsDiffFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/SecondsDiffFunction.java @@ -18,6 +18,13 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -26,14 +33,7 @@ import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.Duration; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.util.NumberEvalHelper; public class SecondsDiffFunction extends BaseFEELFunction { @@ -51,7 +51,7 @@ public FEELFnResult invoke(@ParameterName("datetime1") TemporalAcces } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( Duration.between( (Temporal) datetime1, (Temporal) datetime2 ).getSeconds() ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(Duration.between((Temporal) datetime1, (Temporal) datetime2 ).getSeconds() ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/TextOccurrencesFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/TextOccurrencesFunction.java index 4fc1b363d68..115a8de2cef 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/TextOccurrencesFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/TextOccurrencesFunction.java @@ -25,7 +25,7 @@ import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class TextOccurrencesFunction extends BaseFEELFunction { @@ -49,6 +49,6 @@ public FEELFnResult invoke(@ParameterName("find_text") String find_t } } - return FEELFnResult.ofResult(EvalHelper.getBigDecimalOrNull(occurences)); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(occurences)); } } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/WeekdayFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/WeekdayFunction.java index 141d1770623..d05ead994b3 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/WeekdayFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/WeekdayFunction.java @@ -18,20 +18,20 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.extended.DateFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.runtime.functions.extended.DateFunction; +import org.kie.dmn.feel.util.NumberEvalHelper; public class WeekdayFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("datetime") TemporalAccess } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.DAY_OF_WEEK ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.DAY_OF_WEEK ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearDiffFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearDiffFunction.java index 742ec7d7dba..f2d112ecd03 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearDiffFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearDiffFunction.java @@ -31,7 +31,7 @@ import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.NumberEvalHelper; public class YearDiffFunction extends BaseFEELFunction { @@ -49,7 +49,7 @@ public FEELFnResult invoke(@ParameterName("datetime1") TemporalAcces } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( Period.between( LocalDate.from( datetime1 ), LocalDate.from( datetime2 ) ).toTotalMonths() / 12 ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(Period.between(LocalDate.from(datetime1 ), LocalDate.from(datetime2 ) ).toTotalMonths() / 12 ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearFunction.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearFunction.java index 6701c649ad6..5be95fc4204 100644 --- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearFunction.java +++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/feel/runtime/functions/YearFunction.java @@ -18,20 +18,20 @@ */ package org.kie.dmn.signavio.feel.runtime.functions; +import java.math.BigDecimal; +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; + import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.extended.DateFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import org.kie.dmn.feel.util.EvalHelper; - -import java.math.BigDecimal; -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.function.Function; +import org.kie.dmn.feel.runtime.functions.extended.DateFunction; +import org.kie.dmn.feel.util.NumberEvalHelper; public class YearFunction extends BaseFEELFunction { @@ -63,7 +63,7 @@ public FEELFnResult invoke(@ParameterName("datetime") TemporalAccess } try { - return FEELFnResult.ofResult( EvalHelper.getBigDecimalOrNull( datetime.get( ChronoField.YEAR ) ) ); + return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(datetime.get(ChronoField.YEAR ) ) ); } catch ( DateTimeException e ) { return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "datetime", "invalid 'date' or 'date and time' parameter", e ) ); } diff --git a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java index ebce9941874..c30c9d8c8a6 100644 --- a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java +++ b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/DMNDTAnalyserValueFromNodeVisitor.java @@ -36,7 +36,7 @@ import org.kie.dmn.feel.lang.ast.visitor.DefaultedVisitor; import org.kie.dmn.feel.lang.impl.FEELBuilder; import org.kie.dmn.feel.lang.impl.FEELImpl; -import org.kie.dmn.feel.util.EvalHelper; +import org.kie.dmn.feel.util.StringEvalHelper; import org.kie.dmn.validation.dtanalysis.model.DDTAOutputEntryExpression; import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.DATE; @@ -82,7 +82,7 @@ public BigDecimal visit(NumberNode n) { @Override public String visit(StringNode n) { - return EvalHelper.unescapeString(n.getText()); + return StringEvalHelper.unescapeString(n.getText()); } @Override From 691347d09d9bc311323ccae3eeb239d3f75472b8 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Mon, 13 May 2024 12:23:27 +0200 Subject: [PATCH 03/10] [private-bamoe-issues#1659] WIP - working compilation. --- .../jsr223/JSR223DTExpressionEvaluator.java | 2 +- .../impl/DMNContextFEELCtxWrapperTest.java | 2 +- .../src/main/java/org/kie/dmn/feel/FEEL.java | 2 +- .../feel11/CompiledFEELSemanticMappings.java | 75 +++++++++---------- .../kie/dmn/feel/lang/EvaluationContext.java | 2 +- .../org/kie/dmn/feel/lang/FEELDialect.java | 4 +- .../kie/dmn/feel/lang/ast/BetweenNode.java | 4 +- .../kie/dmn/feel/lang/ast/UnaryTestNode.java | 4 +- .../lang/ast/infixexecutors/GtExecutor.java | 2 +- .../lang/ast/infixexecutors/GteExecutor.java | 2 +- .../lang/ast/infixexecutors/LtExecutor.java | 2 +- .../lang/ast/infixexecutors/LteExecutor.java | 2 +- .../feel/lang/impl/EvaluationContextImpl.java | 2 +- .../kie/dmn/feel/lang/impl/FEELBuilder.java | 4 +- .../SilentWrappingEvaluationContextImpl.java | 4 +- .../java/org/kie/dmn/feel/runtime/Range.java | 4 +- .../kie/dmn/feel/runtime/impl/RangeImpl.java | 4 +- .../kie/dmn/feel/util/BooleanEvalHelper.java | 32 +++++--- .../feel/codegen/feel11/ManualFilterTest.java | 2 +- .../feel/codegen/feel11/ManualQuantTest.java | 2 +- .../codegen/feel11/ManualUnaryTestsTest.java | 5 +- .../org/kie/dmn/feel/runtime/BFEELTest.java | 59 +++++++++++++++ .../dmn/feel/util/BooleanEvalHelperTest.java | 25 ++++--- 23 files changed, 162 insertions(+), 84 deletions(-) create mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java diff --git a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java index 6998f4db7c6..057f0e632c1 100644 --- a/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java +++ b/kie-dmn/kie-dmn-core-jsr223/src/main/java/org/kie/dmn/core/jsr223/JSR223DTExpressionEvaluator.java @@ -249,7 +249,7 @@ public Object getRootObject() { } @Override - public FEELDialect getDialect() { + public FEELDialect getFEELDialect() { return dialect; } } diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java index 3aa3a2553e7..0cbb990790a 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/impl/DMNContextFEELCtxWrapperTest.java @@ -163,7 +163,7 @@ public Object getRootObject() { } @Override - public FEELDialect getDialect() { + public FEELDialect getFEELDialect() { // Defaulting FEELDialect to FEEL return FEELDialect.FEEL; } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java index 1dd0f2306de..280ed3e6a0e 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/FEEL.java @@ -148,7 +148,7 @@ static FEEL newInstance(ClassLoader cl, List profiles) { * Evaluates the given compiled FEEL expression using the * given EvaluationContext, and returns the result * - * @param expression a FEEL expression + * @param expr a FEEL expression * @param ctx the EvaluationContext to be used for defining * input variables and additional feel event listeners * contextual to this method call 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 21247c33311..2c932e2f1c8 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 @@ -26,6 +26,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.ast.InfixOperator; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.runtime.Range; @@ -131,7 +132,7 @@ public static Boolean exists( return false; } - private static Boolean applyUnaryTest(EvaluationContext ctx, Object test, Object target) { + private static Boolean applyUnaryTest(final EvaluationContext ctx, Object test, Object target) { if (test instanceof UnaryTest) { Boolean result = ((UnaryTest) test).apply(ctx, target); return result != null && result; @@ -167,7 +168,7 @@ public static Boolean notExists( return true; } - public static Object getValue(EvaluationContext ctx, String varName) { + public static Object getValue(final EvaluationContext ctx, String varName) { Object value = ctx.getValue(varName); if (value == null && !ctx.isDefined(varName)) { ctx.notifyEvt(() -> new ASTEventBase(FEELEvent.Severity.ERROR, Msg.createMessage(Msg.UNKNOWN_VARIABLE_REFERENCE, varName), null)); @@ -195,20 +196,18 @@ private static Comparable asComparable(Object s) { } } - public static Boolean coerceToBoolean(EvaluationContext ctx, Object value) { - if (value == null || value instanceof Boolean) { - return (Boolean) value; + public static Boolean coerceToBoolean(final EvaluationContext ctx, Object value) { + Boolean toReturn = BooleanEvalHelper.returnOrDefault(value, ctx.getFEELDialect()); + if (!ctx.getFEELDialect().equals(FEELDialect.BFEEL)) { + ctx.notifyEvt(() -> new ASTEventBase( + FEELEvent.Severity.ERROR, + Msg.createMessage( + Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, + value == null ? "null" : value.getClass(), + "Boolean"), + null)); } - - ctx.notifyEvt(() -> new ASTEventBase( - FEELEvent.Severity.ERROR, - Msg.createMessage( - Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, - value == null ? "null" : value.getClass(), - "Boolean"), - null)); - - return null; + return toReturn; } public static T coerceTo(Class paramType, Object value) { @@ -268,11 +267,11 @@ public static List list(T... a) { * @deprecated does not support short-circuit of the operator */ @Deprecated - public static Boolean and(Object left, Object right) { - return (Boolean) InfixOperator.AND.evaluate(left, right, null); + public static Boolean and(final EvaluationContext ctx, Object left, Object right) { + return (Boolean) InfixOperator.AND.evaluate(left, right, ctx); } - public static Boolean and(Boolean left, Supplier right) { + public static Boolean and(final FEELDialect feelDialect, Boolean left, Supplier right) { if (left != null) { if (left.booleanValue()) { return right.get(); @@ -373,49 +372,49 @@ public static Object pow(final Object left, final Object right, final Evaluation * FEEL spec Table 42 and derivations * Delegates to {@link EvalHelper} except evaluationcontext */ - 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. + public static Boolean lte(final FEELDialect feelDialect, Object left, Object right) { + return or(lt(feelDialect, left, right), + eq(feelDialect, left, right)); // do not use Java || to avoid potential NPE due to FEEL 3vl. } /** * FEEL spec Table 42 and derivations * Delegates to {@link EvalHelper} except evaluationcontext */ - public static Boolean lt(Object left, Object right) { - return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) < 0); + public static Boolean lt(final FEELDialect feelDialect, Object left, Object right) { + return BooleanEvalHelper.compare(left, right, feelDialect, (l, r) -> l.compareTo(r) < 0); } /** * FEEL spec Table 42 and derivations * Delegates to {@link EvalHelper} except evaluationcontext */ - 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. + public static Boolean gte(final FEELDialect feelDialect, Object left, Object right) { + return or(gt(feelDialect, left, right), + eq(feelDialect, left, right)); // do not use Java || to avoid potential NPE due to FEEL 3vl. } /** * FEEL spec Table 42 and derivations * Delegates to {@link EvalHelper} except evaluationcontext */ - public static Boolean gt(Object left, Object right) { - return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) > 0); + public static Boolean gt(final FEELDialect feelDialect, Object left, Object right) { + return BooleanEvalHelper.compare(left, right, feelDialect, (l, r) -> l.compareTo(r) > 0); } /** * FEEL spec Table 41: Specific semantics of equality * Delegates to {@link EvalHelper} except evaluationcontext */ - public static Boolean eq(Object left, Object right) { - return BooleanEvalHelper.isEqual(left, right); + public static Boolean eq(final FEELDialect feelDialect, Object left, Object right) { + return BooleanEvalHelper.isEqual(left, right, feelDialect); } public static Boolean gracefulEq(EvaluationContext ctx, Object left, Object right) { if (left instanceof List) { return ((List) left).contains(right); } else { - return eq(left, right); + return eq(ctx.getFEELDialect(), left, right); } } @@ -434,25 +433,25 @@ public static Boolean between(EvaluationContext ctx, return null; } - Boolean gte = gte(value, start); + Boolean gte = gte(ctx.getFEELDialect(), value, start); if (gte == null) { ctx.notifyEvt(() -> new ASTEventBase(FEELEvent.Severity.ERROR, Msg.createMessage(Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, "value", "start"), null)); } - Boolean lte = lte(value, end); + Boolean lte = lte(ctx.getFEELDialect(),value, end); if (lte == null) { ctx.notifyEvt(() -> new ASTEventBase(FEELEvent.Severity.ERROR, Msg.createMessage(Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, "value", "end"), null)); } - return and(gte, lte); // do not use Java && to avoid potential NPE due to FEEL 3vl. + return and(ctx, gte, lte); // do not use Java && to avoid potential NPE due to FEEL 3vl. } /** * FEEL spec Table 39 */ - public static Boolean ne(Object left, Object right) { - return not(BooleanEvalHelper.isEqual(left, right)); + public static Boolean ne(Object left, Object right, FEELDialect feelDialect) { + return not(BooleanEvalHelper.isEqual(left, right, feelDialect)); } - public static Object negateTest(Object param) { + public static Object negateTest(Object param, FEELDialect feelDialect) { if (param instanceof Boolean) { return param.equals(Boolean.FALSE); } else if (param instanceof UnaryTest) { @@ -463,7 +462,7 @@ public static Object negateTest(Object param) { UnaryTest t = (c, left) -> not(includes(c, param, left)); return t; } else { - UnaryTest t = (c, left) -> not(eq(left, param)); + UnaryTest t = (c, left) -> not(eq(feelDialect, left, param)); return t; } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java index faf12356de5..87353e8aa01 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/EvaluationContext.java @@ -59,5 +59,5 @@ public interface EvaluationContext { Object getRootObject(); - FEELDialect getDialect(); + FEELDialect getFEELDialect(); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java index 4d1d68186cf..1005f2f4c35 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java @@ -6,9 +6,9 @@ * 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 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 bc8d5c50bcf..e482ff528fb 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 @@ -99,14 +99,14 @@ public Object evaluate(EvaluationContext ctx) { } if (problem) return null; - Object gte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_s, (l, r) -> l.compareTo(r) > 0), + Object gte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_s, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) > 0), BooleanEvalHelper.isEqual(o_val, o_s), 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 = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_e, (l, r) -> l.compareTo(r) < 0), + Object lte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_e,ctx.getFEELDialect(), (l, r) -> l.compareTo(r) < 0), BooleanEvalHelper.isEqual(o_val, o_e), ctx); // do not use Java || to avoid potential NPE due to FEEL 3vl. if (lte == null) { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java index a3dafdd8818..d1a6dc1bc1b 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java @@ -25,6 +25,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.FEELDialect; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.UnaryTest; import org.kie.dmn.feel.runtime.UnaryTestImpl; @@ -130,7 +131,8 @@ public UnaryTest evaluate(EvaluationContext ctx) { private UnaryTest createCompareUnaryTest( BiPredicate op ) { return (context, left) -> { Object right = value.evaluate( context ); - return BooleanEvalHelper.compare(left, right, op ); + // Defaulting FEELDialect to FEEL + return BooleanEvalHelper.compare(left, right, FEELDialect.FEEL, op ); }; } 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 index f69ba4b21ba..da1457c24da 100644 --- 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 @@ -35,7 +35,7 @@ public static GtExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) > 0); + return BooleanEvalHelper.compare(left, right, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) > 0); } @Override 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 index b2147d296d0..30d128cc8a8 100644 --- 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 @@ -37,7 +37,7 @@ public static GteExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return or(BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) > 0), + return or(BooleanEvalHelper.compare(left, right, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) > 0), BooleanEvalHelper.isEqual(left, right), ctx); // 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/lang/ast/infixexecutors/LtExecutor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/LtExecutor.java index 2481d435c9f..96a7577d319 100644 --- 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 @@ -35,7 +35,7 @@ public static LtExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) < 0); + return BooleanEvalHelper.compare(left, right, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) < 0); } @Override 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 index 4a1ba7f0444..f8a5a9cde2d 100644 --- 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 @@ -37,7 +37,7 @@ public static LteExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return or(BooleanEvalHelper.compare(left, right, (l, r) -> l.compareTo(r) < 0), + return or(BooleanEvalHelper.compare(left, right, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) < 0), BooleanEvalHelper.isEqual(left, right), ctx); // 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/lang/impl/EvaluationContextImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java index 47759d0aefa..a5c5b24fa8a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/EvaluationContextImpl.java @@ -228,7 +228,7 @@ public Object getRootObject() { } @Override - public FEELDialect getDialect() { + public FEELDialect getFEELDialect() { return feelDialect; } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java index 60d4797cea7..7adeb17ac15 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/FEELBuilder.java @@ -6,9 +6,9 @@ * 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 diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java index 19e3f800d2f..cf5d6f157a6 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/impl/SilentWrappingEvaluationContextImpl.java @@ -119,7 +119,7 @@ public ClassLoader getRootClassLoader() { } @Override - public FEELDialect getDialect() { - return wrapped.getDialect(); + public FEELDialect getFEELDialect() { + return wrapped.getFEELDialect(); } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java index a334beaeb9e..2bea2d31992 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java @@ -18,9 +18,11 @@ */ package org.kie.dmn.feel.runtime; +import org.kie.dmn.feel.lang.FEELDialect; + public interface Range { - static enum RangeBoundary { + enum RangeBoundary { OPEN, CLOSED; } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java index f16ee87dd3a..e120fda434b 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java @@ -20,6 +20,7 @@ import java.util.function.BiPredicate; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.util.BooleanEvalHelper; @@ -126,7 +127,8 @@ private static Boolean compare(Comparable left, Object right, BiPredicate op) { + public static Boolean compare(Object left, Object right, FEELDialect feelDialect, BiPredicate op) { if ( left == null || right == null ) { - return null; + return returnOrDefault(null, feelDialect); } if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) { // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared @@ -94,7 +94,7 @@ public static Boolean compare(Object left, Object right, BiPredicate r = (Comparable) right; return op.test(l, r); } - return null; + return returnOrDefault(null, feelDialect); } /** @@ -104,7 +104,7 @@ public static Boolean compare(Object left, Object right, BiPredicate l.compareTo( r ) == 0 ); + return compare( left, right, feelDialect, (l, r) -> l.compareTo( r ) == 0 ); } /** @@ -181,6 +181,18 @@ public static Boolean isEqualTimeInSemanticD(TemporalAccessor left, TemporalAcce return result; } + public static Boolean returnOrDefault(Object rawReturn, FEELDialect feelDialect) { + if (feelDialect.equals(FEELDialect.BFEEL)) { + if (rawReturn instanceof Boolean bool) { + return bool; + } else { + return false; + } + } else { + return (Boolean) rawReturn; + } + } + static Boolean isEqual(Range left, Range right) { return left.equals( right ); } @@ -191,7 +203,7 @@ static Boolean isEqual(Iterable left, Iterable right) { while( li.hasNext() && ri.hasNext() ) { Object l = li.next(); Object r = ri.next(); - if ( !isEqualObject(l, r ) ) return false; + if ( !isEqual(l, r ) ) return false; } return li.hasNext() == ri.hasNext(); } @@ -203,12 +215,12 @@ static Boolean isEqual(Map left, Map right) { for( Map.Entry le : left.entrySet() ) { Object l = le.getValue(); Object r = right.get( le.getKey() ); - if ( !isEqualObject( l, r ) ) return false; + if ( !isEqual( l, r ) ) return false; } return true; } - static Boolean isEqualObject(Object l, Object r) { + public static Boolean isEqual(Object l, Object r) { if( l instanceof Iterable && r instanceof Iterable && !isEqual( (Iterable) l, (Iterable) r ) ) { return false; } else if( l instanceof Map && r instanceof Map && !isEqual( (Map) l, (Map) r ) ) { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualFilterTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualFilterTest.java index f081a65da67..94aeed8d082 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualFilterTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualFilterTest.java @@ -49,7 +49,7 @@ public Object apply(EvaluationContext feelExprCtx) { @Override public Object apply(EvaluationContext feelExprCtx) { - return gt(feelExprCtx.getValue("item"), K_2); + return gt(feelExprCtx.getFEELDialect(), feelExprCtx.getValue("item"), K_2); } }); } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualQuantTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualQuantTest.java index 7204f3e6417..c7f083876e4 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualQuantTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualQuantTest.java @@ -48,7 +48,7 @@ public static class ManualFilterExpression implements CompiledFEELExpression { public Object apply(EvaluationContext feelExprCtx) { return CompiledFEELSupport.quant(Quantifier.SOME, feelExprCtx) .with(c -> "price", c -> Arrays.asList(K_80, K_11, K_110)) - .satisfies(c -> gt(feelExprCtx.getValue("price"), K_100)); + .satisfies(c -> gt(feelExprCtx.getFEELDialect(), feelExprCtx.getValue("price"), K_100)); } } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java index 5d6165f6536..90ca0366184 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/codegen/feel11/ManualUnaryTestsTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.UnaryTest; import org.kie.dmn.feel.util.NumberEvalHelper; import org.slf4j.Logger; @@ -40,9 +41,9 @@ public class ManualUnaryTestsTest { public static class ManualImpl1 implements CompiledFEELUnaryTests { - private static final UnaryTest UT_a = (feelExprCtx, left) -> lt(left, new BigDecimal(47, MathContext.DECIMAL128)); + private static final UnaryTest UT_a = (feelExprCtx, left) -> lt(FEELDialect.FEEL, left, new BigDecimal(47, MathContext.DECIMAL128)); - private static final UnaryTest UT_b = (feelExprCtx, left) -> lt(left, new BigDecimal(1, MathContext.DECIMAL128)); + private static final UnaryTest UT_b = (feelExprCtx, left) -> lt(FEELDialect.FEEL, left, new BigDecimal(1, MathContext.DECIMAL128)); @Override public List getUnaryTests() { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java new file mode 100644 index 00000000000..cdba168e3c4 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java @@ -0,0 +1,59 @@ +/** + * 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.runtime; + +import java.util.Collection; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.lang.FEELDialect; + + +public class BFEELTest extends BaseFEELTest { + + /** + * WARNING: do not use as JUNit's @Parameters name the index {1} within this test class, as this would result in invalid character in the XML surefire-report + * Original error was: An invalid XML character (Unicode: 0x8) was found in the value of attribute "name" and element is "testcase". + */ + @ParameterizedTest + @MethodSource("data") + protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, BaseFEELTest.FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { + expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); + } + + private static Collection data() { + final Object[][] cases = new Object[][] { + {"\"a\" = 1", false, null}, + {"\"a\" != 1", true, null}, + {"\"a\" < 1", false, null}, + {"\"a\" <= null", false, null}, + {"\"a\" > 1", false, null}, + {"null >= 1", false, null}, + {"not(\"a\")", false, null}, + {"true and \"x\"", false, null}, + {"false or \"x\"", false, null}, + {"\"a\" in [1..100]", false, null}, + {"null between 1 and 100", false, null}, +// {"string(null)", "", null}, +// {"substring(\"a\", \"z\")", "", FEELEvent.Severity.ERROR}, + }; + return addAdditionalParameters(cases, false, FEELDialect.BFEEL); + } +} diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java index 675cd3f4d89..6df5c11b3f1 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/BooleanEvalHelperTest.java @@ -22,6 +22,7 @@ import java.math.BigInteger; import org.junit.jupiter.api.Test; +import org.kie.dmn.feel.lang.FEELDialect; import static org.assertj.core.api.Assertions.assertThat; @@ -30,18 +31,18 @@ class BooleanEvalHelperTest { @Test void numericValuesComparative() { - assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(BooleanEvalHelper.compare(1.0, 2.0, (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(BooleanEvalHelper.compare(1, 2, (l, r) -> l.compareTo(r) > 0)).isFalse(); - assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2, (l, r) -> l.compareTo(r) > 0)).isFalse(); - assertThat(BooleanEvalHelper.compare(1, BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2.3, (l, r) -> l.compareTo(r) == 0)).isFalse(); - assertThat(BooleanEvalHelper.compare(1.2, BigDecimal.valueOf(1.2), (l, r) -> l.compareTo(r) == 0)).isTrue(); - assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 0L, (l, r) -> l.compareTo(r) > 0)).isTrue(); - assertThat(BooleanEvalHelper.compare(10L, BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isFalse(); - assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), BigInteger.valueOf(2), (l, r) -> l.compareTo(r) == 0)).isFalse(); - assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2, (l, r) -> l.compareTo(r) < 0)).isTrue(); - assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2.3, (l, r) -> l.compareTo(r) == 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), BigDecimal.valueOf(2), FEELDialect.FEEL, (l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(1.0, 2.0, FEELDialect.FEEL,(l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(1, 2, FEELDialect.FEEL, (l, r) -> l.compareTo(r) > 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2, FEELDialect.FEEL,(l, r) -> l.compareTo(r) > 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(1, BigDecimal.valueOf(2), FEELDialect.FEEL,(l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2.3, FEELDialect.FEEL,(l, r) -> l.compareTo(r) == 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(1.2, BigDecimal.valueOf(1.2), FEELDialect.FEEL, (l, r) -> l.compareTo(r) == 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 0L, FEELDialect.FEEL, (l, r) -> l.compareTo(r) > 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(10L, BigDecimal.valueOf(2), FEELDialect.FEEL, (l, r) -> l.compareTo(r) < 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), BigInteger.valueOf(2), FEELDialect.FEEL, (l, r) -> l.compareTo(r) == 0)).isFalse(); + assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2, FEELDialect.FEEL, (l, r) -> l.compareTo(r) < 0)).isTrue(); + assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2.3, FEELDialect.FEEL,(l, r) -> l.compareTo(r) == 0)).isFalse(); } } From cdacd5bc077572afd28b67185cdba83d49ac46b9 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Tue, 14 May 2024 10:19:02 +0200 Subject: [PATCH 04/10] [private-bamoe-issues#1659] WIP - working compilation. Put on hold for other refactoring (incubator-kie-issues#1206) --- .../feel11/CompiledFEELSemanticMappings.java | 32 ++++++++++----- .../codegen/feel11/CompiledFEELSupport.java | 2 +- .../dmn/feel/codegen/feel11/Expressions.java | 13 ++++-- .../feel/lang/ast/FunctionInvocationNode.java | 2 +- .../org/kie/dmn/feel/lang/ast/InNode.java | 2 +- .../kie/dmn/feel/lang/ast/InfixOpNode.java | 4 ++ .../kie/dmn/feel/lang/ast/UnaryTestNode.java | 4 +- .../lang/ast/infixexecutors/AndExecutor.java | 9 ++-- .../lang/ast/infixexecutors/EqExecutor.java | 2 +- .../infixexecutors/InfixExecutorUtils.java | 8 ++-- .../lang/ast/infixexecutors/LteExecutor.java | 2 +- .../lang/ast/infixexecutors/NeExecutor.java | 2 +- .../lang/ast/infixexecutors/OrExecutor.java | 8 ++-- .../kie/dmn/feel/runtime/FEELFunction.java | 11 ++++- .../java/org/kie/dmn/feel/runtime/Range.java | 2 +- .../runtime/functions/BaseFEELFunction.java | 32 ++++++++------- .../functions/DecisionTableFunction.java | 2 +- .../feel/runtime/functions/IsFunction.java | 1 - .../functions/ListContainsFunction.java | 4 +- .../feel/runtime/functions/NotFunction.java | 5 +++ .../runtime/functions/StringFunction.java | 5 +++ .../runtime/functions/SubstringFunction.java | 5 +++ .../feel/runtime/functions/SumFunction.java | 1 - .../feel/runtime/functions/TimeFunction.java | 5 +++ .../runtime/functions/WeekOfYearFunction.java | 1 - .../kie/dmn/feel/runtime/impl/RangeImpl.java | 36 ++++++++-------- .../kie/dmn/feel/util/BooleanEvalHelper.java | 41 +++++++++++++++++-- .../org/kie/dmn/feel/runtime/BFEELTest.java | 27 +++++++----- .../dmn/feel/runtime/impl/RangeImplTest.java | 31 +++++++------- .../validation/dtanalysis/model/Interval.java | 4 +- 30 files changed, 197 insertions(+), 106 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 2c932e2f1c8..9d26935784d 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 @@ -79,7 +79,7 @@ public static Boolean includes( Object param) { if (range instanceof Range) { try { - return ((Range) range).includes(param); + return ((Range) range).includes(ctx.getFEELDialect(), param); } catch (Exception e) { // e.g. java.base/java.time.Duration cannot be cast to java.base/java.time.Period ctx.notifyEvt(() -> new ASTEventBase( @@ -137,7 +137,7 @@ private static Boolean applyUnaryTest(final EvaluationContext ctx, Object test, Boolean result = ((UnaryTest) test).apply(ctx, target); return result != null && result; } else if (test instanceof Range) { - Boolean result = ((Range) test).includes(target); + Boolean result = ((Range) test).includes(ctx.getFEELDialect(), target); return result != null && result; } else if (test == null) { return target == null ? true : null; @@ -197,8 +197,10 @@ private static Comparable asComparable(Object s) { } public static Boolean coerceToBoolean(final EvaluationContext ctx, Object value) { - Boolean toReturn = BooleanEvalHelper.returnOrDefault(value, ctx.getFEELDialect()); - if (!ctx.getFEELDialect().equals(FEELDialect.BFEEL)) { + Boolean toReturn = BooleanEvalHelper.getBooleanOrDialectDefault(value, ctx.getFEELDialect()); + if (!ctx.getFEELDialect().equals(FEELDialect.BFEEL) + && value != null + && !(value instanceof Boolean)) { ctx.notifyEvt(() -> new ASTEventBase( FEELEvent.Severity.ERROR, Msg.createMessage( @@ -279,8 +281,7 @@ public static Boolean and(final FEELDialect feelDialect, Boolean left, Supplier< return Boolean.FALSE; //left hand operand is false, we do not need to evaluate right side } } else { - Boolean rightAND = right.get(); - return Boolean.FALSE.equals(rightAND) ? Boolean.FALSE : null; + return BooleanEvalHelper.getFalseOrDialectDefault(right.get(), feelDialect); } } @@ -307,7 +308,17 @@ public static Boolean or(Object left, Object right) { return (Boolean) InfixOperator.OR.evaluate(left, right, null); } - public static Boolean or(Boolean left, Supplier right) { + /** + * FEEL spec Table 38 + * Delegates to {@link InfixOperator} except evaluationcontext + * + * @deprecated does not support short-circuit of the operator + */ + public static Boolean or(final FEELDialect feelDialect, Object left, Object right) { + return BooleanEvalHelper.getBooleanOrDialectDefault(InfixOperator.OR.evaluate(left, right, null), feelDialect); + } + + public static Boolean or(final FEELDialect feelDialect, Boolean left, Supplier right) { if (left != null) { if (!left.booleanValue()) { return right.get(); @@ -373,7 +384,8 @@ public static Object pow(final Object left, final Object right, final Evaluation * Delegates to {@link EvalHelper} except evaluationcontext */ public static Boolean lte(final FEELDialect feelDialect, Object left, Object right) { - return or(lt(feelDialect, left, right), + return or(feelDialect, + lt(feelDialect, left, right), eq(feelDialect, left, right)); // do not use Java || to avoid potential NPE due to FEEL 3vl. } @@ -447,11 +459,11 @@ public static Boolean between(EvaluationContext ctx, /** * FEEL spec Table 39 */ - public static Boolean ne(Object left, Object right, FEELDialect feelDialect) { + public static Boolean ne(FEELDialect feelDialect, Object left, Object right) { return not(BooleanEvalHelper.isEqual(left, right, feelDialect)); } - public static Object negateTest(Object param, FEELDialect feelDialect) { + public static Object negateTest(FEELDialect feelDialect, Object param) { if (param instanceof Boolean) { return param.equals(Boolean.FALSE); } else if (param instanceof UnaryTest) { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java index aed762f5d36..86f183333bc 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompiledFEELSupport.java @@ -433,7 +433,7 @@ public static Object invoke(EvaluationContext feelExprCtx, Object function, Obje // alignment to FunctionInvocationNode List ps = (List) params; if (ps.size() == 1) { - return ((Range) function).includes(ps.get(0)); + return ((Range) function).includes(feelExprCtx.getFEELDialect(), ps.get(0)); } else { feelExprCtx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, Msg.createMessage(Msg.CAN_T_INVOKE_AN_UNARY_TEST_WITH_S_PARAMETERS_UNARY_TESTS_REQUIRE_1_SINGLE_PARAMETER, ps.size()), null)); } 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 404db681118..503fdffc552 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 @@ -34,6 +34,7 @@ import com.github.javaparser.ast.expr.MethodReferenceExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; @@ -154,18 +155,22 @@ private static MethodCallExpr arithmetic(String op, Expression left, Expression } private static MethodCallExpr equality(String op, Expression left, Expression right) { - return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), op, new NodeList<>(left, right)); + return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), op, new NodeList<>(getFeelDialectFromEvaluationContext(), left, right)); } private static MethodCallExpr comparison(String op, Expression left, Expression right) { - return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), op, new NodeList<>(left, right)); + return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), op, new NodeList<>(getFeelDialectFromEvaluationContext(), left, right)); } private static MethodCallExpr booleans(String op, Expression left, Expression right) { Expression l = coerceToBoolean(left); Expression r = supplierLambda(coerceToBoolean(right)); - return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), op, new NodeList<>(l, r)); + return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), op, new NodeList<>(getFeelDialectFromEvaluationContext(), l, r)); + } + + private static MethodCallExpr getFeelDialectFromEvaluationContext() { + return new MethodCallExpr(FeelCtx.FEELCTX, "getFEELDialect"); } public static Expression unary( @@ -197,7 +202,7 @@ public static Expression unary( } public static MethodCallExpr unaryComparison(String operator, Expression right) { - return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), operator, new NodeList<>(LEFT_EXPR, right)); + return new MethodCallExpr(compiledFeelSemanticMappingsFQN(), operator, new NodeList<>(getFeelDialectFromEvaluationContext(), LEFT_EXPR, right)); } public static MethodCallExpr lt(Expression left, Expression right) { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/FunctionInvocationNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/FunctionInvocationNode.java index af632d97d9b..83159a84144 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/FunctionInvocationNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/FunctionInvocationNode.java @@ -117,7 +117,7 @@ public Object evaluate(EvaluationContext ctx) { } else if (value instanceof Range) { if (params.getElements().size() == 1) { Object p = params.getElements().get(0).evaluate(ctx); - return ((Range) value).includes(p); + return ((Range) value).includes(ctx.getFEELDialect(), p); } else { ctx.notifyEvt(astEvent(Severity.ERROR, Msg.createMessage(Msg.CAN_T_INVOKE_AN_UNARY_TEST_WITH_S_PARAMETERS_UNARY_TESTS_REQUIRE_1_SINGLE_PARAMETER, params.getElements().size()))); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InNode.java index f105463d582..d8e931b6ba9 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/InNode.java @@ -88,7 +88,7 @@ private Boolean in(EvaluationContext ctx, Object value, Object expr) { return ((UnaryTest) expr).apply( ctx, value ); } else if ( expr instanceof Range ) { try { - return ((Range) expr).includes( value ); + return ((Range) expr).includes(ctx.getFEELDialect(), value ); } catch ( Exception e ) { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.EXPRESSION_IS_RANGE_BUT_VALUE_IS_NOT_COMPARABLE, value.toString(), expr.toString() ), e ) ); return null; 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 69322892710..0319d12bc67 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 @@ -114,6 +114,10 @@ public Type getResultType() { @Override public Object evaluate(EvaluationContext ctx) { + // TODO {gcardosi} only for analysis + if (true) { + throw new UnsupportedOperationException(); + } if (this.left == null) return null; return operator.evaluate(this, ctx); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java index d1a6dc1bc1b..dc4dc4c7425 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java @@ -173,7 +173,7 @@ private UnaryTest createInUnaryTest() { Object val = value.evaluate( c ); if (val instanceof Range) { try { - return ((Range) val).includes(o); + return ((Range) val).includes(c.getFEELDialect(), o); } catch (Exception e) { c.notifyEvt(astEvent(Severity.ERROR, Msg.createMessage(Msg.EXPRESSION_IS_RANGE_BUT_VALUE_IS_NOT_COMPARABLE, o, val))); throw e; @@ -208,7 +208,7 @@ private UnaryTest createNotUnaryTest() { } } else if( test instanceof Range ) { try { - if( ((Range)test).includes( o ) ) { + if( ((Range)test).includes(c.getFEELDialect(), o ) ) { return false; } } catch ( Exception e ) { 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 index cb49008c14a..6271d91f430 100644 --- 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 @@ -42,16 +42,17 @@ public Object evaluate(Object left, Object right, EvaluationContext ctx) { @Override public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) { - Boolean leftAND = BooleanEvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx)); + Boolean leftAND = BooleanEvalHelper.getBooleanOrDialectDefault(infixNode.getLeft().evaluate(ctx), + ctx.getFEELDialect()); if (leftAND != null) { if (leftAND.booleanValue()) { - return BooleanEvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx)); + return BooleanEvalHelper.getBooleanOrDialectDefault(infixNode.getRight().evaluate(ctx), + ctx.getFEELDialect()); } else { return Boolean.FALSE; //left hand operand is false, we do not need to evaluate right side } } else { - Boolean rightAND = BooleanEvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx)); - return Boolean.FALSE.equals(rightAND) ? Boolean.FALSE : null; + return BooleanEvalHelper.getFalseOrDialectDefault(infixNode.getRight().evaluate(ctx), ctx.getFEELDialect()); } } 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 index dd592a8ed93..f67fccd6c7c 100644 --- 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 @@ -35,7 +35,7 @@ public static EqExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - return BooleanEvalHelper.isEqual(left, right); + return BooleanEvalHelper.isEqual(left, right, ctx.getFEELDialect()); } @Override 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 index 71c73483906..1999a68e974 100644 --- 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 @@ -47,8 +47,8 @@ public class InfixExecutorUtils { */ @Deprecated public static Object or(Object left, Object right, EvaluationContext ctx) { - Boolean l = BooleanEvalHelper.getBooleanOrNull(left); - Boolean r = BooleanEvalHelper.getBooleanOrNull(right); + Boolean l = BooleanEvalHelper.getBooleanOrDialectDefault(left, ctx.getFEELDialect()); + Boolean r = BooleanEvalHelper.getBooleanOrDialectDefault(right, ctx.getFEELDialect()); // 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; @@ -65,8 +65,8 @@ public static Object or(Object left, Object right, EvaluationContext ctx) { */ @Deprecated public static Object and(Object left, Object right, EvaluationContext ctx) { - Boolean l = BooleanEvalHelper.getBooleanOrNull(left); - Boolean r = BooleanEvalHelper.getBooleanOrNull(right); + Boolean l = BooleanEvalHelper.getBooleanOrDialectDefault(left, ctx.getFEELDialect()); + Boolean r = BooleanEvalHelper.getBooleanOrDialectDefault(right, ctx.getFEELDialect()); // 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; 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 index f8a5a9cde2d..f78ed7e9ff1 100644 --- 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 @@ -38,7 +38,7 @@ public static LteExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { return or(BooleanEvalHelper.compare(left, right, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) < 0), - BooleanEvalHelper.isEqual(left, right), + BooleanEvalHelper.isEqual(left, right, ctx.getFEELDialect()), ctx); // 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/lang/ast/infixexecutors/NeExecutor.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/NeExecutor.java index a3607335ed7..f8231f004dd 100644 --- 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 @@ -35,7 +35,7 @@ public static NeExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { - Boolean result = BooleanEvalHelper.isEqual(left, right); + Boolean result = BooleanEvalHelper.isEqual(left, right, ctx.getFEELDialect()); return result != null ? !result : null; } 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 index 4cdcc30ee01..74a58bf8175 100644 --- 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 @@ -21,7 +21,6 @@ import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.ast.InfixOpNode; import org.kie.dmn.feel.util.BooleanEvalHelper; -import org.kie.dmn.feel.util.EvalHelper; import static org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils.or; @@ -43,16 +42,15 @@ public Object evaluate(Object left, Object right, EvaluationContext ctx) { @Override public Object evaluate(InfixOpNode infixNode, EvaluationContext ctx) { - Boolean leftOR = BooleanEvalHelper.getBooleanOrNull(infixNode.getLeft().evaluate(ctx)); + Boolean leftOR = BooleanEvalHelper.getBooleanOrDialectDefault(infixNode.getLeft().evaluate(ctx), ctx.getFEELDialect()); if (leftOR != null) { if (!leftOR.booleanValue()) { - return BooleanEvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx)); + return BooleanEvalHelper.getBooleanOrDialectDefault(infixNode.getRight().evaluate(ctx), ctx.getFEELDialect()); } else { return Boolean.TRUE; //left hand operand is true, we do not need to evaluate right side } } else { - Boolean rightOR = BooleanEvalHelper.getBooleanOrNull(infixNode.getRight().evaluate(ctx)); - return Boolean.TRUE.equals(rightOR) ? Boolean.TRUE : null; + return BooleanEvalHelper.getTrueOrDialectDefault(infixNode.getRight().evaluate(ctx), ctx.getFEELDialect()); } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java index 15941675c02..a248d967c03 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java @@ -70,7 +70,16 @@ public interface FEELFunction { */ Object invokeReflectively(EvaluationContext ctx, Object[] params); - public static class Param { + /** + * The default value to return instead of null, to be used with the B-FEEL syntax + * @return + */ + default Object defaultValue() { + // To be overridden by specific classes for B-FEEL compliance + return null; + } + + class Param { public final String name; public final Type type; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java index 2bea2d31992..eacd4cb6617 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/Range.java @@ -34,6 +34,6 @@ enum RangeBoundary { RangeBoundary getHighBoundary(); - Boolean includes(Object param); + Boolean includes(FEELDialect feelDialect, Object param); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java index 7dcb0a5b26a..5398f4d20e8 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java @@ -36,6 +36,7 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.EvaluationContext; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.Symbol; import org.kie.dmn.feel.lang.impl.NamedParameter; import org.kie.dmn.feel.lang.types.FunctionSymbol; @@ -83,13 +84,8 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { try { boolean isNamedParams = params.length > 0 && params[0] instanceof NamedParameter; if ( !isCustomFunction() ) { - List available = null; - if ( isNamedParams ) { - available = Stream.of( params ).map( p -> ((NamedParameter) p).getName() ).collect( Collectors.toList() ); - } - - CandidateMethod cm = getCandidateMethod( ctx, params, isNamedParams, available ); + CandidateMethod cm = getCandidateMethod( ctx, params, isNamedParams ); if ( cm != null ) { Object result = cm.apply.invoke( this, cm.actualParams ); @@ -107,8 +103,10 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { } else { // CandidateMethod cm could be null also if reflection failed on Platforms not supporting getClass().getDeclaredMethods() String ps = getClass().toString(); - logger.error( "Unable to find function '" + getName() + "( " + ps.substring( 1, ps.length() - 1 ) + " )'" ); - ctx.notifyEvt(() -> new FEELEventBase(Severity.ERROR, "Unable to find function '" + getName() + "( " + ps.substring(1, ps.length() - 1) + " )'", null)); + String parametersString = Arrays.stream(params).map(o -> o == null ? "(null)" : o instanceof String ? String.format("\"%s\"", o) : o.toString()).collect(Collectors.joining(", ")); + String errorMessage = String.format("Unable to find function '%s(%s)' with parameters %s", getName(), ps, parametersString); + logger.error(errorMessage ); + ctx.notifyEvt(() -> new FEELEventBase(Severity.ERROR, errorMessage, null)); } } else { if ( isNamedParams ) { @@ -132,7 +130,7 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { logger.error( "Error trying to call function " + getName() + ".", e ); ctx.notifyEvt( () -> new FEELEventBase( Severity.ERROR, "Error trying to call function " + getName() + ".", e )); } - return null; + return ctx.getFEELDialect().equals(FEELDialect.BFEEL) ? defaultValue() : null; } /** @@ -146,8 +144,12 @@ public Object invoke(EvaluationContext ctx, Object[] params) { } private Object getEitherResult(EvaluationContext ctx, Either source, Supplier> parameterNamesSupplier, - Supplier> parameterValuesSupplier) { - return source.cata((left) -> { + Supplier> parameterValuesSupplier) { + if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) + && source.getOrElse(null) == null) { + source = Either.ofRight(defaultValue()); + } + return source.cata(left -> { ctx.notifyEvt(() -> { if (left instanceof InvalidParametersEvent invalidParametersEvent) { invalidParametersEvent.setNodeName(getName()); @@ -177,7 +179,7 @@ private Object[] rearrangeParameters(Object[] params, List pnames) { return params; } - private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] params, boolean isNamedParams, List available) { + private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] params, boolean isNamedParams) { CandidateMethod candidate = null; // first, look for exact matches for ( Method m : getClass().getDeclaredMethods() ) { @@ -186,7 +188,7 @@ private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] param } Object[] actualParams; - boolean injectCtx = Arrays.stream( m.getParameterTypes() ).anyMatch( p -> EvaluationContext.class.isAssignableFrom( p ) ); + boolean injectCtx = Arrays.stream( m.getParameterTypes() ).anyMatch(EvaluationContext.class::isAssignableFrom); if( injectCtx ) { actualParams = new Object[ params.length + 1 ]; int j = 0; @@ -206,7 +208,7 @@ private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] param actualParams = params; } if( isNamedParams ) { - actualParams = calculateActualParams( ctx, m, actualParams, available ); + actualParams = calculateActualParams( m, actualParams ); if( actualParams == null ) { // incompatible method continue; @@ -292,7 +294,7 @@ private void adjustForVariableParameters(CandidateMethod cm, Class[] paramete } } - private Object[] calculateActualParams(EvaluationContext ctx, Method m, Object[] params, List available) { + private Object[] calculateActualParams(Method m, Object[] params) { Annotation[][] pas = m.getParameterAnnotations(); List names = new ArrayList<>( m.getParameterCount() ); for ( int i = 0; i < m.getParameterCount(); i++ ) { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java index 5643ee5922d..9e767b9fe4b 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecisionTableFunction.java @@ -177,7 +177,7 @@ private static UnaryTest toUnaryTest(EvaluationContext ctx, Object o) { } else if ( o instanceof Range ) { return (c, x) -> { try { - return ((Range) o).includes( x ); + return ((Range) o).includes(ctx.getFEELDialect(), x ); } catch ( Exception e ) { ctx.notifyEvt( () -> new FEELEventBase( FEELEvent.Severity.ERROR, Msg.createMessage( Msg.EXPRESSION_IS_RANGE_BUT_VALUE_IS_NOT_COMPARABLE, o.toString(), x.toString() ), diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java index b45d128ae43..6d9ad2889e6 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java @@ -23,7 +23,6 @@ import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.util.BooleanEvalHelper; -import org.kie.dmn.feel.util.EvalHelper; public class IsFunction extends BaseFEELFunction { public static final IsFunction INSTANCE = new IsFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java index d4e92df21ee..ef857b71a64 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ListContainsFunction.java @@ -22,6 +22,7 @@ import java.util.ListIterator; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.BooleanEvalHelper; import org.kie.dmn.feel.util.NumberEvalHelper; @@ -56,7 +57,8 @@ public static boolean itemEqualsSC(Object value, Object itemFromList) { if (value instanceof String) { return value.equals(itemFromList); } else { - Boolean dmnEqual = BooleanEvalHelper.isEqual(value, itemFromList); + // Defaulting FEELDialect to FEEL + Boolean dmnEqual = BooleanEvalHelper.isEqual(value, itemFromList, FEELDialect.FEEL); return dmnEqual != null && dmnEqual; } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NotFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NotFunction.java index 287c63331e3..8454b0c66e7 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NotFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/NotFunction.java @@ -42,4 +42,9 @@ public FEELFnResult invoke(@ParameterName("negand") Object negand) { return FEELFnResult.ofResult( negand == null ? null : !((Boolean) negand) ); } + @Override + public Object defaultValue() { + return false; + } + } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringFunction.java index a5b5629360b..9888aaebd94 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringFunction.java @@ -46,4 +46,9 @@ public FEELFnResult invoke(@ParameterName( "mask" ) String mask, @Parame return FEELFnResult.ofResult( String.format( mask, params ) ); } } + + @Override + public Object defaultValue() { + return ""; + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java index cd5f1939aeb..de59945e99f 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java @@ -62,4 +62,9 @@ public FEELFnResult invoke(@ParameterName("string") String string, @Para StringBuilder result = stream.mapToObj(Character::toChars).collect(StringBuilder::new, StringBuilder::append, StringBuilder::append); return FEELFnResult.ofResult(result.toString()); } + + @Override + public Object defaultValue() { + return ""; + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java index aa2e30013c7..da73fed0674 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java @@ -24,7 +24,6 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.NumberEvalHelper; public class SumFunction diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java index 93564f637d0..f27acab8157 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java @@ -155,4 +155,9 @@ public FEELFnResult invoke(@ParameterName("from") TemporalAcce } } + @Override + public Object defaultValue() { + return invoke("00:00:00+00:00"); + } + } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java index a01aeeae339..2969f002e50 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/WeekOfYearFunction.java @@ -24,7 +24,6 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.NumberEvalHelper; public class WeekOfYearFunction extends BaseFEELFunction { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java index e120fda434b..42e85067b1d 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java @@ -64,7 +64,7 @@ public RangeBoundary getHighBoundary() { } @Override - public Boolean includes(Object param) { + public Boolean includes(FEELDialect feelDialect, Object param) { if (param == null) { return null; } @@ -72,43 +72,44 @@ public Boolean includes(Object param) { if (highEndPoint == null) { return null; } else { - return negInfRangeIncludes(param); + return negInfRangeIncludes(feelDialect, param); } } else { if (highEndPoint == null) { - return posInfRangeIncludes(param); + return posInfRangeIncludes(feelDialect, param); } else { - return finiteRangeIncludes(param); + return finiteRangeIncludes(feelDialect, param); } } } - private Boolean finiteRangeIncludes(Object param) { + private Boolean finiteRangeIncludes(FEELDialect feelDialect, Object param) { + // Defaulting FEELDialect to FEEL if (lowBoundary == RangeBoundary.OPEN && highBoundary == RangeBoundary.OPEN) { - return bothOrThrow(compare(lowEndPoint, param, (l, r) -> l.compareTo(r) < 0) , compare(highEndPoint, param, (l, r) -> l.compareTo(r) > 0), param); + return bothOrThrow(compare(feelDialect, lowEndPoint, param, (l, r) -> l.compareTo(r) < 0) , compare(feelDialect, highEndPoint, param, (l, r) -> l.compareTo(r) > 0), param); } else if (lowBoundary == RangeBoundary.OPEN && highBoundary == RangeBoundary.CLOSED) { - return bothOrThrow(compare(lowEndPoint, param, (l, r) -> l.compareTo(r) < 0) , compare(highEndPoint, param, (l, r) -> l.compareTo(r) >= 0), param); + return bothOrThrow(compare(feelDialect, lowEndPoint, param, (l, r) -> l.compareTo(r) < 0) , compare(feelDialect, highEndPoint, param, (l, r) -> l.compareTo(r) >= 0), param); } else if (lowBoundary == RangeBoundary.CLOSED && highBoundary == RangeBoundary.OPEN) { - return bothOrThrow(compare(lowEndPoint, param, (l, r) -> l.compareTo(r) <= 0) , compare(highEndPoint, param, (l, r) -> l.compareTo(r) > 0), param); + return bothOrThrow(compare(feelDialect, lowEndPoint, param, (l, r) -> l.compareTo(r) <= 0) , compare(feelDialect, highEndPoint, param, (l, r) -> l.compareTo(r) > 0), param); } else if (lowBoundary == RangeBoundary.CLOSED && highBoundary == RangeBoundary.CLOSED) { - return bothOrThrow(compare(lowEndPoint, param, (l, r) -> l.compareTo(r) <= 0) , compare(highEndPoint, param, (l, r) -> l.compareTo(r) >= 0), param); + return bothOrThrow(compare(feelDialect, lowEndPoint, param, (l, r) -> l.compareTo(r) <= 0) , compare(feelDialect, highEndPoint, param, (l, r) -> l.compareTo(r) >= 0), param); } throw new RuntimeException("unknown boundary combination"); } - private Boolean posInfRangeIncludes(Object param) { + private Boolean posInfRangeIncludes(FEELDialect feelDialect, Object param) { if (lowBoundary == RangeBoundary.OPEN) { - return compare(lowEndPoint, param, (l, r) -> l.compareTo(r) < 0); + return compare(feelDialect, lowEndPoint, param, (l, r) -> l.compareTo(r) < 0); } else { - return compare(lowEndPoint, param, (l, r) -> l.compareTo(r) <= 0); + return compare(feelDialect, lowEndPoint, param, (l, r) -> l.compareTo(r) <= 0); } } - private Boolean negInfRangeIncludes(Object param) { + private Boolean negInfRangeIncludes(FEELDialect feelDialect, Object param) { if (highBoundary == RangeBoundary.OPEN) { - return compare(highEndPoint, param, (l, r) -> l.compareTo(r) > 0); + return compare(feelDialect, highEndPoint, param, (l, r) -> l.compareTo(r) > 0); } else { - return compare(highEndPoint, param, (l, r) -> l.compareTo(r) >= 0); + return compare(feelDialect, highEndPoint, param, (l, r) -> l.compareTo(r) >= 0); } } @@ -123,12 +124,11 @@ private static String classOf(Object p) { return p != null ? p.getClass().toString() : "null"; } - private static Boolean compare(Comparable left, Object right, BiPredicate op) { + private static Boolean compare(FEELDialect feelDialect, Comparable left, Object right, BiPredicate op) { if (left.getClass().isAssignableFrom(right.getClass())) { // short path return op.test(left, (Comparable) right); } - // Defaulting FEELDialect to FEEL - return BooleanEvalHelper.compare(left, right, FEELDialect.FEEL, op); // defer to full DMN/FEEL semantic + return BooleanEvalHelper.compare(left, right, feelDialect, op); // defer to full DMN/FEEL semantic } @Override diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java index 3e7fbf89d77..9024c5478f5 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java @@ -30,7 +30,6 @@ import java.util.Optional; import java.util.function.BiPredicate; -import org.kie.dmn.feel.lang.EvaluationContext; import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; @@ -62,7 +61,7 @@ public static Boolean getBooleanOrNull(Object value) { */ public static Boolean compare(Object left, Object right, FEELDialect feelDialect, BiPredicate op) { if ( left == null || right == null ) { - return returnOrDefault(null, feelDialect); + return getBooleanOrDialectDefault(null, feelDialect); } if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) { // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared @@ -94,7 +93,7 @@ public static Boolean compare(Object left, Object right, FEELDialect feelDialect Comparable r = (Comparable) right; return op.test(l, r); } - return returnOrDefault(null, feelDialect); + return getBooleanOrDialectDefault(null, feelDialect); } /** @@ -181,7 +180,13 @@ public static Boolean isEqualTimeInSemanticD(TemporalAccessor left, TemporalAcce return result; } - public static Boolean returnOrDefault(Object rawReturn, FEELDialect feelDialect) { + /** + * Return the original object or, depending on the FEELDialect, a default value + * @param rawReturn + * @param feelDialect + * @return + */ + public static Boolean getBooleanOrDialectDefault(Object rawReturn, FEELDialect feelDialect) { if (feelDialect.equals(FEELDialect.BFEEL)) { if (rawReturn instanceof Boolean bool) { return bool; @@ -193,6 +198,34 @@ public static Boolean returnOrDefault(Object rawReturn, FEELDialect feelDialect) } } + /** + * Return TRUE if it is the original object or, depending on the FEELDialect, a default value + * @param rawReturn + * @param feelDialect + * @return + */ + public static Boolean getTrueOrDialectDefault(Object rawReturn, FEELDialect feelDialect) { + if (rawReturn instanceof Boolean bool && bool) { + return bool; + } else { + return getBooleanOrDialectDefault(null, feelDialect); + } + } + + /** + * Return TRUE if it is the original object or, depending on the FEELDialect, a default value + * @param rawReturn + * @param feelDialect + * @return + */ + public static Boolean getFalseOrDialectDefault(Object rawReturn, FEELDialect feelDialect) { + if (rawReturn instanceof Boolean bool && (!bool)) { + return bool; + } else { + return getBooleanOrDialectDefault(null, feelDialect); + } + } + static Boolean isEqual(Range left, Range right) { return left.equals( right ); } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java index cdba168e3c4..3ceeeeba30d 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java @@ -35,22 +35,27 @@ public class BFEELTest extends BaseFEELTest { @ParameterizedTest @MethodSource("data") protected void instanceTest(String expression, Object result, FEELEvent.Severity severity, BaseFEELTest.FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect feelDialect) { - expression( expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); + try { + expression(expression, result, severity, testFEELTarget, useExtendedProfile, feelDialect); + } catch (UnsupportedOperationException e) { + e.printStackTrace(); + } } private static Collection data() { final Object[][] cases = new Object[][] { + //{"\"a\"", "a", null}, {"\"a\" = 1", false, null}, - {"\"a\" != 1", true, null}, - {"\"a\" < 1", false, null}, - {"\"a\" <= null", false, null}, - {"\"a\" > 1", false, null}, - {"null >= 1", false, null}, - {"not(\"a\")", false, null}, - {"true and \"x\"", false, null}, - {"false or \"x\"", false, null}, - {"\"a\" in [1..100]", false, null}, - {"null between 1 and 100", false, null}, +// {"\"a\" != 1", true, null}, +// {"\"a\" < 1", false, null}, +// {"\"a\" <= null", false, null}, +// {"\"a\" > 1", false, null}, +// {"null >= 1", false, null}, +// {"not(\"a\")", false, null}, +// {"true and \"x\"", false, null}, +// {"false or \"x\"", false, null}, +// {"\"a\" in [1..100]", false, null}, +// {"null between 1 and 100", false, null}, // {"string(null)", "", null}, // {"substring(\"a\", \"z\")", "", FEELEvent.Severity.ERROR}, }; diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java index 6201fe90b12..33a421d7b1b 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java @@ -19,6 +19,7 @@ package org.kie.dmn.feel.runtime.impl; import org.junit.jupiter.api.Test; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.Range; import static org.assertj.core.api.Assertions.assertThat; @@ -56,27 +57,27 @@ void getHighBoundary() { @Test void includes() { RangeImpl rangeImpl = new RangeImpl(Range.RangeBoundary.OPEN, 10, 15, Range.RangeBoundary.OPEN); - assertThat(rangeImpl.includes(-15)).isFalse(); - assertThat(rangeImpl.includes(5)).isFalse(); - assertThat(rangeImpl.includes(10)).isFalse(); - assertThat(rangeImpl.includes(12)).isTrue(); - assertThat(rangeImpl.includes(15)).isFalse(); - assertThat(rangeImpl.includes(156)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, -15)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 5)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 10)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 12)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 15)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 156)).isFalse(); rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, 10, 15, Range.RangeBoundary.OPEN); - assertThat(rangeImpl.includes(10)).isTrue(); - assertThat(rangeImpl.includes(12)).isTrue(); - assertThat(rangeImpl.includes(15)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 10)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 12)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 15)).isFalse(); rangeImpl = new RangeImpl(Range.RangeBoundary.OPEN, 10, 15, Range.RangeBoundary.CLOSED); - assertThat(rangeImpl.includes(10)).isFalse(); - assertThat(rangeImpl.includes(12)).isTrue(); - assertThat(rangeImpl.includes(15)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 10)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 12)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 15)).isTrue(); rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, 10, 15, Range.RangeBoundary.CLOSED); - assertThat(rangeImpl.includes(10)).isTrue(); - assertThat(rangeImpl.includes(12)).isTrue(); - assertThat(rangeImpl.includes(15)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 10)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 12)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 15)).isTrue(); } @Test diff --git a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java index bb9c9ca09c4..421c7d7e716 100644 --- a/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java +++ b/kie-dmn/kie-dmn-validation/src/main/java/org/kie/dmn/validation/dtanalysis/model/Interval.java @@ -27,6 +27,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.Range.RangeBoundary; import org.kie.dmn.feel.runtime.impl.RangeImpl; @@ -168,7 +169,8 @@ public boolean equals(Object obj) { } public boolean asRangeIncludes(Object param) { - Boolean result = this.asRange.includes(param); + // Defaulting FEELDialect to FEEL + Boolean result = this.asRange.includes(FEELDialect.FEEL, param); if (result != null) { return result; } else if (this.lowerBound.getValue() == NEG_INF && From 1315b485e6e177718ff0650b07a6f34c3c2c9be0 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Thu, 27 Jun 2024 09:29:26 +0200 Subject: [PATCH 05/10] [private-bamoe-issues#1659] Implementing B-FEEL - overall working. Suspend to refactor functions as per incubator-kie-issues#1344 --- .../feel11/CompilerBytecodeLoader.java | 4 - .../kie/dmn/feel/lang/ast/BetweenNode.java | 3 +- .../kie/dmn/feel/lang/ast/InfixOpNode.java | 4 - .../dmn/feel/runtime/FEELBooleanFunction.java | 27 ++++ .../feel/runtime/FEELCollectionFunction.java | 29 ++++ .../feel/runtime/FEELDurationFunction.java | 29 ++++ .../kie/dmn/feel/runtime/FEELFunction.java | 18 +++ .../dmn/feel/runtime/FEELNumberFunction.java | 35 +++++ .../dmn/feel/runtime/FEELRangeFunction.java | 31 ++++ .../dmn/feel/runtime/FEELStringFunction.java | 27 ++++ .../feel/runtime/functions/AllFunction.java | 3 +- .../feel/runtime/functions/AnyFunction.java | 4 +- .../runtime/functions/BaseFEELFunction.java | 68 ++++++-- .../runtime/functions/CeilingFunction.java | 1 - .../runtime/functions/ContainsFunction.java | 3 +- .../feel/runtime/functions/CountFunction.java | 9 +- .../feel/runtime/functions/DateFunction.java | 13 +- .../runtime/functions/DayOfWeekFunction.java | 3 +- .../runtime/functions/DayOfYearFunction.java | 3 +- .../runtime/functions/DecimalFunction.java | 4 +- .../runtime/functions/DurationFunction.java | 3 +- .../runtime/functions/MatchesFunction.java | 3 +- .../feel/runtime/functions/MeanFunction.java | 3 +- .../runtime/functions/MedianFunction.java | 3 +- .../feel/runtime/functions/ModeFunction.java | 8 +- .../runtime/functions/ProductFunction.java | 3 +- .../feel/runtime/functions/SplitFunction.java | 3 +- .../runtime/functions/StddevFunction.java | 3 +- .../functions/StringLengthFunction.java | 4 +- .../functions/StringLowerCaseFunction.java | 4 +- .../functions/StringUpperCaseFunction.java | 3 +- .../runtime/functions/SubstringFunction.java | 7 +- .../feel/runtime/functions/SumFunction.java | 3 +- .../feel/runtime/functions/TimeFunction.java | 19 ++- .../functions/YearsAndMonthsFunction.java | 3 +- .../functions/extended/DateFunction.java | 83 ++-------- .../functions/extended/DurationFunction.java | 3 +- .../functions/extended/RangeFunction.java | 3 +- .../functions/extended/RoundUpFunction.java | 3 +- .../functions/extended/TimeFunction.java | 148 ++---------------- .../functions/interval/BeforeFunction.java | 5 + .../kie/dmn/feel/util/DateTimeEvalHelper.java | 1 - .../org/kie/dmn/feel/runtime/BFEELTest.java | 51 +++++- .../kie/dmn/feel/runtime/BaseFEELTest.java | 36 ++--- 44 files changed, 419 insertions(+), 304 deletions(-) create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java create mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompilerBytecodeLoader.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompilerBytecodeLoader.java index 37150828de9..7f9d367f756 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompilerBytecodeLoader.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/codegen/feel11/CompilerBytecodeLoader.java @@ -23,17 +23,13 @@ import java.util.List; import java.util.Map.Entry; import java.util.Optional; -import java.util.Set; import java.util.UUID; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.comments.JavadocComment; -import com.github.javaparser.ast.expr.CastExpr; -import com.github.javaparser.ast.expr.EnclosedExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.NullLiteralExpr; 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 17299ec5571..b12abcdddbc 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 @@ -21,6 +21,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.FEELDialect; import org.kie.dmn.feel.lang.Type; import org.kie.dmn.feel.lang.ast.infixexecutors.InfixExecutorUtils; import org.kie.dmn.feel.lang.types.BuiltInType; @@ -104,7 +105,7 @@ public Object evaluate(EvaluationContext ctx) { ctx.notifyEvt(astEvent(Severity.ERROR, Msg.createMessage(Msg.IS_NULL, "end"))); problem = true; } - if (problem) return null; + if (problem && ctx.getFEELDialect() != FEELDialect.BFEEL) return null; Object gte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_s, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) > 0), BooleanEvalHelper.isEqual(o_val, o_s), 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 326402d0373..d4c56eb7aa2 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 @@ -121,10 +121,6 @@ public Type getResultType() { @Override public Object evaluate(EvaluationContext ctx) { - // TODO {gcardosi} only for analysis - if (true) { - throw new UnsupportedOperationException(); - } if (this.left == null) return null; return operator.evaluate(this, ctx); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java new file mode 100644 index 00000000000..495da7211ef --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java @@ -0,0 +1,27 @@ +/** + * 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.runtime; + +public interface FEELBooleanFunction extends FEELFunction { + + @Override + default Object defaultValue() { + return false; + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java new file mode 100644 index 00000000000..ec0dda0626d --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java @@ -0,0 +1,29 @@ +/** + * 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.runtime; + +import java.util.Collections; + +public interface FEELCollectionFunction extends FEELFunction { + + @Override + default Object defaultValue() { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java new file mode 100644 index 00000000000..f748c3c2acb --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java @@ -0,0 +1,29 @@ +/** + * 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.runtime; + +import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; + +public interface FEELDurationFunction extends FEELFunction { + + @Override + default Object defaultValue() { + return ComparablePeriod.parse("P0M"); + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java index 435654b91d3..9aaf8d6a236 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java @@ -70,6 +70,24 @@ public interface FEELFunction { */ Object invokeReflectively(EvaluationContext ctx, Object[] params); + /** + * The default value to return instead of null, to be used with the B-FEEL syntax + * @return + */ + default Object defaultValue() { + // To be overridden by specific classes for B-FEEL compliance + return null; + } + + /** + * The list to use as input, instead of the original one; to be used with the B-FEEL syntax + * @return + */ + default List emendedList(List toEmend) { + // To be overridden by specific classes for B-FEEL compliance + return toEmend; + } + class Param { public final String name; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java new file mode 100644 index 00000000000..b4f8c3e5113 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.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.runtime; + +import java.math.BigDecimal; +import java.util.List; + +public interface FEELNumberFunction extends FEELFunction { + + @Override + default Object defaultValue() { + return BigDecimal.ZERO; + } + + @Override + default List emendedList(List toEmend) { + return toEmend.stream().filter(element -> (element instanceof Number)).toList(); + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java new file mode 100644 index 00000000000..77db94e2d99 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java @@ -0,0 +1,31 @@ +/** + * 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.runtime; + +import java.math.BigDecimal; + +import org.kie.dmn.feel.runtime.impl.RangeImpl; + +public interface FEELRangeFunction extends FEELFunction { + + @Override + default Object defaultValue() { + return new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ZERO, BigDecimal.ZERO, Range.RangeBoundary.OPEN); + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java new file mode 100644 index 00000000000..ff774bd0729 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java @@ -0,0 +1,27 @@ +/** + * 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.runtime; + +public interface FEELStringFunction extends FEELFunction { + + @Override + default Object defaultValue() { + return ""; + } +} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AllFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AllFunction.java index 08520f44fff..b0a8e5fcb07 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AllFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AllFunction.java @@ -21,10 +21,11 @@ import java.util.Arrays; import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELBooleanFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class AllFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELBooleanFunction { public static final AllFunction INSTANCE = new AllFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java index a8d3abff969..8fd6036160a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java @@ -21,10 +21,11 @@ import java.util.Arrays; import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELBooleanFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class AnyFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELBooleanFunction { public static final AnyFunction INSTANCE = new AnyFunction(); @@ -69,4 +70,5 @@ public FEELFnResult invoke(@ParameterName( "b" ) Object[] list) { return invoke( Arrays.asList( list ) ); } + } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java index 5398f4d20e8..13054f42a56 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java @@ -84,10 +84,23 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { try { boolean isNamedParams = params.length > 0 && params[0] instanceof NamedParameter; if ( !isCustomFunction() ) { + List available = null; + if ( isNamedParams ) { + available = Stream.of( params ).map( p -> ((NamedParameter) p).getName() ).collect( Collectors.toList() ); + } - CandidateMethod cm = getCandidateMethod( ctx, params, isNamedParams ); + + CandidateMethod cm = getCandidateMethod( ctx, params, isNamedParams, available ); if ( cm != null ) { + if (cm.actualParams != null) { + for (int i = 0; i < cm.actualParams.length; i++) { + if (cm.actualParams[i] instanceof List list) { + cm.actualParams[i] = getFEELDialectFixedList(ctx, list); + } + } + } + Object result = cm.apply.invoke( this, cm.actualParams ); if ( result instanceof Either ) { @@ -130,7 +143,7 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { logger.error( "Error trying to call function " + getName() + ".", e ); ctx.notifyEvt( () -> new FEELEventBase( Severity.ERROR, "Error trying to call function " + getName() + ".", e )); } - return ctx.getFEELDialect().equals(FEELDialect.BFEEL) ? defaultValue() : null; + return getFEELDialectFixedObject(ctx, null); } /** @@ -144,12 +157,9 @@ public Object invoke(EvaluationContext ctx, Object[] params) { } private Object getEitherResult(EvaluationContext ctx, Either source, Supplier> parameterNamesSupplier, - Supplier> parameterValuesSupplier) { - if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) - && source.getOrElse(null) == null) { - source = Either.ofRight(defaultValue()); - } - return source.cata(left -> { + Supplier> parameterValuesSupplier) { + source = getFEELDialectFixedEither(ctx, source); + return source.cata((left) -> { ctx.notifyEvt(() -> { if (left instanceof InvalidParametersEvent invalidParametersEvent) { invalidParametersEvent.setNodeName(getName()); @@ -163,6 +173,33 @@ private Object getEitherResult(EvaluationContext ctx, Either }, Function.identity()); } + private Either getFEELDialectFixedEither(EvaluationContext ctx, Either source) { + if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) + && source.getOrElse(null) == null) { + return Either.ofRight(defaultValue()); + } else { + return source; + } + } + + private Object getFEELDialectFixedObject(EvaluationContext ctx, Object source) { + if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) + && source == null) { + return defaultValue(); + } else { + return source; + } + } + + private List getFEELDialectFixedList(EvaluationContext ctx, List source) { + if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) + && source != null) { + return emendedList(source); + } else { + return source; + } + } + private Object[] rearrangeParameters(Object[] params, List pnames) { if ( pnames.size() > 0 ) { Object[] actualParams = new Object[pnames.size()]; @@ -179,14 +216,15 @@ private Object[] rearrangeParameters(Object[] params, List pnames) { return params; } - private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] params, boolean isNamedParams) { + private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] params, boolean isNamedParams, List available) { CandidateMethod candidate = null; // first, look for exact matches - for ( Method m : getClass().getDeclaredMethods() ) { - if ( !Modifier.isPublic(m.getModifiers()) || !m.getName().equals( "invoke" ) ) { - continue; - } - + Method[] declaredMethods = getClass().getMethods(); + List invokeMethods = Arrays.stream(declaredMethods) + .filter(m -> Modifier.isPublic(m.getModifiers()) && + m.getName().equals("invoke")) + .toList(); + for ( Method m : invokeMethods) { Object[] actualParams; boolean injectCtx = Arrays.stream( m.getParameterTypes() ).anyMatch(EvaluationContext.class::isAssignableFrom); if( injectCtx ) { @@ -208,7 +246,7 @@ private CandidateMethod getCandidateMethod(EvaluationContext ctx, Object[] param actualParams = params; } if( isNamedParams ) { - actualParams = calculateActualParams( m, actualParams ); + actualParams = calculateActualParams( m, actualParams ); if( actualParams == null ) { // incompatible method continue; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java index 6d632bf93db..7e7d06758eb 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java @@ -23,7 +23,6 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.FEELFnResult; public class CeilingFunction extends BaseFEELFunction { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ContainsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ContainsFunction.java index 883d8367d0b..5a8c1d12dfb 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ContainsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ContainsFunction.java @@ -19,10 +19,11 @@ package org.kie.dmn.feel.runtime.functions; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELBooleanFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class ContainsFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELBooleanFunction { public static final ContainsFunction INSTANCE = new ContainsFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java index 32d20f455f9..553dea51cea 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java @@ -23,11 +23,13 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELFunction; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.FEELFnResult; public class CountFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final CountFunction INSTANCE = new CountFunction(); @@ -50,4 +52,9 @@ public FEELFnResult invoke(@ParameterName( "c" ) Object[] list) { return invoke( Arrays.asList( list ) ); } + + @Override + public List emendedList(List toEmend) { + return toEmend; + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java index 05f28b8bfde..6ef4f70b4b9 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java @@ -27,6 +27,7 @@ import java.time.temporal.TemporalAccessor; import java.util.regex.Pattern; +import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -66,10 +67,15 @@ public FEELFnResult invoke(@ParameterName( "from" ) String val try { return FEELFnResult.ofResult(LocalDate.from(FEEL_DATE.parse(val))); } catch (DateTimeException e) { - return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "date", e)); + return manageDateTimeException(e, val); } } + public FEELFnResult manageDateTimeException(DateTimeException e, String val) { + return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "date", e)); + } + + public FEELFnResult invoke(@ParameterName( "year" ) Number year, @ParameterName( "month" ) Number month, @ParameterName( "day" ) Number day) { if ( year == null ) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "year", "cannot be null")); @@ -99,4 +105,9 @@ public FEELFnResult invoke(@ParameterName( "from" ) TemporalAc return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "from", "date-parsing exception", e)); } } + + @Override + public Object defaultValue() { + return LocalDate.of(1970, 1, 1); + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfWeekFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfWeekFunction.java index becac394fe5..b7f76c36565 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfWeekFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfWeekFunction.java @@ -24,9 +24,10 @@ import java.util.Locale; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELStringFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -public class DayOfWeekFunction extends BaseFEELFunction { +public class DayOfWeekFunction extends BaseFEELFunction implements FEELStringFunction { public static final DayOfWeekFunction INSTANCE = new DayOfWeekFunction(); DayOfWeekFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java index 9a218dcbefd..ca9d6bc0ec7 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DayOfYearFunction.java @@ -23,10 +23,11 @@ import java.time.temporal.TemporalAccessor; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.NumberEvalHelper; -public class DayOfYearFunction extends BaseFEELFunction { +public class DayOfYearFunction extends BaseFEELFunction implements FEELNumberFunction { public static final DayOfYearFunction INSTANCE = new DayOfYearFunction(); DayOfYearFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java index b62266cda32..cafae5c0357 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java @@ -22,11 +22,11 @@ import java.math.RoundingMode; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.FEELFnResult; public class DecimalFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final DecimalFunction INSTANCE = new DecimalFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DurationFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DurationFunction.java index acf5d8ab587..adad611e2db 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DurationFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DurationFunction.java @@ -25,11 +25,12 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELDurationFunction; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class DurationFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELDurationFunction { public static final DurationFunction INSTANCE = new DurationFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java index e13beaa0fc3..0c49ecdd548 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java @@ -19,6 +19,7 @@ package org.kie.dmn.feel.runtime.functions; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELBooleanFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import java.util.regex.Matcher; @@ -26,7 +27,7 @@ import java.util.regex.PatternSyntaxException; public class MatchesFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELBooleanFunction { public static final MatchesFunction INSTANCE = new MatchesFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java index c53dc339952..b409d5ac17a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java @@ -26,11 +26,12 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.NumberEvalHelper; public class MeanFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final MeanFunction INSTANCE = new MeanFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MedianFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MedianFunction.java index e2a6a6c7092..917926f5ea8 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MedianFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MedianFunction.java @@ -25,10 +25,11 @@ import java.util.stream.Collectors; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class MedianFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final MedianFunction INSTANCE = new MedianFunction(); MedianFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java index 09224dcc621..580c0b2754a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java @@ -28,11 +28,12 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELCollectionFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.NumberEvalHelper; public class ModeFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELCollectionFunction { public static final ModeFunction INSTANCE = new ModeFunction(); ModeFunction() { @@ -67,4 +68,9 @@ public FEELFnResult invoke(@ParameterName("n") Object[] list) { return invoke( Arrays.asList( list ) ); } + + @Override + public List emendedList(List toEmend) { + return toEmend.stream().filter(element -> (element instanceof Number)).toList(); + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java index 689dfafe3af..7344e546f43 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ProductFunction.java @@ -23,11 +23,12 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.NumberEvalHelper; public class ProductFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final ProductFunction INSTANCE = new ProductFunction(); ProductFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SplitFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SplitFunction.java index ba633d17eee..6df27b16ffa 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SplitFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SplitFunction.java @@ -23,10 +23,11 @@ import java.util.regex.PatternSyntaxException; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELCollectionFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class SplitFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELCollectionFunction { public static final SplitFunction INSTANCE = new SplitFunction(); SplitFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java index 88a3484e9a6..cf660a90812 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StddevFunction.java @@ -24,13 +24,14 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.EvalHelper; import org.kie.dmn.feel.util.NumberEvalHelper; // based on the examples of calculations, stddev is supposed to return sample standard deviation, not population standard deviation public class StddevFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final StddevFunction INSTANCE = new StddevFunction(); StddevFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java index e1c673102a7..2daa55032c1 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java @@ -21,11 +21,12 @@ import java.math.BigDecimal; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.NumberEvalHelper; public class StringLengthFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final StringLengthFunction INSTANCE = new StringLengthFunction(); @@ -40,4 +41,5 @@ public FEELFnResult invoke(@ParameterName("string") String string) { return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(string.codePointCount(0, string.length()))); } } + } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java index c3ee83c4994..2db79917af3 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java @@ -19,10 +19,12 @@ package org.kie.dmn.feel.runtime.functions; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; +import org.kie.dmn.feel.runtime.FEELStringFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class StringLowerCaseFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELStringFunction { public static final StringLowerCaseFunction INSTANCE = new StringLowerCaseFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringUpperCaseFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringUpperCaseFunction.java index 4bffb14476d..f7dc16bfdbf 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringUpperCaseFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringUpperCaseFunction.java @@ -19,10 +19,11 @@ package org.kie.dmn.feel.runtime.functions; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELStringFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class StringUpperCaseFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELStringFunction { public static final StringUpperCaseFunction INSTANCE = new StringUpperCaseFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java index de59945e99f..6de026cdf86 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java @@ -21,10 +21,11 @@ import java.util.stream.IntStream; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELStringFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class SubstringFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELStringFunction { public static final SubstringFunction INSTANCE = new SubstringFunction(); @@ -63,8 +64,4 @@ public FEELFnResult invoke(@ParameterName("string") String string, @Para return FEELFnResult.ofResult(result.toString()); } - @Override - public Object defaultValue() { - return ""; - } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java index da73fed0674..d09272a3da1 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SumFunction.java @@ -23,11 +23,12 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.util.NumberEvalHelper; public class SumFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final SumFunction INSTANCE = new SumFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java index 392e8c47a86..31d8eb04983 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java @@ -63,6 +63,13 @@ public class TimeFunction .withResolverStyle(ResolverStyle.STRICT); } + public static boolean timeStringWithSeconds(String val) { + return timePattern.matcher(val).find(); + } + + private static final BigDecimal NANO_MULT = BigDecimal.valueOf( 1000000000 ); + + public TimeFunction() { super(FEELConversionFunctionNames.TIME); } @@ -71,7 +78,6 @@ public FEELFnResult invoke(@ParameterName("from") String val) if ( val == null ) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "from", "cannot be null")); } - try { TemporalAccessor parsed = FEEL_TIME.parse(val); @@ -90,19 +96,16 @@ public FEELFnResult invoke(@ParameterName("from") String val) ZoneTime zoneTime = ZoneTime.of(asLocalTime, zoneId, hasSeconds); return FEELFnResult.ofResult(zoneTime); } - return FEELFnResult.ofResult(parsed); } catch (DateTimeException e) { - return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "from", e)); + return manageDateTimeException(e, val); } } - public static boolean timeStringWithSeconds(String val) { - return timePattern.matcher(val).find(); + public FEELFnResult manageDateTimeException(DateTimeException e, String val) { + return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "from", e)); } - private static final BigDecimal NANO_MULT = BigDecimal.valueOf( 1000000000 ); - public FEELFnResult invoke( @ParameterName("hour") Number hour, @ParameterName("minute") Number minute, @ParameterName("second") Number seconds) { @@ -173,7 +176,7 @@ public FEELFnResult invoke(@ParameterName("from") TemporalAcce @Override public Object defaultValue() { - return invoke("00:00:00+00:00"); + return OffsetTime.of(0, 0, 0, 0, ZoneOffset.ofHoursMinutes(0, 0)); } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/YearsAndMonthsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/YearsAndMonthsFunction.java index fad88161e98..b2120032515 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/YearsAndMonthsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/YearsAndMonthsFunction.java @@ -28,10 +28,11 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; +import org.kie.dmn.feel.runtime.FEELDurationFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; public class YearsAndMonthsFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELDurationFunction { public static final YearsAndMonthsFunction INSTANCE = new YearsAndMonthsFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DateFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DateFunction.java index e40fd3a77b4..c3dad0e2dbb 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DateFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DateFunction.java @@ -20,93 +20,30 @@ import java.time.DateTimeException; import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.ResolverStyle; -import java.time.format.SignStyle; import java.time.temporal.TemporalAccessor; -import java.util.regex.Pattern; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.BuiltInFunctions; import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; -import org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.YEAR; - -public class DateFunction extends BaseFEELFunction { +public class DateFunction extends org.kie.dmn.feel.runtime.functions.DateFunction { public static final DateFunction INSTANCE = new DateFunction(); - private static final Pattern BEGIN_YEAR = Pattern.compile("^-?(([1-9]\\d\\d\\d+)|(0\\d\\d\\d))-"); // FEEL spec, "specified by XML Schema Part 2 Datatypes", hence: yearFrag ::= '-'? (([1-9] digit digit digit+)) | ('0' digit digit digit)) - private static final DateTimeFormatter FEEL_DATE; - - static { - FEEL_DATE = new DateTimeFormatterBuilder().appendValue(YEAR, 4, 9, SignStyle.NORMAL) - .appendLiteral('-') - .appendValue(MONTH_OF_YEAR, 2) - .appendLiteral('-') - .appendValue(DAY_OF_MONTH, 2) - .toFormatter() - .withResolverStyle(ResolverStyle.STRICT); - } - DateFunction() { - super(FEELConversionFunctionNames.DATE); - } - - public FEELFnResult invoke(@ParameterName("from") String val) { - if (val == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "cannot be null")); - } - if (!BEGIN_YEAR.matcher(val).find()) { // please notice the regex strictly requires the beginning, so we can use find. - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "year not compliant with XML Schema Part 2 Datatypes")); - } - - try { - return FEELFnResult.ofResult(LocalDate.from(FEEL_DATE.parse(val))); - } catch (DateTimeException e) { - // try to parse it as a date time and extract the date component - // NOTE: this is an extension to the standard - return BuiltInFunctions.getFunction(DateAndTimeFunction.class).invoke(val) - .cata(overrideLeft -> FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "date-parsing exception", e)), - this::invoke - ); - } } - public FEELFnResult invoke(@ParameterName("year") Number year, @ParameterName("month") Number month, @ParameterName("day") Number day) { - if (year == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "year", "cannot be null")); - } - if (month == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "month", "cannot be null")); - } - if (day == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "day", "cannot be null")); - } - - try { - return FEELFnResult.ofResult(LocalDate.of(year.intValue(), month.intValue(), day.intValue())); - } catch (DateTimeException e) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "input parameters date-parsing exception", e)); - } + @Override + public FEELFnResult manageDateTimeException(DateTimeException e, String val) { + // try to parse it as a date time and extract the date component + // NOTE: this is an extension to the standard + return BuiltInFunctions.getFunction(DateAndTimeFunction.class).invoke(val) + .cata(overrideLeft -> FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from" + , "date-parsing exception", e)), + this::invoke + ); } - public FEELFnResult invoke(@ParameterName("from") TemporalAccessor date) { - if (date == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "cannot be null")); - } - - try { - return FEELFnResult.ofResult(LocalDate.from(date)); - } catch (DateTimeException e) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "date-parsing exception", e)); - } - } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java index 869efea0035..2df3de753ed 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java @@ -25,6 +25,7 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent; +import org.kie.dmn.feel.runtime.FEELDurationFunction; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; @@ -32,7 +33,7 @@ import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -public class DurationFunction extends BaseFEELFunction { +public class DurationFunction extends BaseFEELFunction implements FEELDurationFunction { public static final DurationFunction INSTANCE = new DurationFunction(); DurationFunction() { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java index 1eac4c6dfe6..db5f1cbe75f 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RangeFunction.java @@ -28,6 +28,7 @@ import org.kie.dmn.feel.parser.feel11.ASTBuilderVisitor; import org.kie.dmn.feel.parser.feel11.FEELParser; import org.kie.dmn.feel.parser.feel11.FEEL_1_1Parser; +import org.kie.dmn.feel.runtime.FEELRangeFunction; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.runtime.Range.RangeBoundary; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; @@ -44,7 +45,7 @@ import java.util.Objects; import java.util.function.Predicate; -public class RangeFunction extends BaseFEELFunction { +public class RangeFunction extends BaseFEELFunction implements FEELRangeFunction { public static final RangeFunction INSTANCE = new RangeFunction(); // Defaulting FEELDialect to FEEL diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RoundUpFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RoundUpFunction.java index e17c90d57df..d2d5ce35d07 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RoundUpFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/RoundUpFunction.java @@ -22,6 +22,7 @@ import java.math.RoundingMode; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; +import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.FEELFnResult; @@ -31,7 +32,7 @@ * provisional access for DMN14-126 */ public class RoundUpFunction - extends BaseFEELFunction { + extends BaseFEELFunction implements FEELNumberFunction { public static final RoundUpFunction INSTANCE = new RoundUpFunction(); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/TimeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/TimeFunction.java index 744474dd615..6b9116f8f8f 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/TimeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/TimeFunction.java @@ -18,158 +18,30 @@ */ package org.kie.dmn.feel.runtime.functions.extended; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.time.DateTimeException; -import java.time.Duration; -import java.time.LocalTime; -import java.time.OffsetTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.ResolverStyle; -import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalQueries; import org.kie.dmn.api.feel.runtime.events.FEELEvent; -import org.kie.dmn.feel.runtime.custom.ZoneTime; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; import org.kie.dmn.feel.runtime.functions.BuiltInFunctions; import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction; -import org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames; import org.kie.dmn.feel.runtime.functions.FEELFnResult; import org.kie.dmn.feel.runtime.functions.ParameterName; -import static org.kie.dmn.feel.runtime.functions.TimeFunction.timeStringWithSeconds; - -public class TimeFunction extends BaseFEELFunction { +public class TimeFunction extends org.kie.dmn.feel.runtime.functions.TimeFunction { public static final TimeFunction INSTANCE = new TimeFunction(); - private static final DateTimeFormatter FEEL_TIME; - - static { - FEEL_TIME = new DateTimeFormatterBuilder().parseCaseInsensitive() - .append(DateTimeFormatter.ISO_LOCAL_TIME) - .optionalStart() - .appendLiteral("@") - .appendZoneRegionId() - .optionalEnd() - .optionalStart() - .appendOffsetId() - .optionalEnd() - .toFormatter() - .withResolverStyle(ResolverStyle.STRICT); - } - TimeFunction() { - super(FEELConversionFunctionNames.TIME); - } - - public FEELFnResult invoke(@ParameterName("from") String val) { - if (val == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "cannot be null")); - } - - try { - TemporalAccessor parsed = FEEL_TIME.parse(val); - - if (parsed.query(TemporalQueries.offset()) != null) { - // it is an offset-zoned time, so I can know for certain an OffsetTime - OffsetTime asOffSetTime = parsed.query(OffsetTime::from); - return FEELFnResult.ofResult(asOffSetTime); - } else if (parsed.query(TemporalQueries.zone()) == null) { - // if it does not contain any zone information at all, then I know for certain is a local time. - LocalTime asLocalTime = parsed.query(LocalTime::from); - return FEELFnResult.ofResult(asLocalTime); - } else if (parsed.query(TemporalQueries.zone()) != null) { - boolean hasZeroSeconds = timeStringWithSeconds(val); - LocalTime asLocalTime = parsed.query(LocalTime::from); - ZoneId zoneId = parsed.query(TemporalQueries.zone()); - ZoneTime zoneTime = ZoneTime.of(asLocalTime, zoneId, hasZeroSeconds); - return FEELFnResult.ofResult(zoneTime); - } - - return FEELFnResult.ofResult(parsed); - } catch (DateTimeException e) { - // try to parse it as a date time and extract the date component - // NOTE: this is an extension to the standard - return BuiltInFunctions.getFunction(DateAndTimeFunction.class).invoke(val) - .cata(overrideLeft -> FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "time-parsing exception", e)), - this::invoke - ); - } } - private static final BigDecimal NANO_MULT = BigDecimal.valueOf(1000000000); - - public FEELFnResult invoke( - @ParameterName("hour") Number hour, @ParameterName("minute") Number minute, - @ParameterName("second") Number seconds) { - return invoke(hour, minute, seconds, null); - } - - public FEELFnResult invoke( - @ParameterName("hour") Number hour, @ParameterName("minute") Number minute, - @ParameterName("second") Number seconds, @ParameterName("offset") Duration offset) { - if (hour == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "hour", "cannot be null")); - } - if (minute == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "minute", "cannot be null")); - } - if (seconds == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "seconds", "cannot be null")); - } - - try { - int nanosecs = 0; - if (seconds instanceof BigDecimal) { - BigDecimal secs = (BigDecimal) seconds; - nanosecs = secs.subtract(secs.setScale(0, RoundingMode.DOWN)).multiply(NANO_MULT).intValue(); - } - - if (offset == null) { - return FEELFnResult.ofResult(LocalTime.of(hour.intValue(), minute.intValue(), seconds.intValue(), - nanosecs)); - } else { - return FEELFnResult.ofResult(OffsetTime.of(hour.intValue(), minute.intValue(), seconds.intValue(), - nanosecs, - ZoneOffset.ofTotalSeconds((int) offset.getSeconds()))); - } - } catch (DateTimeException e) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "time-parsing exception", e)); - } - } - - public FEELFnResult invoke(@ParameterName("from") TemporalAccessor date) { - if (date == null) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "cannot be null")); - } - - try { - // If the temporal accessor type doesn't support time, try to parse it as a date with UTC midnight. - if (!date.isSupported(ChronoField.HOUR_OF_DAY)) { - return BuiltInFunctions.getFunction( DateAndTimeFunction.class ).invoke( date, OffsetTime.of(0, 0, 0, 0, ZoneOffset.UTC) ) - .cata( overrideLeft -> FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "time-parsing exception")), - this::invoke - ); - } else if( date.query( TemporalQueries.offset() ) == null ) { - return FEELFnResult.ofResult(LocalTime.from(date)); - } else { - ZoneId zone = date.query(TemporalQueries.zoneId()); - if (!(zone instanceof ZoneOffset)) { - // TZ is a ZoneRegion, so do NOT normalize (although the result will be unreversible, but will keep what was supplied originally). - // Unfortunately java.time.Parsed is a package-private class, hence will need to re-parse in order to have it instantiated. - return invoke(date.query(TemporalQueries.localTime()) + "@" + zone); - } else { - return FEELFnResult.ofResult(OffsetTime.from(date)); - } - } - } catch (DateTimeException e) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "time-parsing exception", e)); - } + @Override + public FEELFnResult manageDateTimeException(DateTimeException e, String val) { + // try to parse it as a date time and extract the date component + // NOTE: this is an extension to the standard + return BuiltInFunctions.getFunction(DateAndTimeFunction.class).invoke(val) + .cata(overrideLeft -> FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from" + , "time-parsing exception", e)), + this::invoke + ); } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/interval/BeforeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/interval/BeforeFunction.java index 4ae46d43ad1..3611282b002 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/interval/BeforeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/interval/BeforeFunction.java @@ -102,4 +102,9 @@ public FEELFnResult invoke(@ParameterName( "range1" ) Range range1, @Pa } } + @Override + public Object defaultValue() { + return false; + } + } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java index c36ba7905f3..7da39931ab9 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java @@ -28,7 +28,6 @@ import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; -import java.time.temporal.TemporalQuery; import java.util.Optional; import java.util.function.BiPredicate; diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java index 3ceeeeba30d..81ebe1d0922 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java @@ -18,13 +18,23 @@ */ package org.kie.dmn.feel.runtime; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.List; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.FEELDialect; - +import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; +import org.kie.dmn.feel.runtime.custom.ZoneTime; +import org.kie.dmn.feel.runtime.impl.RangeImpl; public class BFEELTest extends BaseFEELTest { @@ -44,8 +54,7 @@ protected void instanceTest(String expression, Object result, FEELEvent.Severity private static Collection data() { final Object[][] cases = new Object[][] { - //{"\"a\"", "a", null}, - {"\"a\" = 1", false, null}, +// {"\"a\" = 1", false, null}, // {"\"a\" != 1", true, null}, // {"\"a\" < 1", false, null}, // {"\"a\" <= null", false, null}, @@ -55,10 +64,42 @@ private static Collection data() { // {"true and \"x\"", false, null}, // {"false or \"x\"", false, null}, // {"\"a\" in [1..100]", false, null}, -// {"null between 1 and 100", false, null}, +// {"null between 1 and 100", false, FEELEvent.Severity.ERROR}, + +// {"matches(\"bad pattern\",\"[0-9\")", false, null}, +// {"before(date(\"2021-01-01\"), null)", false, null}, +// {"all(true,\"x\",true)", false, null}, +// {"any(null)", false, null}, + +// {"decimal(\"a\", 0)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, +// {"round up(\"5.5\", 0)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, +// {"string length(22)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, +// {"day of year(\"a\")", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, +// {"count([1,null,3])", BigDecimal.valueOf(3), null}, +// {"sum([1, null, 3])", BigDecimal.valueOf(4), null}, +// {"sum([1, \"1\" ,3])", BigDecimal.valueOf(4), null}, +// {"sum([])", BigDecimal.ZERO, null}, +// {"mean([\"a\"])", BigDecimal.ZERO, null}, +// {"mean([1, \"a\", 3])", BigDecimal.valueOf(2), null}, +// +// {"lower case(12)", "", FEELEvent.Severity.ERROR}, // {"string(null)", "", null}, +// {"day of week(\"a\")", "", FEELEvent.Severity.ERROR}, // {"substring(\"a\", \"z\")", "", FEELEvent.Severity.ERROR}, + +// {"time(\"a\")", OffsetTime.of(0, 0, 0, 0, ZoneOffset.ofHoursMinutes(0, 0)), null}, +// {"date(null)", LocalDate.of(1970, 1, 1), null}, + +// {"duration(\"a\")", ComparablePeriod.parse("P0M" ) , null}, +// {"years and months duration(null, null)", ComparablePeriod.parse("P0M" ) , null}, + +// {"split(\"abc\", 22)", Collections.emptyList(), FEELEvent.Severity.ERROR}, +// {"mode([null,null,null, 1, 1, 2])", List.of(BigDecimal.ONE), null}, + + {"range(\"x\")", new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ZERO, BigDecimal.ZERO, Range.RangeBoundary.OPEN), null}, + + }; - return addAdditionalParameters(cases, false, FEELDialect.BFEEL); + return addAdditionalParametersForBothProfiles(cases, FEELDialect.BFEEL); } } diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELTest.java index 5e9c612e81f..959734bc994 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BaseFEELTest.java @@ -58,30 +58,6 @@ public enum FEEL_TARGET { public boolean useExtendedProfile; -// public void expression(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, -// Boolean useExtendedProfile) { -// this.expression = expression; -// this.result = result; -// this.severity = severity; -// this.testFEELTarget = testFEELTarget; -// this.useExtendedProfile = useExtendedProfile; -// -// final List profiles = getFEELProfilesForTests(); -// feel = FEELBuilder.builder().withProfiles(profiles).build(); -// final FEELEventListener listener = mock(FEELEventListener.class ); -// feel.addListener( listener ); -// feel.addListener(System.out::println); -// assertResult( expression, result ); -// -// if( severity != null ) { -// final ArgumentCaptor captor = ArgumentCaptor.forClass(FEELEvent.class ); -// verify( listener , atLeastOnce()).onEvent( captor.capture() ); -// assertThat(captor.getValue().getSeverity()).isEqualTo(severity); -// } else { -// verify( listener, never() ).onEvent( any(FEELEvent.class) ); -// } -// } - public void expression(String expression, Object result, FEELEvent.Severity severity, FEEL_TARGET testFEELTarget, Boolean useExtendedProfile, FEELDialect dialect) { this.expression = expression; @@ -135,6 +111,18 @@ protected static List addAdditionalParameters(final Object[][] cases, return toReturn; } + protected static List addAdditionalParametersForBothProfiles(final Object[][] cases, FEELDialect feelDialect) { + final List toReturn = new ArrayList<>(); + final boolean[] useExtendedProfiles = { false, true }; + for (final Object[] c : cases) { + for (boolean useExtendedProfile : useExtendedProfiles) { + toReturn.add(new Object[]{c[0], c[1], c[2], FEEL_TARGET.AST_INTERPRETED, useExtendedProfile, feelDialect}); + toReturn.add(new Object[]{c[0], c[1], c[2], FEEL_TARGET.JAVA_TRANSLATED, useExtendedProfile, feelDialect}); + } + } + return toReturn; + } + private List getFEELProfilesForTests() { final List profiles = new ArrayList<>(); if (testFEELTarget == FEEL_TARGET.JAVA_TRANSLATED) { From 6454b4dbe8f96658b2caad8551a2162e2c21a4f2 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Wed, 8 Jan 2025 12:00:55 +0100 Subject: [PATCH 06/10] [incubator-kie-issues#1742] Working status - compilation and tests succeed --- .../kie/dmn/feel/lang/ast/BetweenNode.java | 6 +- .../kie/dmn/feel/lang/ast/UnaryTestNode.java | 2 +- .../lang/ast/infixexecutors/GteExecutor.java | 2 +- .../dmn/feel/runtime/FEELRangeFunction.java | 31 -------- .../feel/runtime/functions/AnyFunction.java | 1 - .../feel/runtime/functions/CountFunction.java | 1 - .../feel/runtime/functions/DateFunction.java | 7 ++ .../feel/runtime/functions/IsFunction.java | 3 +- .../runtime/functions/MatchesFunction.java | 5 ++ .../feel/runtime/functions/MeanFunction.java | 1 - .../feel/runtime/functions/RangeFunction.java | 7 ++ .../functions/StringLengthFunction.java | 1 - .../functions/StringLowerCaseFunction.java | 1 - .../runtime/functions/SubstringFunction.java | 1 - .../feel/runtime/functions/TimeFunction.java | 7 ++ .../functions/extended/DurationFunction.java | 71 ----------------- .../kie/dmn/feel/runtime/impl/RangeImpl.java | 1 + .../kie/dmn/feel/util/BooleanEvalHelper.java | 6 +- .../dmn/feel/jandex/AbstractJandexTest.java | 10 +-- .../org/kie/dmn/feel/runtime/BFEELTest.java | 77 +++++++++---------- .../dmn/feel/runtime/impl/RangeImplTest.java | 25 +++--- 21 files changed, 91 insertions(+), 175 deletions(-) delete mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java delete mode 100644 kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java 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 b12abcdddbc..e7079db5236 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 @@ -108,14 +108,14 @@ public Object evaluate(EvaluationContext ctx) { if (problem && ctx.getFEELDialect() != FEELDialect.BFEEL) return null; Object gte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_s, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) > 0), - BooleanEvalHelper.isEqual(o_val, o_s), + BooleanEvalHelper.isEqual(o_val, o_s, ctx.getFEELDialect()), 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 = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_e,ctx.getFEELDialect(), (l, r) -> l.compareTo(r) < 0), - BooleanEvalHelper.isEqual(o_val, o_e), + Object lte = InfixExecutorUtils.or(BooleanEvalHelper.compare(o_val, o_e, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) < 0), + BooleanEvalHelper.isEqual(o_val, o_e, ctx.getFEELDialect()), 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"))); diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java index c8127a6633f..b6d3747d6e9 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/UnaryTestNode.java @@ -158,7 +158,7 @@ private Boolean utEqualSemantic(Object left, Object right) { return ((Collection) right).contains(left); } else { // evaluate single entity - return BooleanEvalHelper.isEqual(left, right); + return BooleanEvalHelper.isEqual(left, right, FEELDialect.FEEL); } } 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 index 30d128cc8a8..8ec4ca5bf2e 100644 --- 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 @@ -38,7 +38,7 @@ public static GteExecutor instance() { @Override public Object evaluate(Object left, Object right, EvaluationContext ctx) { return or(BooleanEvalHelper.compare(left, right, ctx.getFEELDialect(), (l, r) -> l.compareTo(r) > 0), - BooleanEvalHelper.isEqual(left, right), + BooleanEvalHelper.isEqual(left, right, ctx.getFEELDialect()), ctx); // 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/runtime/FEELRangeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java deleted file mode 100644 index 77db94e2d99..00000000000 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELRangeFunction.java +++ /dev/null @@ -1,31 +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.runtime; - -import java.math.BigDecimal; - -import org.kie.dmn.feel.runtime.impl.RangeImpl; - -public interface FEELRangeFunction extends FEELFunction { - - @Override - default Object defaultValue() { - return new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ZERO, BigDecimal.ZERO, Range.RangeBoundary.OPEN); - } -} \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java index e7a21db45bd..17006ce7ceb 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/AnyFunction.java @@ -67,5 +67,4 @@ public FEELFnResult invoke(@ParameterName( "b" ) Object[] list) { return invoke( Arrays.asList( list ) ); } - } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java index 2de2941d3b1..2ebba7d5594 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java @@ -23,7 +23,6 @@ import java.util.List; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; -import org.kie.dmn.feel.runtime.FEELFunction; import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java index 1c2e07780e8..b9401814e79 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java @@ -51,6 +51,8 @@ public class DateFunction .withResolverStyle(ResolverStyle.STRICT); } + private static final TemporalAccessor DEFAULT_VALUE = LocalDate.of(1970, 1, 1); + protected DateFunction() { super(FEELConversionFunctionNames.DATE); } @@ -100,6 +102,11 @@ public FEELFnResult invoke(@ParameterName( "from" ) TemporalAc } } + @Override + public Object defaultValue() { + return DEFAULT_VALUE; + } + protected FEELFnResult manageDateTimeException(DateTimeException e, String val) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "date", e)); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java index 36a225d3567..4ea3e45f3a1 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/IsFunction.java @@ -21,6 +21,7 @@ import java.time.chrono.ChronoPeriod; import java.time.temporal.TemporalAccessor; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.util.BooleanEvalHelper; @@ -45,7 +46,7 @@ public FEELFnResult invoke(@ParameterName("value1") Object value1, @Par return FEELFnResult.ofResult(BooleanEvalHelper.isEqualDateTimeInSemanticD(left, right)); } // fallback; continue: } - Boolean fallback = BooleanEvalHelper.isEqual(value1, value2); // if null implying they are not the same semantic domain value. + Boolean fallback = BooleanEvalHelper.isEqual(value1, value2, FEELDialect.FEEL); // if null implying they are not the same semantic domain value. return FEELFnResult.ofResult(fallback != null ? fallback : Boolean.FALSE); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java index 2acb38ad269..e9c0fe7c6d0 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java @@ -57,4 +57,9 @@ public FEELFnResult invoke(@ParameterName("input") String input, @Param return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, errorMessage, e)); } } + + @Override + public Object defaultValue() { + return false; + } } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java index a353ae3db4f..d4798738d66 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MeanFunction.java @@ -28,7 +28,6 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.util.NumberEvalHelper; public class MeanFunction extends BaseFEELFunction implements FEELNumberFunction { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java index ae9d6d526c0..b6601c462b3 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/RangeFunction.java @@ -18,6 +18,7 @@ */ package org.kie.dmn.feel.runtime.functions; +import java.math.BigDecimal; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; @@ -57,6 +58,7 @@ public class RangeFunction extends BaseFEELFunction { public static final RangeFunction INSTANCE = new RangeFunction(); private static EvaluationContext STUBBED; + private static final Range DEFAULT_VALUE = new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ZERO, BigDecimal.ZERO, Range.RangeBoundary.OPEN); private static final List> ALLOWED_NODES = Arrays.asList(baseNode -> baseNode instanceof NullNode, @@ -138,6 +140,11 @@ public FEELFnResult invoke(@ParameterName("from") String from) { return FEELFnResult.ofResult(new RangeImpl(startBoundary, (Comparable) left, (Comparable) right, endBoundary)); } + @Override + public Object defaultValue() { + return DEFAULT_VALUE; + } + protected boolean nodeIsAllowed(BaseNode node) { return ALLOWED_NODES.stream().anyMatch(baseNodePredicate -> baseNodePredicate.test(node)); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java index 4358617ed0a..8c2a45dc478 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLengthFunction.java @@ -41,5 +41,4 @@ public FEELFnResult invoke(@ParameterName("string") String string) { return FEELFnResult.ofResult(NumberEvalHelper.getBigDecimalOrNull(string.codePointCount(0, string.length()))); } } - } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java index acb9ec4d419..f643b2ed1a0 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/StringLowerCaseFunction.java @@ -19,7 +19,6 @@ package org.kie.dmn.feel.runtime.functions; import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity; -import org.kie.dmn.feel.runtime.FEELNumberFunction; import org.kie.dmn.feel.runtime.FEELStringFunction; import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java index 819042ec407..af24d14ea2b 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/SubstringFunction.java @@ -63,5 +63,4 @@ public FEELFnResult invoke(@ParameterName("string") String string, @Para StringBuilder result = stream.mapToObj(Character::toChars).collect(StringBuilder::new, StringBuilder::append, StringBuilder::append); return FEELFnResult.ofResult(result.toString()); } - } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java index 8150480613b..07a20f219ea 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java @@ -49,6 +49,8 @@ public class TimeFunction private static final String timePatternString = "[0-9]{2}[:]{1}[0-9]{2}[:]{1}[0-9]{2}"; private static final Pattern timePattern = Pattern.compile(timePatternString); + private static final TemporalAccessor DEFAULT_VALUE = OffsetTime.of(0, 0, 0, 0, ZoneOffset.ofHoursMinutes(0, 0)); + static { FEEL_TIME = new DateTimeFormatterBuilder().parseCaseInsensitive() .append(DateTimeFormatter.ISO_LOCAL_TIME) @@ -170,6 +172,11 @@ public FEELFnResult invoke(@ParameterName("from") TemporalAcce } } + @Override + public Object defaultValue() { + return DEFAULT_VALUE; + } + protected FEELFnResult manageDateTimeException(DateTimeException e, String val) { return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, "from", e)); } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java deleted file mode 100644 index 2df3de753ed..00000000000 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/extended/DurationFunction.java +++ /dev/null @@ -1,71 +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.runtime.functions.extended; - -import java.time.Duration; -import java.time.format.DateTimeParseException; -import java.time.temporal.TemporalAmount; -import java.util.Arrays; -import java.util.List; - -import org.kie.dmn.api.feel.runtime.events.FEELEvent; -import org.kie.dmn.feel.runtime.FEELDurationFunction; -import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; -import org.kie.dmn.feel.runtime.events.InvalidParametersEvent; -import org.kie.dmn.feel.runtime.functions.BaseFEELFunction; -import org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames; -import org.kie.dmn.feel.runtime.functions.FEELFnResult; -import org.kie.dmn.feel.runtime.functions.ParameterName; - -public class DurationFunction extends BaseFEELFunction implements FEELDurationFunction { - public static final DurationFunction INSTANCE = new DurationFunction(); - - DurationFunction() { - super(FEELConversionFunctionNames.DURATION); - } - - public FEELFnResult invoke(@ParameterName( "from" ) String val) { - if ( val == null ) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "cannot be null")); - } - - try { - // try to parse as days/hours/minute/seconds - return FEELFnResult.ofResult( Duration.parse( val ) ); - } catch( DateTimeParseException e ) { - // if it failed, try to parse as years/months - try { - return FEELFnResult.ofResult(ComparablePeriod.parse(val).normalized()); - } catch( DateTimeParseException e2 ) { - // failed to parse, so return null according to the spec - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "date-parsing exception", - new RuntimeException(new Throwable() { public final List causes = Arrays.asList( new Throwable[]{e, e2} ); } ))); - } - } - - } - - public FEELFnResult invoke(@ParameterName( "from" ) TemporalAmount val) { - if ( val == null ) { - return FEELFnResult.ofError(new InvalidParametersEvent(FEELEvent.Severity.ERROR, "from", "cannot be null")); - } - return FEELFnResult.ofResult( val ); - } - -} diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java index 3d5829037b0..3d8206ae1e5 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/impl/RangeImpl.java @@ -20,6 +20,7 @@ import java.util.function.BiPredicate; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.runtime.Range; import org.kie.dmn.feel.util.BooleanEvalHelper; diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java index 56b93473d42..7a1a6ae4f4e 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BooleanEvalHelper.java @@ -126,15 +126,15 @@ public static Boolean isEqual(Object left, Object right, FEELDialect feelDialect // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared Long l = ComparablePeriod.toTotalMonths((ChronoPeriod) left); Long r = ComparablePeriod.toTotalMonths((ChronoPeriod) right); - return isEqual(l, r); + return isEqual(l, r, feelDialect); } else if (left instanceof TemporalAccessor && right instanceof TemporalAccessor) { // Handle specific cases when both time / datetime TemporalAccessor l = (TemporalAccessor) left; TemporalAccessor r = (TemporalAccessor) right; if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) { - return isEqual(DateTimeEvalHelper.valuet(l), DateTimeEvalHelper.valuet(r)); + return isEqual(DateTimeEvalHelper.valuet(l), DateTimeEvalHelper.valuet(r), feelDialect); } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) { - return isEqual(DateTimeEvalHelper.valuedt(l, r.query(TemporalQueries.zone())), DateTimeEvalHelper.valuedt(r, l.query(TemporalQueries.zone()))); + return isEqual(DateTimeEvalHelper.valuedt(l, r.query(TemporalQueries.zone())), DateTimeEvalHelper.valuedt(r, l.query(TemporalQueries.zone())), feelDialect); } // fallback; continue: } return compare( left, right, feelDialect, (l, r) -> l.compareTo( r ) == 0 ); diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/jandex/AbstractJandexTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/jandex/AbstractJandexTest.java index be3d2f5ad1d..98435ea11f4 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/jandex/AbstractJandexTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/jandex/AbstractJandexTest.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -82,14 +83,13 @@ public void reflectConfigJSON() throws Exception { @SuppressWarnings("unchecked") List> fromJson = jsonb.fromJson(new FileReader("src/main/resources/META-INF/native-image/org.kie/" + moduleName + "/reflect-config.json"), List.class); - List dotNamesInJSON = fromJson.stream().map(m -> DotName.createSimple((String) m.get("name"))).collect(Collectors.toList()); + List dotNamesInJSON = fromJson.stream().map(m -> DotName.createSimple((String) m.get("name"))).toList(); Set foundsViaJandex = founds.stream().map(ClassInfo::name).collect(Collectors.toSet()); - Set foundsViaJSON = dotNamesInJSON.stream().collect(Collectors.toSet()); + Set foundsViaJSON = new HashSet<>(dotNamesInJSON); assertThat(foundsViaJandex) - .as("List of classes found via Jandex during test and listed in JSON file must be same.") - .isEqualTo(foundsViaJSON) - ; + .as("Classes found via Jandex during test and listed in JSON file must be same.") + .hasSameElementsAs(foundsViaJSON); } private Map toReflectConfigMap(ClassInfo found) { diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java index 81ebe1d0922..34385729136 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/BFEELTest.java @@ -20,10 +20,8 @@ import java.math.BigDecimal; import java.time.LocalDate; -import java.time.LocalTime; import java.time.OffsetTime; import java.time.ZoneOffset; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -33,7 +31,6 @@ import org.kie.dmn.api.feel.runtime.events.FEELEvent; import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.types.impl.ComparablePeriod; -import org.kie.dmn.feel.runtime.custom.ZoneTime; import org.kie.dmn.feel.runtime.impl.RangeImpl; public class BFEELTest extends BaseFEELTest { @@ -54,49 +51,49 @@ protected void instanceTest(String expression, Object result, FEELEvent.Severity private static Collection data() { final Object[][] cases = new Object[][] { -// {"\"a\" = 1", false, null}, -// {"\"a\" != 1", true, null}, -// {"\"a\" < 1", false, null}, -// {"\"a\" <= null", false, null}, -// {"\"a\" > 1", false, null}, -// {"null >= 1", false, null}, -// {"not(\"a\")", false, null}, -// {"true and \"x\"", false, null}, -// {"false or \"x\"", false, null}, -// {"\"a\" in [1..100]", false, null}, -// {"null between 1 and 100", false, FEELEvent.Severity.ERROR}, + {"\"a\" = 1", false, null}, + {"\"a\" != 1", true, null}, + {"\"a\" < 1", false, null}, + {"\"a\" <= null", false, null}, + {"\"a\" > 1", false, null}, + {"null >= 1", false, null}, + {"not(\"a\")", false, null}, + {"true and \"x\"", false, null}, + {"false or \"x\"", false, null}, + {"\"a\" in [1..100]", false, null}, + {"null between 1 and 100", false, FEELEvent.Severity.ERROR}, -// {"matches(\"bad pattern\",\"[0-9\")", false, null}, -// {"before(date(\"2021-01-01\"), null)", false, null}, -// {"all(true,\"x\",true)", false, null}, -// {"any(null)", false, null}, + {"matches(\"bad pattern\",\"[0-9\")", false, null}, + {"before(date(\"2021-01-01\"), null)", false, null}, + {"all(true,\"x\",true)", false, null}, + {"any(null)", false, null}, -// {"decimal(\"a\", 0)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, -// {"round up(\"5.5\", 0)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, -// {"string length(22)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, -// {"day of year(\"a\")", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, -// {"count([1,null,3])", BigDecimal.valueOf(3), null}, -// {"sum([1, null, 3])", BigDecimal.valueOf(4), null}, -// {"sum([1, \"1\" ,3])", BigDecimal.valueOf(4), null}, -// {"sum([])", BigDecimal.ZERO, null}, -// {"mean([\"a\"])", BigDecimal.ZERO, null}, -// {"mean([1, \"a\", 3])", BigDecimal.valueOf(2), null}, -// -// {"lower case(12)", "", FEELEvent.Severity.ERROR}, -// {"string(null)", "", null}, -// {"day of week(\"a\")", "", FEELEvent.Severity.ERROR}, -// {"substring(\"a\", \"z\")", "", FEELEvent.Severity.ERROR}, + {"decimal(\"a\", 0)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, + {"round up(\"5.5\", 0)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, + {"string length(22)", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, + {"day of year(\"a\")", BigDecimal.ZERO, FEELEvent.Severity.ERROR}, + {"count([1,null,3])", BigDecimal.valueOf(3), null}, + {"sum([1, null, 3])", BigDecimal.valueOf(4), null}, + {"sum([1, \"1\" ,3])", BigDecimal.valueOf(4), null}, + {"sum([])", BigDecimal.ZERO, null}, + {"mean([\"a\"])", BigDecimal.ZERO, null}, + {"mean([1, \"a\", 3])", BigDecimal.valueOf(2), null}, -// {"time(\"a\")", OffsetTime.of(0, 0, 0, 0, ZoneOffset.ofHoursMinutes(0, 0)), null}, -// {"date(null)", LocalDate.of(1970, 1, 1), null}, + {"lower case(12)", "", FEELEvent.Severity.ERROR}, + {"string(null)", "", null}, + {"day of week(\"a\")", "", FEELEvent.Severity.ERROR}, + {"substring(\"a\", \"z\")", "", FEELEvent.Severity.ERROR}, -// {"duration(\"a\")", ComparablePeriod.parse("P0M" ) , null}, -// {"years and months duration(null, null)", ComparablePeriod.parse("P0M" ) , null}, + {"time(\"a\")", OffsetTime.of(0, 0, 0, 0, ZoneOffset.ofHoursMinutes(0, 0)), null}, + {"date(null)", LocalDate.of(1970, 1, 1), null}, -// {"split(\"abc\", 22)", Collections.emptyList(), FEELEvent.Severity.ERROR}, -// {"mode([null,null,null, 1, 1, 2])", List.of(BigDecimal.ONE), null}, + {"duration(\"a\")", ComparablePeriod.parse("P0M" ) , null}, + {"years and months duration(null, null)", ComparablePeriod.parse("P0M" ) , null}, - {"range(\"x\")", new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ZERO, BigDecimal.ZERO, Range.RangeBoundary.OPEN), null}, + {"split(\"abc\", 22)", Collections.emptyList(), FEELEvent.Severity.ERROR}, + {"mode([null,null,null, 1, 1, 2])", List.of(BigDecimal.ONE), null}, + + {"range(\"[x]\")", new RangeImpl(Range.RangeBoundary.OPEN, BigDecimal.ZERO, BigDecimal.ZERO, Range.RangeBoundary.OPEN), null}, }; diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java index de0160ea52e..f81ddb68f7d 100644 --- a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/impl/RangeImplTest.java @@ -98,25 +98,24 @@ void includes() { assertThat(rangeImpl.includes(FEELDialect.FEEL, 15)).isTrue(); rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, new UndefinedValueComparable(), 15, Range.RangeBoundary.CLOSED); - assertThat(rangeImpl.includes(-1456)).isTrue(); - assertThat(rangeImpl.includes(20)).isFalse(); - assertThat(rangeImpl.includes(null)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, -1456)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 20)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, null)).isNull(); rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, 15, new UndefinedValueComparable(), Range.RangeBoundary.CLOSED); - assertThat(rangeImpl.includes(-1456)).isFalse(); - assertThat(rangeImpl.includes(20)).isTrue(); - assertThat(rangeImpl.includes(null)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, -1456)).isFalse(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 20)).isTrue(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, null)).isNull(); rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, null, new UndefinedValueComparable(), Range.RangeBoundary.CLOSED); - assertThat(rangeImpl.includes(-1456)).isNull(); - assertThat(rangeImpl.includes(20)).isNull(); - assertThat(rangeImpl.includes(null)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, -1456)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 20)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, null)).isNull(); rangeImpl = new RangeImpl(Range.RangeBoundary.CLOSED, new UndefinedValueComparable(), null, Range.RangeBoundary.CLOSED); - assertThat(rangeImpl.includes(-1456)).isNull(); - assertThat(rangeImpl.includes(20)).isNull(); - assertThat(rangeImpl.includes(null)).isNull(); - + assertThat(rangeImpl.includes(FEELDialect.FEEL, -1456)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, 20)).isNull(); + assertThat(rangeImpl.includes(FEELDialect.FEEL, null)).isNull(); } @Test From 70c7668a88b987cb8e4a08839934e4d5ec80f5c9 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Wed, 8 Jan 2025 12:53:51 +0100 Subject: [PATCH 07/10] [incubator-kie-issues#1742] Fixed as per PR suggestion --- .../kie/dmn/feel/runtime/FEELFunction.java | 6 +-- .../dmn/feel/runtime/FEELNumberFunction.java | 4 +- .../runtime/functions/BaseFEELFunction.java | 38 +++++++++++++++---- .../feel/runtime/functions/CountFunction.java | 5 ++- .../feel/runtime/functions/ModeFunction.java | 4 +- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java index 9aaf8d6a236..f2883b23ec2 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELFunction.java @@ -71,7 +71,7 @@ public interface FEELFunction { Object invokeReflectively(EvaluationContext ctx, Object[] params); /** - * The default value to return instead of null, to be used with the B-FEEL syntax + * The default value to return instead of null, to be used with the B-FEEL (and other different dialects) syntax * @return */ default Object defaultValue() { @@ -83,9 +83,9 @@ default Object defaultValue() { * The list to use as input, instead of the original one; to be used with the B-FEEL syntax * @return */ - default List emendedList(List toEmend) { + default List feelDialectAdaptedInputList(List toAdapt) { // To be overridden by specific classes for B-FEEL compliance - return toEmend; + return toAdapt; } class Param { diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java index b4f8c3e5113..8b2a2377f01 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java @@ -29,7 +29,7 @@ default Object defaultValue() { } @Override - default List emendedList(List toEmend) { - return toEmend.stream().filter(element -> (element instanceof Number)).toList(); + default List feelDialectAdaptedInputList(List toAdapt) { + return toAdapt.stream().filter(element -> (element instanceof Number)).toList(); } } \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java index 82513867d55..b8b33bbe21a 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/BaseFEELFunction.java @@ -84,7 +84,7 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { if (cm.actualParams != null) { for (int i = 0; i < cm.actualParams.length; i++) { if (cm.actualParams[i] instanceof List list) { - cm.actualParams[i] = getFEELDialectFixedList(ctx, list); + cm.actualParams[i] = getFEELDialectAdaptedList(ctx, list); } } } @@ -139,7 +139,7 @@ public Object invokeReflectively(EvaluationContext ctx, Object[] params) { ctx.notifyEvt(() -> new FEELEventBase(Severity.ERROR, "Error trying to call function " + getName() + ".", e)); } - return getFEELDialectFixedObject(ctx, null); + return getFEELDialectAdaptedObject(ctx, null); } @Override @@ -226,7 +226,7 @@ private CandidateMethod getBestScoredCandidateMethod(Object[] originalInput, Can private Object getEitherResult(EvaluationContext ctx, Either source, Supplier> parameterNamesSupplier, Supplier> parameterValuesSupplier) { - source = getFEELDialectFixedEither(ctx, source); + source = getFEELDialectAdaptedEither(ctx, source); return source.cata((left) -> { ctx.notifyEvt(() -> { if (left instanceof InvalidParametersEvent invalidParametersEvent) { @@ -241,7 +241,15 @@ private Object getEitherResult(EvaluationContext ctx, Either }, Function.identity()); } - private Either getFEELDialectFixedEither(EvaluationContext ctx, Either source) { + /** + * Adapt the given Either<FEELEvent, Object> to contain FEEL-Dialect-specific value, if needed + * + * @see FEELFunction#defaultValue() + * @param ctx + * @param source + * @return + */ + private Either getFEELDialectAdaptedEither(EvaluationContext ctx, Either source) { if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) && source.getOrElse(null) == null) { return Either.ofRight(defaultValue()); @@ -250,7 +258,15 @@ private Either getFEELDialectFixedEither(EvaluationContext ct } } - private Object getFEELDialectFixedObject(EvaluationContext ctx, Object source) { + /** + * Adapt the given Object to FEEL-Dialect-specific value, if needed + * + * @see FEELFunction#defaultValue() + * @param ctx + * @param source + * @return + */ + private Object getFEELDialectAdaptedObject(EvaluationContext ctx, Object source) { if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) && source == null) { return defaultValue(); @@ -259,10 +275,18 @@ private Object getFEELDialectFixedObject(EvaluationContext ctx, Object source) { } } - private List getFEELDialectFixedList(EvaluationContext ctx, List source) { + /** + * Adapt the given List to FEEL-Dialect-specific values, if needed + * + * @see FEELFunction#feelDialectAdaptedInputList(List) + * @param ctx + * @param source + * @return + */ + private List getFEELDialectAdaptedList(EvaluationContext ctx, List source) { if (ctx.getFEELDialect().equals(FEELDialect.BFEEL) && source != null) { - return emendedList(source); + return feelDialectAdaptedInputList(source); } else { return source; } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java index 2ebba7d5594..2b5c03f9b0d 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CountFunction.java @@ -52,7 +52,8 @@ public FEELFnResult invoke(@ParameterName( "c" ) Object[] list) { } @Override - public List emendedList(List toEmend) { - return toEmend; + public List feelDialectAdaptedInputList(List toAdapt) { + return toAdapt; } + } diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java index 7d2a4daf6fb..1daf7ebcd88 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ModeFunction.java @@ -70,7 +70,7 @@ public FEELFnResult invoke(@ParameterName("n") Object[] list) { } @Override - public List emendedList(List toEmend) { - return toEmend.stream().filter(element -> (element instanceof Number)).toList(); + public List feelDialectAdaptedInputList(List toAdapt) { + return toAdapt.stream().filter(element -> (element instanceof Number)).toList(); } } From 8912aebdb7ee56f98896002ad4e2f4da9bc380c6 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Wed, 8 Jan 2025 13:40:58 +0100 Subject: [PATCH 08/10] [incubator-kie-issues#1742] Extend test coverage --- .../org/kie/dmn/feel/lang/FEELDialect.java | 38 ++++++++- .../kie/dmn/feel/lang/FEELDialectTest.java | 81 +++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/FEELDialectTest.java diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java index 9d821f2407f..81716c03107 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/FEELDialect.java @@ -19,6 +19,10 @@ package org.kie.dmn.feel.lang; import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + public enum FEELDialect { @@ -33,15 +37,41 @@ public enum FEELDialect { public String getNamespace() {return namespace;} + public final static Set STANDARD_FEEL_URIS = getStandardFEELDialectURIS(); + /** - * In current implementation, it returns BFEEL if provided namespace matches, otherwise returns FEEL + * It returns BFEEL if provided namespace matches, + * or FEEL if it matches any of the STANDARD_FEEL_URIS, + * or throws an IllegalArgumentException if no match is found + * * @param namespace * @return */ public static FEELDialect fromNamespace(String namespace) { - return Arrays.stream(FEELDialect.values()) + Optional byNamespace = Arrays.stream(FEELDialect.values()) .filter(dialect -> dialect.getNamespace().equals(namespace)) - .findFirst() - .orElse(FEELDialect.FEEL); + .findFirst(); + if (byNamespace.isPresent()) { + return byNamespace.get(); + } + Optional fromStandardFeelUris = getStandardFeelDialect(namespace); + if (fromStandardFeelUris.isPresent()) { + return fromStandardFeelUris.get(); + } + throw new IllegalArgumentException("Unknown FEEL dialect '" + namespace + "'"); + } + + static Optional getStandardFeelDialect(String namespace) { + return STANDARD_FEEL_URIS.contains(namespace) ? Optional.of(FEEL) : Optional.empty(); + } + + private static Set getStandardFEELDialectURIS() { + Set toReturn = new HashSet<>(); + toReturn.add(org.kie.dmn.model.v1_1.KieDMNModelInstrumentedBase.URI_FEEL); + toReturn.add(org.kie.dmn.model.v1_2.KieDMNModelInstrumentedBase.URI_FEEL); + toReturn.add(org.kie.dmn.model.v1_3.KieDMNModelInstrumentedBase.URI_FEEL); + toReturn.add(org.kie.dmn.model.v1_4.KieDMNModelInstrumentedBase.URI_FEEL); + toReturn.add(org.kie.dmn.model.v1_5.KieDMNModelInstrumentedBase.URI_FEEL); + return toReturn; } } \ No newline at end of file diff --git a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/FEELDialectTest.java b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/FEELDialectTest.java new file mode 100644 index 00000000000..5413711e1e5 --- /dev/null +++ b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/lang/FEELDialectTest.java @@ -0,0 +1,81 @@ +/* + * 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; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.kie.dmn.feel.lang.FEELDialect.STANDARD_FEEL_URIS; + +class FEELDialectTest { + + @Test + void fromNamespaceValid() { + String bFeelNamespace = "https://www.omg.org/spec/DMN/20240513/B-FEEL/"; + assertThat(FEELDialect.fromNamespace(bFeelNamespace)).isEqualTo(FEELDialect.BFEEL); + + String emptyNamespace = ""; + assertThat(FEELDialect.fromNamespace(emptyNamespace)).isEqualTo(FEELDialect.FEEL); + + STANDARD_FEEL_URIS.forEach(namespace -> assertThat(FEELDialect.fromNamespace(namespace)).isEqualTo(FEELDialect.FEEL)); + } + + @Test + void fromNamespaceInvalid() { + String unknownNameSpace = "whatever-get"; + assertThatThrownBy(() -> FEELDialect.fromNamespace(unknownNameSpace)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Unknown FEEL dialect '" + unknownNameSpace + "'"); + String nullNameSpace = null; + assertThatThrownBy(() -> FEELDialect.fromNamespace(nullNameSpace)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Unknown FEEL dialect '" + nullNameSpace + "'"); + } + + @Test + void getStandardFeelDialectValid() { + String bFeelNamespace = "https://www.omg.org/spec/DMN/20240513/B-FEEL/"; + assertThat(FEELDialect.fromNamespace(bFeelNamespace)).isEqualTo(FEELDialect.BFEEL); + + String emptyNamespace = ""; + assertThat(FEELDialect.fromNamespace(emptyNamespace)).isEqualTo(FEELDialect.FEEL); + + STANDARD_FEEL_URIS.forEach(namespace -> assertThat(FEELDialect.getStandardFeelDialect(namespace)) + .isNotEmpty() + .contains(FEELDialect.FEEL)); + } + + @Test + void getStandardFeelDialectInvalid() { + String bFeelNamespace = "https://www.omg.org/spec/DMN/20240513/B-FEEL/"; + assertThat(FEELDialect.getStandardFeelDialect(bFeelNamespace)) + .isEmpty(); + String emptyNamespace = ""; + assertThat(FEELDialect.getStandardFeelDialect(emptyNamespace)) + .isEmpty(); + String unknownNameSpace = "whatever-get"; + assertThat(FEELDialect.getStandardFeelDialect(unknownNameSpace)) + .isEmpty(); + String nullNameSpace = null; + assertThat(FEELDialect.getStandardFeelDialect(nullNameSpace)) + .isEmpty(); + } +} \ No newline at end of file From b9de803219e2fb5de51412f547ad5b11e52d7171 Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Wed, 8 Jan 2025 16:21:34 +0100 Subject: [PATCH 09/10] [incubator-kie-issues#1742] WIP --- .../dmn/core/compiler/DMNCompilerImpl.java | 3 +- .../kie/dmn/core/compiler/DMNFEELHelper.java | 19 ++-- .../org/kie/dmn/core/impl/DMNModelImpl.java | 14 +++ .../kie/dmn/core/pmml/DMNImportPMMLInfo.java | 3 +- .../org/kie/dmn/core/DMNInputRuntimeTest.java | 48 ++++++++++ .../DMNv1_5/B-FEEL/BFeelChecks.dmn | 76 +++++++++++++++ .../DMNv1_5/B-FEEL/ConstraintsChecksBFeel.dmn | 93 +++++++++++++++++++ 7 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/BFeelChecks.dmn create mode 100644 kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/ConstraintsChecksBFeel.dmn diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java index 078a1158036..4b6db70be71 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java @@ -76,6 +76,7 @@ import org.kie.dmn.core.util.Msg; import org.kie.dmn.core.util.MsgUtil; import org.kie.dmn.core.util.NamespaceUtil; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.FEELProfile; import org.kie.dmn.feel.lang.Type; import org.kie.dmn.feel.lang.types.AliasFEELType; @@ -210,7 +211,7 @@ public DMNModel compile(Definitions dmndefs, Collection dmnModels, Res model.setRuntimeTypeCheck(((DMNCompilerConfigurationImpl) dmnCompilerConfig).getOption(RuntimeTypeCheckOption.class).isRuntimeTypeCheck()); DMNCompilerConfigurationImpl cc = (DMNCompilerConfigurationImpl) dmnCompilerConfig; List helperFEELProfiles = cc.getFeelProfiles(); - DMNFEELHelper feel = new DMNFEELHelper(cc.getRootClassLoader(), helperFEELProfiles); + DMNFEELHelper feel = new DMNFEELHelper(cc.getRootClassLoader(), helperFEELProfiles, model.getFeelDialect()); DMNCompilerContext ctx = new DMNCompilerContext(feel); ctx.setRelativeResolver(relativeResolver); List toMerge = new ArrayList<>(); diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java index cf15523da2d..1177431a713 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNFEELHelper.java @@ -73,22 +73,24 @@ public class DMNFEELHelper { private final FEEL feel; private final FEELEventsListenerImpl listener; private final List feelProfiles = new ArrayList<>(); + private final FEELDialect feelDialect; - public DMNFEELHelper(List feelProfiles) { - this(ClassLoaderUtil.findDefaultClassLoader(), feelProfiles); + public DMNFEELHelper(List feelProfiles, FEELDialect feelDialect) { + this(ClassLoaderUtil.findDefaultClassLoader(), feelProfiles, feelDialect); } - public DMNFEELHelper(ClassLoader classLoader, List feelProfiles) { + public DMNFEELHelper(ClassLoader classLoader, List feelProfiles, FEELDialect feelDialect) { this.classLoader = classLoader; this.feelProfiles.addAll(feelProfiles); this.listener = new FEELEventsListenerImpl(); + this.feelDialect = feelDialect; this.feel = createFEELInstance(); } private FEEL createFEELInstance() { - FEEL feel = FEELBuilder.builder().withClassloader(classLoader).withProfiles(feelProfiles).build(); - feel.addListener( listener ); - return feel; + FEEL toReturn = newFEELInstance(); + toReturn.addListener( listener ); + return toReturn; } /** @@ -96,7 +98,10 @@ private FEEL createFEELInstance() { * This FEEL instance is potentially not the same shared by the compiler during the compilation phase. */ public FEEL newFEELInstance() { - return FEELBuilder.builder().withClassloader(classLoader).withProfiles(feelProfiles).build(); + return FEELBuilder.builder().withClassloader(classLoader) + .withProfiles(feelProfiles) + .withFEELDialect(feelDialect) + .build(); } public static boolean valueMatchesInUnaryTests(List unaryTests, Object value, DMNContext dmnContext) { diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNModelImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNModelImpl.java index 6cd1b3a4b6b..d25ed091f4b 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNModelImpl.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNModelImpl.java @@ -68,6 +68,7 @@ import org.kie.dmn.core.compiler.DMNTypeRegistryV15; import org.kie.dmn.core.pmml.DMNImportPMMLInfo; import org.kie.dmn.core.util.DefaultDMNMessagesManager; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.model.api.DMNModelInstrumentedBase; import org.kie.dmn.model.api.Definitions; @@ -107,6 +108,8 @@ private enum SerializationFormat { private ImportChain importChain; + private FEELDialect feelDialect; + public DMNModelImpl() { // needed because Externalizable. } @@ -116,6 +119,13 @@ public DMNModelImpl(Definitions definitions) { wireTypeRegistry(definitions); importChain = new ImportChain(this); messages = new DefaultDMNMessagesManager(null); + String feelUri = definitions.getNsContext().get("feel"); + try { + feelDialect = FEELDialect.fromNamespace(feelUri); + } catch (IllegalArgumentException e) { + // TODO gcardosi 1742 + feelDialect = FEELDialect.FEEL; + } } public DMNModelImpl(Definitions dmndefs, Resource resource) { @@ -124,6 +134,10 @@ public DMNModelImpl(Definitions dmndefs, Resource resource) { messages = new DefaultDMNMessagesManager(resource); } + public FEELDialect getFeelDialect() { + return feelDialect; + } + private void wireTypeRegistry(Definitions definitions) { if (definitions instanceof org.kie.dmn.model.v1_1.TDefinitions) { types = new DMNTypeRegistryV11(Collections.unmodifiableMap(importAliases)); diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNImportPMMLInfo.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNImportPMMLInfo.java index bc0946ab5d3..a99be1abf8d 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNImportPMMLInfo.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/pmml/DMNImportPMMLInfo.java @@ -40,6 +40,7 @@ import org.kie.dmn.core.impl.CompositeTypeImpl; import org.kie.dmn.core.impl.DMNModelImpl; import org.kie.dmn.core.impl.SimpleTypeImpl; +import org.kie.dmn.feel.lang.FEELDialect; import org.kie.dmn.feel.lang.FEELProfile; import org.kie.dmn.feel.lang.types.BuiltInType; import org.kie.dmn.feel.runtime.UnaryTest; @@ -67,7 +68,7 @@ public static Either from(InputStream is, DMNCompi String dfName =df.getName(); BuiltInType ft = getBuiltInTypeByDataType(df.getDataType()); List helperFEELProfiles = cc.getFeelProfiles(); - DMNFEELHelper feel = new DMNFEELHelper(cc.getRootClassLoader(), helperFEELProfiles); + DMNFEELHelper feel = new DMNFEELHelper(cc.getRootClassLoader(), helperFEELProfiles, model.getFeelDialect()); List av = new ArrayList<>(); if (df.getValues() != null && !df.getValues().isEmpty() && ft != BuiltInType.UNKNOWN) { final BuiltInType feelType = ft; diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java index 5f245869683..aea00505e16 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/DMNInputRuntimeTest.java @@ -46,7 +46,9 @@ import org.kie.dmn.api.core.event.DMNRuntimeEventListener; import org.kie.dmn.core.api.DMNFactory; import org.kie.dmn.core.api.event.DefaultDMNRuntimeEventListener; +import org.kie.dmn.core.impl.DMNModelImpl; import org.kie.dmn.core.util.DMNRuntimeUtil; +import org.kie.dmn.feel.lang.FEELDialect; import static org.assertj.core.api.Assertions.assertThat; import static org.kie.dmn.core.util.DynamicTypeUtils.entry; @@ -383,6 +385,52 @@ void typeConstraintsChecks(boolean useExecModelCompiler) { assertThat(dmnResult3.getMessages().stream().anyMatch(m -> m.getMessageType().equals(DMNMessageType.ERROR_EVAL_NODE))).isTrue(); } + @ParameterizedTest + @MethodSource("params") + void constraintsChecksBFEEL(boolean useExecModelCompiler) { + init(useExecModelCompiler); + final DMNRuntime runtime = DMNRuntimeUtil.createRuntime("valid_models/DMNv1_5/B-FEEL/ConstraintsChecksBFeel.dmn", this.getClass() ); + final DMNModel dmnModel = runtime.getModel( + "http://www.trisotech.com/definitions/_238bd96d-47cd-4746-831b-504f3e77b442", + "ConstraintsChecksBFEEL" ); + assertThat(dmnModel).isNotNull(); + assertThat(dmnModel.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnModel.getMessages())).isFalse(); + assertThat(dmnModel).isInstanceOf(DMNModelImpl.class); + assertThat(((DMNModelImpl)dmnModel).getFeelDialect()).isEqualTo(FEELDialect.BFEEL); + } + + @ParameterizedTest + @MethodSource("params") + void typeConstraintsChecksBFEEL(boolean useExecModelCompiler) { + init(useExecModelCompiler); + final DMNRuntime runtime = DMNRuntimeUtil.createRuntime("valid_models/DMNv1_5/B-FEEL/BFeelChecks.dmn", this.getClass() ); + final DMNModel dmnModel = runtime.getModel( + "http://www.trisotech.com/definitions/_238bd96d-47cd-4746-831b-504f3e77b442", + "BFEELChecks" ); + assertThat(dmnModel).isNotNull(); + assertThat(dmnModel.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnModel.getMessages())).isFalse(); + assertThat(dmnModel).isInstanceOf(DMNModelImpl.class); + assertThat(((DMNModelImpl)dmnModel).getFeelDialect()).isEqualTo(FEELDialect.BFEEL); + + final DMNContext ctx1 = runtime.newContext(); + ctx1.set("p1", prototype(entry("Name", "P1"), entry("Interests", Collections.singletonList("Golf")))); + final DMNResult dmnResult1 = runtime.evaluateAll( dmnModel, ctx1 ); + assertThat(dmnResult1.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult1.getMessages())).isFalse(); + assertThat( dmnResult1.getContext().get( "MyDecision" )).isEqualTo("The Person P1 likes 1 thing(s)." ); + + final DMNContext ctx2 = runtime.newContext(); + ctx2.set("p1", prototype(entry("Name", "P2"), entry("Interests", Collections.singletonList("x")))); + final DMNResult dmnResult2 = runtime.evaluateAll( dmnModel, ctx2 ); + assertThat(dmnResult2.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult2.getMessages())).isFalse(); + assertThat( dmnResult2.getContext().get( "MyDecision" )).isEqualTo("The Person P2 likes 1 thing(s)." ); + + final DMNContext ctx3 = runtime.newContext(); + ctx3.set("p1", prototype(entry("Name", "P3"), entry("Interests", Arrays.asList("Golf", "Computer")))); + final DMNResult dmnResult3 = runtime.evaluateAll( dmnModel, ctx3 ); + assertThat(dmnResult3.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnResult3.getMessages())).isTrue(); + assertThat(dmnResult3.getMessages().stream().anyMatch(m -> m.getMessageType().equals(DMNMessageType.ERROR_EVAL_NODE))).isTrue(); + } + @ParameterizedTest @MethodSource("params") void evaluationHitIdsCheck(boolean useExecModelCompiler) { diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/BFeelChecks.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/BFeelChecks.dmn new file mode 100644 index 00000000000..1d51cd90258 --- /dev/null +++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/BFeelChecks.dmn @@ -0,0 +1,76 @@ + + + + + + + string + + + tInterests + + + + string + + + tInterest + + count (?) = 1 + + + + + + + + + "The Person " + p1.Name + " likes " + string(count( p1.Interests )) + " thing(s)." + + + + + + diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/ConstraintsChecksBFeel.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/ConstraintsChecksBFeel.dmn new file mode 100644 index 00000000000..93fdff1730a --- /dev/null +++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/B-FEEL/ConstraintsChecksBFeel.dmn @@ -0,0 +1,93 @@ + + + + + + number + + 0, 1, 2 + + + + string + + "a", "b", "c" + + + + string + + "a", "b", "c", null + + + + number + + 0, 1, 2 + + + + string + + "a", "b", "c" + + + + string + + "a", "b", "c", null + + + + + + + + + + + + + + + + + + + + + + + + + + + From 938bfa2f228354a1c5ebf89ab3137f286be0e21a Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Thu, 9 Jan 2025 12:45:27 +0100 Subject: [PATCH 10/10] [incubator-kie-issues#1742] Fixing headers --- .../java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java | 6 +++--- .../org/kie/dmn/feel/runtime/FEELCollectionFunction.java | 6 +++--- .../java/org/kie/dmn/feel/runtime/FEELDurationFunction.java | 6 +++--- .../java/org/kie/dmn/feel/runtime/FEELNumberFunction.java | 6 +++--- .../java/org/kie/dmn/feel/runtime/FEELStringFunction.java | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java index 495da7211ef..5a68e878718 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELBooleanFunction.java @@ -6,9 +6,9 @@ * 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 - *

+ * + * 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 diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java index ec0dda0626d..1f044a05ab4 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELCollectionFunction.java @@ -6,9 +6,9 @@ * 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 - *

+ * + * 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 diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java index f748c3c2acb..07624b1e325 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELDurationFunction.java @@ -6,9 +6,9 @@ * 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 - *

+ * + * 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 diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java index 8b2a2377f01..81613958036 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELNumberFunction.java @@ -6,9 +6,9 @@ * 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 - *

+ * + * 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 diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java index ff774bd0729..3adf76ee698 100644 --- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java +++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/FEELStringFunction.java @@ -6,9 +6,9 @@ * 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 - *

+ * + * 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