Skip to content

Commit

Permalink
[#655] DMN 1.5: Clarify edge cases for unary tests with ranges (DMN15…
Browse files Browse the repository at this point in the history
…-78)
  • Loading branch information
opatrascoiu committed Oct 25, 2024
1 parent 50a5372 commit b10c57d
Show file tree
Hide file tree
Showing 17 changed files with 550 additions and 1,068 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ public Triple lazyEvaluation(String name, String nativeName) {
return addTriple(triple);
}

public Triple text(String text) {
Triple triple = new TextTriple(String.format("\"%s\"", text));
return addTriple(triple);
}

@Override
public String toString() {
return triples.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,16 @@

import com.gs.dmn.feel.analysis.syntax.ast.Visitor;
import com.gs.dmn.feel.analysis.syntax.ast.expression.Expression;
import com.gs.dmn.runtime.DMNRuntimeException;

import java.util.Objects;

public class OperatorRange<T> extends Range<T> {
private final String operator;
private final Expression<T> endpoint;
private final EndpointsRange<T> endpointsRange;

public OperatorRange(String operator, Expression<T> endpoint) {
this.operator = operator;
this.endpoint = endpoint;
if (operator == null || "=".equals(operator)) {
this.endpointsRange = new EndpointsRange<>(false, endpoint, false, endpoint);
} else if ("!=".equals(operator)) {
this.endpointsRange = new EndpointsRange<>(false, endpoint, false, endpoint);
} else if ("<".equals(operator)) {
this.endpointsRange = new EndpointsRange<>(true, null, true, endpoint);
} else if ("<=".equals(operator)) {
this.endpointsRange = new EndpointsRange<>(true, null, false, endpoint);
} else if (">".equals(operator)) {
this.endpointsRange = new EndpointsRange<>(true, endpoint, true, null);
} else if (">=".equals(operator)) {
this.endpointsRange = new EndpointsRange<>(false, endpoint, true, null);
} else {
throw new DMNRuntimeException(String.format("Unexpected operator '%s'", operator));
}
}

public Expression<T> getEndpoint() {
Expand All @@ -56,10 +39,6 @@ public String getOperator() {
return this.operator;
}

public EndpointsRange<T> getEndpointsRange() {
return this.endpointsRange;
}

@Override
public <C, R> R accept(Visitor<T, C, R> visitor, C context) {
return visitor.visit(this, context);
Expand All @@ -70,12 +49,12 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OperatorRange<?> that = (OperatorRange<?>) o;
return Objects.equals(operator, that.operator) && Objects.equals(endpoint, that.endpoint) && Objects.equals(endpointsRange, that.endpointsRange);
return Objects.equals(operator, that.operator) && Objects.equals(endpoint, that.endpoint);
}

@Override
public int hashCode() {
return Objects.hash(operator, endpoint, endpointsRange);
return Objects.hash(operator, endpoint);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public Object visit(OperatorRange<Type> element, DMNContext context) {
// Evaluate as range
return evaluateOperatorRange(element, operator, null, endpoint, context);
} else {
// Evaluate as test
// Evaluate as test according to 7.3.2 UnaryTests Metamodel
Object self = context.lookupBinding(INPUT_ENTRY_PLACE_HOLDER);
if (Type.sameSemanticDomain(endpointType, inputExpressionType)) {
// input and endpoint are comparable
Expand Down Expand Up @@ -186,15 +186,17 @@ private Object evaluateOperatorRange(Expression<Type> element, String operator,
Object endpointValue = endpointExpression.accept(this, context);
if (context.isExpressionContext()) {
if (operator == null || "=".equals(operator)) {
return new Range(true, endpointValue, true, endpointValue);
return new Range(true, endpointValue, true, endpointValue, "=");
} else if ("!=".equals(operator)) {
return new Range(false, endpointValue, false, endpointValue, operator);
} else if ("<".equals(operator)) {
return new Range(false, null, false, endpointValue);
return new Range(false, null, false, endpointValue, operator);
} else if ("<=".equals(operator)) {
return new Range(false, null, true, endpointValue);
return new Range(false, null, true, endpointValue, operator);
} else if (">".equals(operator)) {
return new Range(false, endpointValue, false, null);
return new Range(false, endpointValue, false, null, operator);
} else if (">=".equals(operator)) {
return new Range(true, endpointValue, false, null);
return new Range(true, endpointValue, false, null, operator);
} else {
throw new DMNRuntimeException(String.format("Unknown operator '%s'", operator));
}
Expand All @@ -203,6 +205,10 @@ private Object evaluateOperatorRange(Expression<Type> element, String operator,
}
}

private Object evaluateRangeEndpoint(Expression<Type> element, String operator, Object self, Expression<Type> endpointExpression, DMNContext context) throws Exception {
return evaluateOperatorRange(element, operator, self, context.getInputExpressionType(), endpointExpression.getType(), endpointExpression.accept(this, context));
}

private Object evaluateOperatorRange(Expression<Type> element, String operator, Object self, Type inputExpressionType, Type endpointType, Object endpointValue) throws IllegalAccessException, InvocationTargetException {
NativeOperator javaOperator = javaOperator(operator, inputExpressionType, endpointType);
if (javaOperator == null) {
Expand Down Expand Up @@ -289,15 +295,15 @@ public Object visit(EndpointsRange<Type> element, DMNContext context) {
String leftOperator = element.isOpenStart() ? ">" : ">=";
String rightOperator = element.isOpenEnd() ? "<" : "<=";

if (self == null) {
if (context.isExpressionContext()) {
// Evaluate as range
Object startValue = element.getStart().accept(this, context);
Object endValue = element.getEnd().accept(this, context);
return new Range(!element.isOpenStart(), startValue, !element.isOpenEnd(), endValue);
} else {
// Evaluate as test
Object leftCondition = evaluateOperatorRange(element, leftOperator, self, startExpression, context);
Object rightCondition = evaluateOperatorRange(element, rightOperator, self, endExpression, context);
Object leftCondition = evaluateRangeEndpoint(element, leftOperator, self, startExpression, context);
Object rightCondition = evaluateRangeEndpoint(element, rightOperator, self, endExpression, context);

return this.lib.booleanAnd(leftCondition, rightCondition);
}
Expand All @@ -324,7 +330,7 @@ public Object visit(ListTest<Type> element, DMNContext context) {
if (Type.conformsTo(inputExpressionType, optimizedListType)) {
// both are compatible lists
String operator = "=";
return evaluateOperatorRange(element, operator, self, optimizedListLiteral, context);
return evaluateRangeEndpoint(element, operator, self, optimizedListLiteral, context);
} else if (Type.conformsTo(inputExpressionType, optimizedListElementType)) {
// input conforms to element in the list
List list = (List) optimizedListLiteral.accept(this, context);
Expand Down
Loading

0 comments on commit b10c57d

Please sign in to comment.