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

Annotations threshold #670

Merged
merged 3 commits into from
May 31, 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 @@ -13,8 +13,12 @@
package com.gs.dmn.feel.analysis;

import com.gs.dmn.DMNModelRepository;
import com.gs.dmn.context.DMNContext;
import com.gs.dmn.context.environment.EnvironmentFactory;
import com.gs.dmn.el.analysis.semantics.type.Type;
import com.gs.dmn.error.ErrorHandler;
import com.gs.dmn.feel.analysis.semantics.SemanticError;
import com.gs.dmn.feel.analysis.syntax.ast.expression.Expression;
import com.gs.dmn.feel.analysis.syntax.ast.visitor.AbstractVisitor;
import com.gs.dmn.feel.synthesis.type.NativeTypeFactory;
import com.gs.dmn.transformation.basic.BasicDMNToNativeTransformer;
Expand Down Expand Up @@ -54,4 +58,16 @@ protected AbstractAnalysisVisitor(BasicDMNToNativeTransformer<T, C> dmnTransform
public BasicDMNToNativeTransformer<T, C> getDmnTransformer() {
return dmnTransformer;
}

protected void handleError(String message) {
throw new SemanticError(message);
}

protected void handleError(DMNContext context, Expression<Type> element, String message) {
throw new SemanticError(context, element, message);
}

protected void handleError(DMNContext context, Expression<Type> element, String message, Exception e) {
throw new SemanticError(context, element, message, e);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import com.gs.dmn.feel.analysis.syntax.ast.expression.textual.*;
import com.gs.dmn.feel.analysis.syntax.ast.expression.type.*;
import com.gs.dmn.feel.analysis.syntax.ast.test.*;
import com.gs.dmn.runtime.DMNRuntimeException;
import com.gs.dmn.runtime.Pair;
import com.gs.dmn.transformation.basic.BasicDMNToNativeTransformer;

Expand Down Expand Up @@ -91,7 +90,8 @@ public Element<Type> visit(NegatedPositiveUnaryTests<Type> element, DMNContext c
for (Type child : ((TupleType) type).getTypes()) {
if (child == BooleanType.BOOLEAN || child instanceof RangeType) {
} else {
throw new SemanticError(element, String.format("Operator '%s' cannot be applied to '%s'", "not", child));
handleError(context, element, String.format("Operator '%s' cannot be applied to '%s'", "not", child));
return null;
}
}
}
Expand Down Expand Up @@ -155,7 +155,8 @@ public Element<Type> visit(EndpointsRange<Type> element, DMNContext context) {
Expression<Type> start = element.getStart();
Expression<Type> end = element.getEnd();
if (start == null && end == null) {
throw new DMNRuntimeException(String.format("Illegal range, both endpoints are null in context of element '%s'", context.getElementName()));
handleError(String.format("Illegal range, both endpoints are null in context of element '%s'", context.getElementName()));
return null;
}

// Visit children
Expand Down Expand Up @@ -213,7 +214,8 @@ public Element<Type> visit(ListTest<Type> element, DMNContext context) {
} else if (com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(inputExpressionType, optimizedListElementType)) {
// input conforms to element in the list
} else {
throw new SemanticError(element, String.format("Cannot compare '%s', '%s'", inputExpressionType, optimizedListType));
handleError(context, element, String.format("Cannot compare '%s', '%s'", inputExpressionType, optimizedListType));
return null;
}
} else {
// test is list of ranges compatible with input
Expand Down Expand Up @@ -373,10 +375,11 @@ public Element<Type> visit(IfExpression<Type> element, DMNContext context) {
Type thenType = thenExpression.getType();
Type elseType = elseExpression.getType();
if (conditionType != BOOLEAN) {
throw new SemanticError(element, String.format("Condition type must be boolean. Found '%s' instead.", conditionType));
}
if (com.gs.dmn.el.analysis.semantics.type.Type.isNullType(thenType) && com.gs.dmn.el.analysis.semantics.type.Type.isNullType(elseType)) {
throw new SemanticError(element, String.format("Types of then and else branches are incompatible. Found '%s' and '%s'.", thenType, elseType));
handleError(context, element, String.format("Condition type must be boolean. Found '%s' instead.", conditionType));
return null;
} else if (com.gs.dmn.el.analysis.semantics.type.Type.isNullType(thenType) && com.gs.dmn.el.analysis.semantics.type.Type.isNullType(elseType)) {
handleError(context, element, String.format("Types of then and else branches are incompatible. Found '%s' and '%s'.", thenType, elseType));
return null;
} else if (com.gs.dmn.el.analysis.semantics.type.Type.isNullType(thenType)) {
element.setType(elseType);
} else if (com.gs.dmn.el.analysis.semantics.type.Type.isNullType(elseType)) {
Expand All @@ -387,7 +390,8 @@ public Element<Type> visit(IfExpression<Type> element, DMNContext context) {
} else if (com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(elseType, thenType)) {
element.setType(thenType);
} else {
throw new SemanticError(element, String.format("Types of then and else branches are incompatible. Found '%s' and '%s'.", thenType, elseType));
handleError(context, element, String.format("Types of then and else branches are incompatible. Found '%s' and '%s'.", thenType, elseType));
return null;
}
}

Expand Down Expand Up @@ -431,15 +435,15 @@ public Element<Type> visit(FilterExpression<Type> element, DMNContext context) {
} else if (filterType == BOOLEAN) {
element.setType(sourceType);
} else {
throw new SemanticError(element, String.format("Cannot resolve type for '%s'", element));
handleError(context, element, String.format("Cannot resolve type for '%s'", element));
}
} else {
if (filterType == NUMBER) {
element.setType(sourceType);
} else if (filterType == BOOLEAN) {
element.setType(new ListType(sourceType));
} else {
throw new SemanticError(element, String.format("Cannot resolve type for '%s'", element));
handleError(context, element, String.format("Cannot resolve type for '%s'", element));
}
}

Expand Down Expand Up @@ -633,7 +637,7 @@ public Element<Type> visit(ArithmeticNegation<Type> element, DMNContext context)
Type type = element.getLeftOperand().getType();
element.setType(NUMBER);
if (type != NUMBER) {
throw new SemanticError(element, String.format("Operator '%s' cannot be applied to '%s'", element.getOperator(), type));
handleError(context, element, String.format("Operator '%s' cannot be applied to '%s'", element.getOperator(), type));
}

// Derive type
Expand Down Expand Up @@ -727,7 +731,7 @@ private void visitSortParameters(FunctionInvocation<Type> element, DMNContext co
lambdaExpression.accept(this, context);
}
if (!success) {
throw new SemanticError(element, String.format("Cannot infer parameter type for lambda in sort call '%s'", element));
handleError(context, element, String.format("Cannot infer parameter type for lambda in sort call '%s'", element));
}
}

Expand Down Expand Up @@ -821,10 +825,12 @@ public Element<Type> visit(DateTimeLiteral<Type> element, DMNContext context) {
} else if (element.isDaysAndTimeDuration(element.getLexeme())) {
element.setType(DurationType.DAYS_AND_TIME_DURATION);
} else {
throw new SemanticError(element, String.format("Date time literal '%s(%s) is not supported", conversionFunction, element.getLexeme()));
handleError(context, element, String.format("Date time literal '%s(%s) is not supported", conversionFunction, element.getLexeme()));
return null;
}
} else {
throw new SemanticError(element, String.format("Date time literal '%s(%s)' is not supported", conversionFunction, element.getLexeme()));
handleError(context, element, String.format("Date time literal '%s(%s)' is not supported", conversionFunction, element.getLexeme()));
return null;
}

return element;
Expand Down Expand Up @@ -905,7 +911,8 @@ public Element<Type> visit(QualifiedName<Type> element, DMNContext context) {
// Derive type
List<String> names = element.getNames();
if (names == null || names.isEmpty()) {
throw new SemanticError(element, "Illegal qualified name.");
handleError(context, element, "Illegal qualified name.");
return null;
} else if (names.size() == 1) {
deriveType(element, context);
return element;
Expand Down Expand Up @@ -1022,13 +1029,13 @@ private DMNContext visitIterators(final Expression<Type> element, DMNContext con
it.accept(visitor, qContext);
String itName = it.getName();
Type domainType = it.getDomain().getType();
Type itType;
Type itType = null;
if (domainType instanceof ListType) {
itType = ((ListType) domainType).getElementType();
} else if (domainType instanceof RangeType) {
itType = ((RangeType) domainType).getRangeType();
} else {
throw new SemanticError(element, String.format("Cannot resolve iterator type for '%s'", domainType));
handleError(context, element, String.format("Cannot resolve iterator type for '%s'", domainType));
}
qContext.addDeclaration(this.environmentFactory.makeVariableDeclaration(itName, itType));
});
Expand All @@ -1041,10 +1048,10 @@ protected void checkType(Expression<Type> element, String operator, Type leftOpe
if (resultType != null) {
element.setType(resultType);
} else {
throw new SemanticError(element, String.format("Operator '%s' cannot be applied to '%s', '%s'", operator, leftOperandType, rightOperandType));
handleError(context, element, String.format("Operator '%s' cannot be applied to '%s', '%s'", operator, leftOperandType, rightOperandType));
}
} catch (Exception e) {
throw new SemanticError(element, String.format("Operator '%s' cannot be applied to '%s', '%s' in element '%s'", operator, leftOperandType, rightOperandType, context.getElementName()), e);
handleError(context, element, String.format("Operator '%s' cannot be applied to '%s', '%s'", operator, leftOperandType, rightOperandType), e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package com.gs.dmn.feel.analysis.semantics;

import com.gs.dmn.context.DMNContext;
import com.gs.dmn.el.analysis.semantics.type.Type;
import com.gs.dmn.feel.analysis.syntax.ast.expression.Expression;

Expand All @@ -20,11 +21,24 @@ public SemanticError(String errorMessage) {
super(errorMessage);
}

public SemanticError(Expression<Type> expression, String errorMessage) {
super(String.format("'%s': %s", expression.getClass().getSimpleName(), errorMessage));
public SemanticError(DMNContext context, Expression<Type> expression, String errorMessage) {
super(String.format("'%s': %s", makeLocation(context, expression), errorMessage));
}

public SemanticError(Expression<Type> expression, String errorMessage, Exception e) {
super(String.format("'%s': %s", expression.getClass().getSimpleName(), errorMessage), e);
public SemanticError(DMNContext context, Expression<Type> expression, String errorMessage, Exception e) {
super(String.format("'%s': %s", makeLocation(context, expression), errorMessage), e);
}

private static String makeLocation(DMNContext context, Expression<Type> expression) {
String location = null;
if (context != null && context.getElement() != null) {
location = context.getElementName();
}
if (location == null) {
location = expression.getClass().getSimpleName();
} else {
location += ":" + expression.getClass().getSimpleName();
}
return location;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ public boolean equivalentTo(Type other) {
@Override
public boolean conformsTo(Type other) {
// “contravariant function argument type” and “covariant function return type”
return other instanceof FunctionType
return other == FunctionType.ANY_FUNCTION ||
other instanceof FunctionType
&& com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(this.returnType, ((FunctionType) other).returnType)
&& com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(((FunctionType) other).parameterTypes, this.parameterTypes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public boolean equivalentTo(Type other) {
@Override
public boolean conformsTo(Type other) {
// “contravariant function argument type” and “covariant function return type”
return other instanceof FunctionType
return other == FunctionType.ANY_FUNCTION ||
other instanceof FunctionType
&& com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(this.returnType, ((FunctionType) other).returnType)
&& com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(((FunctionType) other).parameterTypes, this.parameterTypes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public boolean equivalentTo(Type other) {
@Override
public boolean conformsTo(Type other) {
// “contravariant function argument type” and “covariant function return type”
return other instanceof FunctionType
return other == FunctionType.ANY_FUNCTION ||
other instanceof FunctionType
&& com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(this.returnType, ((FunctionType) other).returnType)
&& com.gs.dmn.el.analysis.semantics.type.Type.conformsTo(((FunctionType) other).parameterTypes, this.parameterTypes);
}
Expand Down
Loading
Loading