public static Boolean coerceToBoolean(EvaluationContext ctx, Object value) { if (value == null || value instanceof Boolean) { return (Boolean) value; } 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; }
private Object withIndex(Object filterIndex) { if (value == null) { return null; } List list = value instanceof List ? (List) value : Arrays.asList(value); if (filterIndex instanceof Number) { int i = ((Number) filterIndex).intValue(); if (i > 0 && i <= list.size()) { return list.get(i - 1); } else if (i < 0 && Math.abs(i) <= list.size()) { return list.get(list.size() + i); } else { ctx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, Msg.createMessage(Msg.INDEX_OUT_OF_BOUND), null)); return null; } } else if (filterIndex == null) { return Collections.emptyList(); } else { ctx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, Msg.createMessage(Msg.ERROR_EXECUTING_LIST_FILTER, filterIndex), null)); return null; } } }
@Override public Object evaluate(EvaluationContext ctx) { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.BASE_NODE_EVALUATE_CALLED) ) ); return null; }
private Comparable convertToComparable(EvaluationContext ctx, Object s) { Comparable start; if( s instanceof Comparable ) { start = (Comparable) s; } else if( s instanceof Period ) { // period has special semantics start = new ComparablePeriod( (Period) s ); } else { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.INCOMPATIBLE_TYPE_FOR_RANGE, s.getClass().getSimpleName() ))); start = null; } return start; }
private static UnaryTest toUnaryTest(EvaluationContext ctx, Object o) { if ( o instanceof UnaryTest ) { return (UnaryTest) o; } else if ( o instanceof Range ) { return (c, x) -> { try { return ((Range) o).includes( 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() ), e ) ); throw e; } }; } else if ( o instanceof List ) { return (c, x) -> ((List<?>) o).contains( x ); } else { return (c, x) -> x.equals( o ); } }
@Override public Object evaluate(EvaluationContext ctx) { if (expression == null) return null; BigDecimal result = EvalHelper.getBigDecimalOrNull( expression.evaluate( ctx ) ); if ( result == null ) { ctx.notifyEvt( astEvent(Severity.WARN, Msg.createMessage(Msg.NEGATING_A_NULL))); return null; } else if ( Sign.NEGATIVE == sign ) { return BigDecimal.valueOf( -1 ).multiply( result ); } else { return result; } }
public static Expression external(List<String> paramNames, BaseNode body) { EvaluationContextImpl emptyEvalCtx = new EvaluationContextImpl(Functions.class.getClassLoader(), new FEELEventListenersManager()); Map<String, Object> conf = (Map<String, Object>) body.evaluate(emptyEvalCtx); Map<String, String> java = (Map<String, String>) conf.get( "java" ); if (java != null) { String className = java.get("class"); String methodSignature = java.get("method signature"); if (className == null || methodSignature == null) { throw new FEELCompilationError( Msg.createMessage(Msg.UNABLE_TO_FIND_EXTERNAL_FUNCTION_AS_DEFINED_BY, methodSignature)); } return FunctionDefs.asMethodCall(className, methodSignature, paramNames); } else { throw new FEELCompilationError(Msg.createMessage(Msg.UNABLE_TO_FIND_EXTERNAL_FUNCTION_AS_DEFINED_BY, null)); } }
private UnaryTest createInUnaryTest() { return (c, o) -> { if (o == null) { return false; } Object val = value.evaluate( c ); if (val instanceof Range) { try { return ((Range) val).includes(o); } catch (Exception e) { c.notifyEvt(astEvent(Severity.ERROR, Msg.createMessage(Msg.EXPRESSION_IS_RANGE_BUT_VALUE_IS_NOT_COMPARABLE, o.toString(), val.toString()))); throw e; } } else if (val instanceof Collection) { return ((Collection) val).contains(o); } else { return false; // make consistent with #createNotUnaryTest() } }; }
private void valueMustBeANumber(EvaluationContext ctx, Object value) { if (!(value instanceof BigDecimal)) { ctx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, Msg.createMessage(Msg.VALUE_X_NOT_A_VALID_ENDPOINT_FOR_RANGE_BECAUSE_NOT_A_NUMBER, value), null)); throw new EndpointOfRangeNotOfNumberException(); } }
private void valueMustBeANumber(EvaluationContext ctx, Object value) { if (!(value instanceof BigDecimal)) { ctx.notifyEvt(astEvent(Severity.ERROR, Msg.createMessage(Msg.VALUE_X_NOT_A_VALID_ENDPOINT_FOR_RANGE_BECAUSE_NOT_A_NUMBER, value), null)); throw new EndpointOfRangeNotOfNumberException(); } }
private UnaryTest createBooleanUnaryTest( ) { return (context, left) -> { Object right = value.evaluate( context ); if( right instanceof Boolean ) { return (Boolean) right; } else { context.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.EXTENDED_UNARY_TEST_MUST_BE_BOOLEAN, left.toString(), value.toString() ) ) ); return Boolean.FALSE; } }; }
private Boolean in(EvaluationContext ctx, Object value, Object expr) { // need to improve this to work with unary tests if ( expr == null ) { return value == expr; } else if ( expr instanceof UnaryTest ) { return ((UnaryTest) expr).apply( ctx, value ); } else if ( expr instanceof Range ) { try { return ((Range) expr).includes( 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; } } else if ( value != null ) { return value.equals( expr ); } else { // value == null, expr != null return Boolean.FALSE; } }
public Object satisfies(Function<EvaluationContext, Object> expression) { if (quantOp == Quantifier.SOME || quantOp == Quantifier.EVERY) { return iterateContexts(ctx, iterationContexts, expression, quantOp); } // can never happen, but anyway: ctx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, Msg.createMessage(Msg.IS_NULL, "Quantifier"), null)); return null; }
@Override public Boolean evaluate(EvaluationContext ctx) { if( quantifier == Quantifier.SOME || quantifier == Quantifier.EVERY ) { return iterateContexts( ctx, iterationContexts, expression, quantifier ); } ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.IS_NULL, "Quantifier")) ); return null; }
@Override public Range evaluate(EvaluationContext ctx) { Object s = start.evaluate( ctx ); Object e = end.evaluate( ctx ); boolean problem = false; if ( s == null ) { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.IS_NULL, "Start"))); problem = true; } if ( e == null ) { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.IS_NULL, "End"))); problem = true; } if (problem) { return null; } if ( BuiltInType.determineTypeFromInstance( s ) != BuiltInType.determineTypeFromInstance( e ) && !s.getClass().isAssignableFrom( e.getClass() ) ) { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.X_TYPE_INCOMPATIBLE_WITH_Y_TYPE, "Start", "End"))); return null; } Comparable start = convertToComparable( ctx, s ); Comparable end = convertToComparable( ctx, e ); return new RangeImpl( lowerBound==IntervalBoundary.OPEN ? Range.RangeBoundary.OPEN : Range.RangeBoundary.CLOSED, start, end, upperBound==IntervalBoundary.OPEN ? Range.RangeBoundary.OPEN : Range.RangeBoundary.CLOSED ); }
@Override public Object evaluate(EvaluationContext ctx) { String varName = EvalHelper.normalizeVariableName( getText() ); if( ! ctx.isDefined( varName ) ) { ctx.notifyEvt( astEvent( FEELEvent.Severity.ERROR, Msg.createMessage( Msg.UNKNOWN_VARIABLE_REFERENCE, getText()), null) ); return null; } return ctx.getValue( varName ); }
@Test public void testVariableNameWithInvalidCharacterPercent() { String var = "?_873./-'%+*valid"; assertThat( FEELParser.isVariableNameValid( var ), is( false ) ); assertThat( FEELParser.checkVariableName( var ).get( 0 ).getMessage(), is( Msg.createMessage(Msg.INVALID_VARIABLE_NAME, "character", "%") ) ); }
@Test public void testVariableNameCantStartWithKeyword() { String var = "for keyword is an invalid start for a variable name"; assertThat( FEELParser.isVariableNameValid( var ), is( false ) ); assertThat( FEELParser.checkVariableName( var ).get( 0 ).getMessage(), is( Msg.createMessage(Msg.INVALID_VARIABLE_NAME_START, "keyword", "for") ) ); }
@Test public void testVariableNameInvalidStartCharacter() { String var = "5variable can't start with a number"; assertThat( FEELParser.isVariableNameValid( var ), is( false ) ); assertThat( FEELParser.checkVariableName( var ).get( 0 ).getMessage(), is( Msg.createMessage(Msg.INVALID_VARIABLE_NAME_START, "character", "5") ) ); }
public static Object invoke(EvaluationContext feelExprCtx, Object function, Object params) { if (function == null) { feelExprCtx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, Msg.createMessage(Msg.FUNCTION_NOT_FOUND, function), null)); return null; } if (function instanceof FEELFunction) { Object[] invocationParams = toFunctionParams(params); FEELFunction f = (FEELFunction) function; if (function instanceof CompiledCustomFEELFunction) { CompiledCustomFEELFunction ff = (CompiledCustomFEELFunction) function; if (ff.isProperClosure()) { return ff.invokeReflectively(ff.getEvaluationContext(), invocationParams); } } return f.invokeReflectively(feelExprCtx, invocationParams); } else if (function instanceof UnaryTest) { return ((UnaryTest) function).apply(feelExprCtx, ((List)params).get(0)); } return null; }