public static Set<FieldDeclaration> mergeFDs( DirectCompilerResult... sets ) { return mergeFDs(Arrays.asList(sets)); }
@Override public DirectCompilerResult visitFormalParameters(FEEL_1_1Parser.FormalParametersContext ctx) { List<DirectCompilerResult> exprs = new ArrayList<>(); for (FEEL_1_1Parser.FormalParameterContext fpc : ctx.formalParameter()) { exprs.add(visit(fpc)); } MethodCallExpr list = new MethodCallExpr(null, "list"); exprs.stream().map(DirectCompilerResult::getExpression).forEach(list::addArgument); return DirectCompilerResult.of(list, BuiltInType.LIST, DirectCompilerResult.mergeFDs(exprs.toArray(new DirectCompilerResult[]{}))); }
@Override public DirectCompilerResult visitPositionalParameters(FEEL_1_1Parser.PositionalParametersContext ctx) { List<DirectCompilerResult> exprs = new ArrayList<>(); for (FEEL_1_1Parser.ExpressionContext ec : ctx.expression()) { exprs.add(visit(ec)); } MethodCallExpr list = new MethodCallExpr(null, "list"); exprs.stream().map(DirectCompilerResult::getExpression).forEach(list::addArgument); return DirectCompilerResult.of(list, BuiltInType.LIST, DirectCompilerResult.mergeFDs(exprs.toArray(new DirectCompilerResult[]{}))); }
@Override public DirectCompilerResult visitNamedParameters(FEEL_1_1Parser.NamedParametersContext ctx) { List<DirectCompilerResult> exprs = new ArrayList<>(); for (FEEL_1_1Parser.NamedParameterContext npc : ctx.namedParameter()) { exprs.add(visitNamedParameter(npc)); } MethodCallExpr list = new MethodCallExpr(null, "list"); exprs.stream().map(DirectCompilerResult::getExpression).forEach(list::addArgument); return DirectCompilerResult.of(list, BuiltInType.LIST, DirectCompilerResult.mergeFDs(exprs.toArray(new DirectCompilerResult[]{}))); }
/** * NOTE: technically this rule of the grammar does not have an equivalent Java expression (or a valid FEEL expression) per-se. * Using here as assuming if this grammar rule trigger, it is intended as a List, either to be returned, or re-used internally in this visitor. */ @Override public DirectCompilerResult visitExpressionList(FEEL_1_1Parser.ExpressionListContext ctx) { List<DirectCompilerResult> exprs = new ArrayList<>(); for (int i = 0; i < ctx.getChildCount(); i++) { if (ctx.getChild(i) instanceof FEEL_1_1Parser.ExpressionContext) { FEEL_1_1Parser.ExpressionContext childCtx = (FEEL_1_1Parser.ExpressionContext) ctx.getChild(i); DirectCompilerResult child = visit(childCtx); exprs.add(child); } } MethodCallExpr list = new MethodCallExpr(null, "list"); exprs.stream().map(DirectCompilerResult::getExpression).forEach(list::addArgument); return DirectCompilerResult.of(list, BuiltInType.LIST, DirectCompilerResult.mergeFDs(exprs.toArray(new DirectCompilerResult[]{}))); }
@Override public DirectCompilerResult visitPositiveUnaryTests(FEEL_1_1Parser.PositiveUnaryTestsContext ctx) { List<DirectCompilerResult> rs = new ArrayList<>(); for (FEEL_1_1Parser.PositiveUnaryTestContext positiveUnaryTestContext : ctx.positiveUnaryTest()) { DirectCompilerResult result = visit(positiveUnaryTestContext); if (result.resultType == BuiltInType.UNARY_TEST) { rs.add(result); } else if (result.resultType == BuiltInType.RANGE) { // being a range, need the `in` operator. DirectCompilerResult replaced = createUnaryTestExpression(positiveUnaryTestContext, result, UnaryOperator.IN); rs.add(replaced); } else if (result.resultType == BuiltInType.LIST) { DirectCompilerResult replaced = createListUnaryTestExpression(positiveUnaryTestContext, result); rs.add(replaced); } else { DirectCompilerResult unaryTestExpression = createUnaryTestExpression(positiveUnaryTestContext, result, UnaryOperator.EQ); rs.add(unaryTestExpression); } rs.add(result); } MethodCallExpr expression = new MethodCallExpr( null, "list", new NodeList<>(rs.stream().map(DirectCompilerResult::getExpression).collect(Collectors.toList()))); return DirectCompilerResult.of(expression, BuiltInType.UNARY_TEST, DirectCompilerResult.mergeFDs(rs)); }
"list", new NodeList<>(rs.stream().map(DirectCompilerResult::getExpression).collect(Collectors.toList()))); return DirectCompilerResult.of(expression, BuiltInType.UNARY_TEST, DirectCompilerResult.mergeFDs(rs));
private DirectCompilerResult visitPow(DirectCompilerResult left, DirectCompilerResult right) { if (left.getExpression() instanceof NullLiteralExpr || right.getExpression() instanceof NullLiteralExpr) { // optimization: if either left or right is a null literal, just null return DirectCompilerResult.of(new NullLiteralExpr(), BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } else { EnclosedExpr leftCasted = castToBigDecimal(left.getExpression()); EnclosedExpr rightCasted = castToBigDecimal(right.getExpression()); MethodCallExpr powCall = new MethodCallExpr(new NameExpr(CompiledFEELSupport.class.getSimpleName()), "pow"); powCall.addArgument(leftCasted); powCall.addArgument(rightCasted); Expression result = groundToNullIfAnyIsNull(powCall, leftCasted, rightCasted); return DirectCompilerResult.of(result, BuiltInType.NUMBER, DirectCompilerResult.mergeFDs(left, right)); } }
@Override public DirectCompilerResult visitRelExpressionInstanceOf(FEEL_1_1Parser.RelExpressionInstanceOfContext ctx) { DirectCompilerResult expr = visit(ctx.val); DirectCompilerResult type = visit(ctx.type()); MethodCallExpr isInstanceOfCall = new MethodCallExpr(type.getExpression(), "isInstanceOf"); isInstanceOfCall.addArgument(expr.getExpression()); return DirectCompilerResult.of(isInstanceOfCall, BuiltInType.BOOLEAN, mergeFDs(expr, type)); }
@Override public DirectCompilerResult visit(InstanceOfNode n) { DirectCompilerResult expr = n.getExpression().accept(this); DirectCompilerResult type = n.getType().accept(this); return DirectCompilerResult.of( Expressions.isInstanceOf(expr.getExpression(), type.getExpression()), BuiltInType.BOOLEAN, mergeFDs(expr, type)); }
private DirectCompilerResult visitDiv(DirectCompilerResult left, DirectCompilerResult right) { if (left.getExpression() instanceof NullLiteralExpr || right.getExpression() instanceof NullLiteralExpr) { // optimization: if either left or right is a null literal, just null return DirectCompilerResult.of(new NullLiteralExpr(), BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } else if (left.resultType == BuiltInType.NUMBER && right.resultType == BuiltInType.NUMBER) { // right might be zero, hence if divide-by-zero we should ground to null. MethodCallExpr addCall = new MethodCallExpr(null, "div"); EnclosedExpr l = castToBigDecimal(left.getExpression()); EnclosedExpr r = castToBigDecimal(right.getExpression()); addCall.addArgument(l); addCall.addArgument(r); Expression result = groundToNullIfAnyIsNull(addCall, l, r); return DirectCompilerResult.of(result, BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } else { // fallback support strategy: MethodCallExpr addCall = new MethodCallExpr(null, "div"); addCall.addArgument(left.getExpression()); addCall.addArgument(right.getExpression()); Expression result = groundToNullIfAnyIsNull(addCall, left.getExpression(), right.getExpression()); return DirectCompilerResult.of(result, BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } }
private DirectCompilerResult visitMult(DirectCompilerResult left, DirectCompilerResult right) { if (left.getExpression() instanceof NullLiteralExpr || right.getExpression() instanceof NullLiteralExpr) { // optimization: if either left or right is a null literal, just null return DirectCompilerResult.of(new NullLiteralExpr(), BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } else if (left.resultType == BuiltInType.NUMBER && right.resultType == BuiltInType.NUMBER) { Expression l = castToBigDecimal(left.getExpression()); Expression r = castToBigDecimal(right.getExpression()); MethodCallExpr addCall = new MethodCallExpr(l, "multiply"); addCall.addArgument(r); addCall.addArgument(DECIMAL_128); Expression result = groundToNullIfAnyIsNull(addCall, l, r); return DirectCompilerResult.of(result, BuiltInType.NUMBER, DirectCompilerResult.mergeFDs(left, right)); } else { // fallback support strategy: MethodCallExpr addCall = new MethodCallExpr(null, "mult"); addCall.addArgument(left.getExpression()); addCall.addArgument(right.getExpression()); Expression result = groundToNullIfAnyIsNull(addCall, left.getExpression(), right.getExpression()); return DirectCompilerResult.of(result, BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } }
@Override public DirectCompilerResult visit(RangeNode n) { DirectCompilerResult start = n.getStart().accept(this); DirectCompilerResult end = n.getEnd().accept(this); return DirectCompilerResult.of( Expressions.range( n.getLowerBound(), start.getExpression(), end.getExpression(), n.getUpperBound()), BuiltInType.RANGE, DirectCompilerResult.mergeFDs(start, end)); }
@Override public DirectCompilerResult visitContextEntries(FEEL_1_1Parser.ContextEntriesContext ctx) { MethodCallExpr openContextCall = new MethodCallExpr(new NameExpr(CompiledFEELSupport.class.getSimpleName()), "openContext"); openContextCall.addArgument(new NameExpr("feelExprCtx")); scopeHelper.pushScope(); MapBackedType returnType = new MapBackedType(); Expression chainedCallScope = openContextCall; List<DirectCompilerResult> collectedEntryValues = new ArrayList<>(); for (ContextEntryContext ceCtx : ctx.contextEntry()) { DirectCompilerResult key = visit(ceCtx.key()); if (key.resultType != BuiltInType.STRING) { throw new IllegalArgumentException("a Context Entry Key must be a valid FEEL String type"); } String keyText = ((StringLiteralExpr) key.getExpression()).getValue(); DirectCompilerResult entryValueResult = visit(ceCtx.expression()); collectedEntryValues.add(entryValueResult); MethodCallExpr setEntryContextCall = new MethodCallExpr(chainedCallScope, "setEntry"); setEntryContextCall.addArgument(new StringLiteralExpr(keyText)); setEntryContextCall.addArgument(entryValueResult.getExpression()); chainedCallScope = setEntryContextCall; scopeHelper.addType(keyText, entryValueResult.resultType); returnType.addField(keyText, entryValueResult.resultType); } MethodCallExpr closeContextCall = new MethodCallExpr(chainedCallScope, "closeContext"); scopeHelper.popScope(); return DirectCompilerResult.of(closeContextCall, returnType, DirectCompilerResult.mergeFDs(collectedEntryValues.toArray(new DirectCompilerResult[]{}))); }
private DirectCompilerResult visitSub( DirectCompilerResult left, DirectCompilerResult right ) { if (left.getExpression() instanceof NullLiteralExpr || right.getExpression() instanceof NullLiteralExpr) { // optimization: if either left or right is a null literal, just null return DirectCompilerResult.of(new NullLiteralExpr(), BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } else if ( left.resultType == BuiltInType.STRING && right.resultType == BuiltInType.STRING ) { // DMN spec Table 45 // Subtraction is undefined. // incosistent when FEEL is in evaluation mode (in contrast to this compilation mode), // for now is more important to check the actual java code produced BinaryExpr postFixMinus = new BinaryExpr(left.getExpression(), new StringLiteralExpr("-"), BinaryExpr.Operator.PLUS); BinaryExpr plusCall = new BinaryExpr(postFixMinus, right.getExpression(), BinaryExpr.Operator.PLUS); Expression result = groundToNullIfAnyIsNull(plusCall, left.getExpression(), right.getExpression()); return DirectCompilerResult.of(result, BuiltInType.STRING, DirectCompilerResult.mergeFDs(left, right)); } else if ( left.resultType == BuiltInType.NUMBER && right.resultType == BuiltInType.NUMBER ) { Expression l = castToBigDecimal(left.getExpression()); Expression r = castToBigDecimal(right.getExpression()); MethodCallExpr subtractCall = new MethodCallExpr(l, "subtract"); subtractCall.addArgument(r); subtractCall.addArgument(DECIMAL_128); Expression result = groundToNullIfAnyIsNull(subtractCall, l, r); return DirectCompilerResult.of(result, BuiltInType.NUMBER, DirectCompilerResult.mergeFDs(left, right)); } else { // fallback support strategy; to avoid the below, will require to match all the possible conbination in InfixOpNode#sub MethodCallExpr addCall = new MethodCallExpr(null, "sub"); addCall.addArgument(left.getExpression()); addCall.addArgument(right.getExpression()); Expression result = groundToNullIfAnyIsNull(addCall, left.getExpression(), right.getExpression()); return DirectCompilerResult.of(result, BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } }
r.getExpression().asMethodCallExpr().setScope(l.getExpression()), r.resultType, DirectCompilerResult.mergeFDs(l, r)));
private DirectCompilerResult visitAdd( DirectCompilerResult left, DirectCompilerResult right ) { if (left.getExpression() instanceof NullLiteralExpr || right.getExpression() instanceof NullLiteralExpr) { return DirectCompilerResult.of(new NullLiteralExpr(), BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right)); } else if ( left.resultType == BuiltInType.STRING && right.resultType == BuiltInType.STRING ) { if (left.getExpression() instanceof StringLiteralExpr && right.getExpression() instanceof StringLiteralExpr) { BinaryExpr plusCall = new BinaryExpr(left.getExpression(), right.getExpression(), BinaryExpr.Operator.PLUS); Expression result = groundToNullIfAnyIsNull(plusCall, left.getExpression(), right.getExpression()); return DirectCompilerResult.of(result, BuiltInType.STRING, DirectCompilerResult.mergeFDs(left, right)); } else { Expression newStringBuilderExpr = JavaParser.parseExpression("new StringBuilder()"); appendR.addArgument(right.getExpression()); Expression result = new MethodCallExpr(appendR, "toString"); return DirectCompilerResult.of(result, BuiltInType.STRING, DirectCompilerResult.mergeFDs(left, right)); addCall.addArgument(DECIMAL_128); Expression result = groundToNullIfAnyIsNull(addCall, l, r); return DirectCompilerResult.of(result, BuiltInType.NUMBER, DirectCompilerResult.mergeFDs(left, right)); } else { addCall.addArgument(right.getExpression()); Expression result = groundToNullIfAnyIsNull(addCall, left.getExpression(), right.getExpression()); return DirectCompilerResult.of(result, BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(left, right));
@Override public DirectCompilerResult visitRelExpressionTestList(FEEL_1_1Parser.RelExpressionTestListContext ctx) { DirectCompilerResult relationalExpression = visit(ctx.relationalExpression()); DirectCompilerResult unaryTests = visit(ctx.positiveUnaryTests()); MethodCallExpr expression = new MethodCallExpr( null, "exists", new NodeList<>( new NameExpr("feelExprCtx"), unaryTests.getExpression(), relationalExpression.getExpression() )); return DirectCompilerResult.of( expression, BuiltInType.BOOLEAN, mergeFDs(relationalExpression, unaryTests)); }
@Override public DirectCompilerResult visitIfExpression(FEEL_1_1Parser.IfExpressionContext ctx) { DirectCompilerResult c = visit( ctx.c ); DirectCompilerResult t = visit( ctx.t ); DirectCompilerResult e = visit( ctx.e ); // Instead of using Java operator `instanceof` and `cast` directly, safer to use this method-based version, to avoid issue with primitives (eg: true instanceof Boolean does not compile) MethodCallExpr castC = new MethodCallExpr(new ClassExpr(JavaParser.parseType(Boolean.class.getSimpleName())), "cast"); castC.addArgument(new EnclosedExpr(c.getExpression())); Expression safeInternal = new ConditionalExpr(castC, new EnclosedExpr(t.getExpression()), new EnclosedExpr(e.getExpression())); safeInternal = new EnclosedExpr(safeInternal); MethodCallExpr instanceOfBoolean = new MethodCallExpr(new ClassExpr(JavaParser.parseType(Boolean.class.getSimpleName())), "isInstance"); instanceOfBoolean.addArgument(new EnclosedExpr(c.getExpression())); ConditionalExpr result = new ConditionalExpr(instanceOfBoolean, safeInternal, e.getExpression()); return DirectCompilerResult.of(result, BuiltInType.UNKNOWN, DirectCompilerResult.mergeFDs(c, t, e)); }
expression, BuiltInType.BOOLEAN, mergeFDs(value, expr));