Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support generic range type in DMN engine #6123

Merged
merged 5 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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;
import static org.kie.dmn.feel.util.EvaluationContextTestUtil.newEmptyEvaluationContext;

public class DMNCompilerTest extends BaseVariantTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ type
helper.popScope();
}
: {_input.LT(1).getText().equals("list")}? sk=Identifier LT type GT #listType
| {_input.LT(1).getText().equals("range")}? sk=Identifier LT type GT #rangeType
| {_input.LT(1).getText().equals("context")}? sk=Identifier LT Identifier COLON type ( COMMA Identifier COLON type )* GT #contextType
| FUNCTION #qnType
| FUNCTION LT (type ( COMMA type )*)? GT RARROW type #functionType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
import org.kie.dmn.feel.lang.ast.RangeNode;
import org.kie.dmn.feel.lang.ast.RangeTypeNode;
import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
import org.kie.dmn.feel.lang.ast.StringNode;
import org.kie.dmn.feel.lang.ast.TemporalConstantNode;
Expand Down Expand Up @@ -136,6 +137,7 @@
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.QUALIFIEDNAMENODE_CT;
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.QUANTIFIEDEXPRESSIONNODE_CT;
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.RANGENODE_CT;
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.RANGETYPENODE_CT;
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.SIGNEDUNARYNODE_CT;
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.STRINGNODE_CT;
import static org.kie.dmn.feel.codegen.feel11.DMNCodegenConstants.TEMPORALCONSTANTNODE_CT;
Expand Down Expand Up @@ -431,6 +433,12 @@ public BlockStmt add(RangeNode n) {
endExpression), n.getText());
}

public BlockStmt add(RangeTypeNode n) {
Expression genTypeNodeExpression = getNodeExpression(n.getGenericTypeNode());
return addVariableDeclaratorWithObjectCreation(RANGETYPENODE_CT, NodeList.nodeList(genTypeNodeExpression),
n.getText());
}

public BlockStmt add(SignedUnaryNode n) {
Expression signExpression = getEnumExpression(n.getSign());
Expression expressionExpression = getNodeExpression(n.getExpression());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
import org.kie.dmn.feel.lang.ast.RangeNode;
import org.kie.dmn.feel.lang.ast.RangeTypeNode;
import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
import org.kie.dmn.feel.lang.ast.StringNode;
import org.kie.dmn.feel.lang.ast.TemporalConstantNode;
Expand Down Expand Up @@ -253,6 +254,12 @@ public BlockStmt visit(RangeNode n) {
return compilerHelper.add(n);
}

@Override
public BlockStmt visit(RangeTypeNode n) {
LOGGER.trace("visit {}", n);
return compilerHelper.add(n);
}

@Override
public BlockStmt visit(SignedUnaryNode n) {
LOGGER.trace("visit {}", n);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
import org.kie.dmn.feel.lang.ast.RangeNode;
import org.kie.dmn.feel.lang.ast.RangeTypeNode;
import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
import org.kie.dmn.feel.lang.ast.StringNode;
import org.kie.dmn.feel.lang.ast.TemporalConstantNode;
Expand Down Expand Up @@ -142,6 +143,8 @@ public class DMNCodegenConstants {
public static final ClassOrInterfaceType LISTNODE_CT = parseClassOrInterfaceType(ListNode.class.getCanonicalName());
public static final ClassOrInterfaceType LISTTYPENODE_CT =
parseClassOrInterfaceType(ListTypeNode.class.getCanonicalName());
public static final ClassOrInterfaceType RANGETYPENODE_CT =
parseClassOrInterfaceType(RangeTypeNode.class.getCanonicalName());
public static final ClassOrInterfaceType NAMEDEFNODE_CT =
parseClassOrInterfaceType(NameDefNode.class.getCanonicalName());
public static final ClassOrInterfaceType NAMEDPARAMETERNODE_CT =
Expand Down
Original file line number Diff line number Diff line change
@@ -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.lang.ast;

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.GenRangeType;

public class RangeTypeNode extends TypeNode {

private final TypeNode genericTypeNode;

public RangeTypeNode(ParserRuleContext ctx, TypeNode gen) {
super(ctx);
this.genericTypeNode = gen;
}

public RangeTypeNode(TypeNode genericTypeNode, String text) {
this.genericTypeNode = genericTypeNode;
this.setText(text);
}

@Override
public Type evaluate(EvaluationContext ctx) {
Type gen = genericTypeNode.evaluate(ctx);
return new GenRangeType(gen);
}

@Override
public <T> T accept(Visitor<T> v) {
return v.visit(this);
}

public TypeNode getGenericTypeNode() {
return genericTypeNode;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public interface Visitor<T> {
T visit(QualifiedNameNode n);
T visit(QuantifiedExpressionNode n);
T visit(RangeNode n);
T visit(RangeTypeNode n);
T visit(SignedUnaryNode n);
T visit(StringNode n);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
import org.kie.dmn.feel.lang.ast.RangeNode;
import org.kie.dmn.feel.lang.ast.RangeTypeNode;
import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
import org.kie.dmn.feel.lang.ast.StringNode;
import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
Expand Down Expand Up @@ -194,6 +195,11 @@ public T visit(RangeNode n) {
return defaultVisit(n);
}

@Override
public T visit(RangeTypeNode n) {
return defaultVisit(n);
}

@Override
public T visit(SignedUnaryNode n) {
return defaultVisit(n);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* 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.types;

import org.kie.dmn.feel.lang.SimpleType;
import org.kie.dmn.feel.lang.Type;
import org.kie.dmn.feel.runtime.impl.RangeImpl;

public class GenRangeType implements SimpleType {

/**
* Represents the "generic" type of the current list
*/
private final Type gen;


public GenRangeType(Type gen) {
this.gen = gen;
}

@Override
public boolean isInstanceOf(Object o) {
if (o instanceof RangeImpl rangeImpl) {
return gen.isInstanceOf(rangeImpl.getLowEndPoint()) && gen.isInstanceOf(rangeImpl.getHighEndPoint());
} else {
return false;
}
}

@Override
public boolean isAssignableValue(Object value) {
if ( value == null ) {
return true; // a null-value can be assigned to any type.
}
if (!(value instanceof RangeImpl)) {
return gen.isAssignableValue(value);
}
return isInstanceOf(value);
}

@Override
public String getName() {
return "[anonymous]";
}

public Type getGen() {
return gen;
}

@Override
public boolean conformsTo(Type t) {
return (t instanceof GenRangeType && this.gen.conformsTo(((GenRangeType) t).gen)) || t == BuiltInType.RANGE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
import org.kie.dmn.feel.lang.ast.QuantifiedExpressionNode;
import org.kie.dmn.feel.lang.ast.RangeNode;
import org.kie.dmn.feel.lang.ast.RangeTypeNode;
import org.kie.dmn.feel.lang.ast.StringNode;
import org.kie.dmn.feel.lang.ast.TypeNode;
import org.kie.dmn.feel.lang.ast.UnaryTestListNode;
Expand Down Expand Up @@ -586,6 +587,12 @@ public BaseNode visitListType(FEEL_1_1Parser.ListTypeContext ctx) {
return new ListTypeNode(ctx, type);
}

@Override
public BaseNode visitRangeType(FEEL_1_1Parser.RangeTypeContext ctx) {
TypeNode type = (TypeNode) visit(ctx.type());
return new RangeTypeNode(ctx, type);
}

@Override
public BaseNode visitContextType(FEEL_1_1Parser.ContextTypeContext ctx) {
List<String> pNames = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.kie.dmn.feel.lang.types.DefaultBuiltinFEELTypeRegistry;
import org.kie.dmn.feel.lang.types.FEELTypeRegistry;
import org.kie.dmn.feel.lang.types.GenListType;
import org.kie.dmn.feel.lang.types.GenRangeType;
import org.kie.dmn.feel.lang.types.ScopeImpl;
import org.kie.dmn.feel.lang.types.SymbolTable;
import org.kie.dmn.feel.lang.types.VariableSymbol;
Expand Down Expand Up @@ -144,6 +145,10 @@ public void recoverScope( String name ) {
scopeType = ((GenListType) scopeType).getGen();
}

if (scopeType instanceof GenRangeType) {
scopeType = ((GenRangeType) scopeType).getGen();
}

if (resolved != null && scopeType instanceof CompositeType) {
pushScope(scopeType);
CompositeType type = (CompositeType) scopeType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,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.EvaluationContextTestUtil;
import org.kie.dmn.feel.util.NumberEvalHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -98,7 +99,7 @@ private List<Boolean> parseCompileEvaluate(String feelLiteralExpression, Object
FEELEventListenersManager mgr = new FEELEventListenersManager();
SyntaxErrorListener listener = new SyntaxErrorListener();
mgr.addListener(listener);
EvaluationContext emptyContext = CodegenTestUtil.newEmptyEvaluationContext(mgr);
EvaluationContext emptyContext = EvaluationContextTestUtil.newEmptyEvaluationContext(mgr);
CompiledFEELUnaryTests compiledUnaryTests = parse(feelLiteralExpression, mgr, listener);
LOG.debug("{}", compiledUnaryTests);
List<Boolean> result = compiledUnaryTests.getUnaryTests()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.kie.dmn.feel.runtime.FEELTernaryLogicTest;
import org.kie.dmn.feel.runtime.functions.CustomFEELFunction;
import org.kie.dmn.feel.util.CompilerUtils;
import org.kie.dmn.feel.util.EvaluationContextTestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -226,7 +227,7 @@ void filter_path_tricky1() {
CompiledFEELExpression nameRef = CompilerUtils.parseCodegen("[ {x:1, y:2}, {x:2, y:3} ][x]");
LOG.debug("{}", nameRef);

EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext();
EvaluationContext context = EvaluationContextTestUtil.newEmptyEvaluationContext();
context.setValue("x", 2);
Object result = nameRef.apply(context);
LOG.debug("{}", result);
Expand All @@ -239,7 +240,7 @@ void filter_path_tricky2() {
CompiledFEELExpression nameRef = CompilerUtils.parseCodegen("[ {x:1, y:2}, {x:2, y:3} ][x]");
LOG.debug("{}", nameRef);

EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext();
EvaluationContext context = EvaluationContextTestUtil.newEmptyEvaluationContext();
context.setValue("x", false);
Object result = nameRef.apply(context);
LOG.debug("{}", result);
Expand Down Expand Up @@ -410,7 +411,7 @@ void nameReference() {
CompiledFEELExpression nameRef = parseCodegen(inputExpression, mapOf(entry("someSimpleName", BuiltInType.STRING) ) );
LOG.debug("{}", nameRef);

EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext();
EvaluationContext context = EvaluationContextTestUtil.newEmptyEvaluationContext();
context.setValue("someSimpleName", 123L);
Object result = nameRef.apply(context);
LOG.debug("{}", result);
Expand All @@ -425,7 +426,7 @@ void qualifiedName() {
CompiledFEELExpression qualRef = parseCodegen(inputExpression, mapOf(entry("My Person", personType) ) );
LOG.debug("{}", qualRef);

EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext();
EvaluationContext context = EvaluationContextTestUtil.newEmptyEvaluationContext();
context.setValue("My Person", mapOf( entry("Full Name", "John Doe"), entry("Age", 47) ));
Object result = qualRef.apply(context);
LOG.debug("{}", result);
Expand Down Expand Up @@ -456,7 +457,7 @@ void qualifiedName2() {
CompiledFEELExpression qualRef = parseCodegen(inputExpression, mapOf(entry("My Person", personType) ) );
LOG.debug("{}", qualRef);

EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext();
EvaluationContext context = EvaluationContextTestUtil.newEmptyEvaluationContext();
context.setValue("My Person", new MyPerson());
Object result = qualRef.apply(context);
LOG.debug("{}", result);
Expand All @@ -471,7 +472,7 @@ void qualifiedName3() {
CompiledFEELExpression qualRef = parseCodegen(inputExpression, mapOf(entry("a date", dateType)));
LOG.debug("{}", qualRef);

EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext();
EvaluationContext context = EvaluationContextTestUtil.newEmptyEvaluationContext();
context.setValue("a date", LocalDate.of(2016, 8, 2));
Object result = qualRef.apply(context);
LOG.debug("{}", result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.kie.dmn.feel.codegen.feel11.CodegenTestUtil;
import org.kie.dmn.feel.util.EvaluationContextTestUtil;
import org.kie.dmn.feel.lang.Type;
import org.kie.dmn.feel.lang.types.BuiltInType;

Expand All @@ -39,7 +39,7 @@ void evaluateSimpleArray() {
IterationContextNode x = getIterationContextNode("x", getListNode("[ 1, 2, 3, 4 ]", Arrays.asList("1", "2", "3", "4")), "x in [ 1, 2, 3, 4 ]");
IterationContextNode y = getIterationContextNode("y", getNameRefNode(BuiltInType.UNKNOWN, "x"), "y in x");
ForExpressionNode forExpressionNode = new ForExpressionNode(Arrays.asList(x, y), getNameRefNode(BuiltInType.UNKNOWN, "y"), "for x in [ 1, 2, 3, 4 ], y in x return y");
Object retrieved = forExpressionNode.evaluate(CodegenTestUtil.newEmptyEvaluationContext());
Object retrieved = forExpressionNode.evaluate(EvaluationContextTestUtil.newEmptyEvaluationContext());
assertThat(retrieved).isInstanceOf(List.class).asList().
containsExactly(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3), BigDecimal.valueOf(4));
}
Expand All @@ -52,7 +52,7 @@ void evaluateNestedArray() {
IterationContextNode x = getIterationContextNode("x", getNestedListNode("[ [1, 2], [3, 4] ]", firstIterationContext), "x in [ [1, 2], [3, 4] ]");
IterationContextNode y = getIterationContextNode("y", getNameRefNode(BuiltInType.UNKNOWN, "x"), "y in x");
ForExpressionNode forExpressionNode = new ForExpressionNode(Arrays.asList(x, y), getNameRefNode(BuiltInType.UNKNOWN, "y"), "for x in [ [1, 2], [3, 4] ], y in x return y");
Object retrieved = forExpressionNode.evaluate(CodegenTestUtil.newEmptyEvaluationContext());
Object retrieved = forExpressionNode.evaluate(EvaluationContextTestUtil.newEmptyEvaluationContext());
assertThat(retrieved).isInstanceOf(List.class).asList().
containsExactly(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3), BigDecimal.valueOf(4));

Expand Down
Loading
Loading