/// <summary> /// Parses the specified text converting it into a expression action. /// </summary> /// <param name="text">The text to parse.</param> /// <returns></returns> public Expression <Func <decimal> > Parse(string text) { var body = language.Parse(text); body = ExpressionConversions.Convert(body, typeof(decimal)); return(Expression.Lambda <Func <decimal> >(body)); }
/// <summary> /// Returns the definitions for logic operators used within the language. /// </summary> /// <returns></returns> protected virtual IEnumerable <GrammerDefinition> LogicalOperatorDefinitions() { return(new GrammerDefinition[] { new BinaryOperatorDefinition( name: "EQ", regex: @"\b(eq)\b", orderOfPrecedence: 11, expressionBuilder: ConvertEnumsIfRequired((left, right) => Expression.Equal(left, right))), new BinaryOperatorDefinition( name: "NE", regex: @"\b(ne)\b", orderOfPrecedence: 12, expressionBuilder: ConvertEnumsIfRequired((left, right) => Expression.NotEqual(left, right))), new BinaryOperatorDefinition( name: "GT", regex: @"\b(gt)\b", orderOfPrecedence: 13, expressionBuilder: (left, right) => Expression.GreaterThan(left, right)), new BinaryOperatorDefinition( name: "GE", regex: @"\b(ge)\b", orderOfPrecedence: 14, expressionBuilder: (left, right) => Expression.GreaterThanOrEqual(left, right)), new BinaryOperatorDefinition( name: "LT", regex: @"\b(lt)\b", orderOfPrecedence: 15, expressionBuilder: (left, right) => Expression.LessThan(left, right)), new BinaryOperatorDefinition( name: "LE", regex: @"\b(le)\b", orderOfPrecedence: 16, expressionBuilder: (left, right) => Expression.LessThanOrEqual(left, right)), new BinaryOperatorDefinition( name: "AND", regex: @"\b(and)\b", orderOfPrecedence: 17, expressionBuilder: (left, right) => Expression.And(left, right)), new BinaryOperatorDefinition( name: "OR", regex: @"\b(or)\b", orderOfPrecedence: 18, expressionBuilder: (left, right) => Expression.Or(left, right)), new UnaryOperatorDefinition( name: "NOT", regex: @"\b(not)\b", orderOfPrecedence: 19, operandPosition: RelativePosition.Right, expressionBuilder: (arg) => { ExpressionConversions.TryBoolean(ref arg); return Expression.Not(arg); }) }); }
/// <summary> /// Returns the definitions for logic operators used within the language. /// </summary> /// <returns></returns> protected override IEnumerable <GrammerDefinition> LogicalOperatorDefinitions() { return(new GrammerDefinition[] { new BinaryOperatorDefinition( name: "EQ", regex: @"eq", orderOfPrecedence: 11, expressionBuilder: ConvertEnumsIfRequired((left, right) => Expression.Equal(left, right))), new BinaryOperatorDefinition( name: "NE", regex: @"ne", orderOfPrecedence: 12, expressionBuilder: ConvertEnumsIfRequired((left, right) => Expression.NotEqual(left, right))), new BinaryOperatorDefinition( name: "GT", regex: @"gt", orderOfPrecedence: 13, expressionBuilder: (left, right) => Expression.GreaterThan(left, right)), new BinaryOperatorDefinition( name: "GE", regex: @"ge", orderOfPrecedence: 14, expressionBuilder: (left, right) => Expression.GreaterThanOrEqual(left, right)), new BinaryOperatorDefinition( name: "LT", regex: @"lt", orderOfPrecedence: 15, expressionBuilder: (left, right) => Expression.LessThan(left, right)), new BinaryOperatorDefinition( name: "LE", regex: @"le", orderOfPrecedence: 16, expressionBuilder: (left, right) => Expression.LessThanOrEqual(left, right)), new BinaryOperatorDefinition( name: "AND", regex: @"and", orderOfPrecedence: 17, expressionBuilder: (left, right) => Expression.AndAlso(left, right)), new BinaryOperatorDefinition( name: "OR", regex: @"or", orderOfPrecedence: 18, expressionBuilder: (left, right) => Expression.OrElse(left, right)), new UnaryOperatorDefinition( name: "NOT", regex: @"not", orderOfPrecedence: 19, operandPosition: RelativePosition.Right, expressionBuilder: (arg) => { ExpressionConversions.TryBoolean(ref arg); return Expression.Not(arg); }) }); }
/// <summary> /// Parses the specified text converting it into an expression. The expression can take a single parameter /// </summary> /// <typeparam name="T">the type of the parameter.</typeparam> /// <param name="text">The text to parse.</param> /// <returns></returns> public Expression <Func <T, decimal> > Parse <T>(string text) { var parameters = new[] { Expression.Parameter(typeof(T)) }; var body = language.Parse(text, parameters); body = ExpressionConversions.Convert(body, typeof(decimal)); return(Expression.Lambda <Func <T, decimal> >(body, parameters)); }
/// <summary> /// Parses the specified text converting it into a predicate expression /// </summary> /// <typeparam name="T">The input type</typeparam> /// <param name="text">The text to parse.</param> /// <returns></returns> public Expression <Func <T, bool> > Parse <T>(string text) { var parameters = new[] { Expression.Parameter(typeof(T)) }; var body = language.Parse(text, parameters); ExpressionConversions.TryBoolean(ref body); return(Expression.Lambda <Func <T, bool> >(body, parameters)); }
/// <summary> /// Wraps the function to convert any constants to enums if required /// </summary> /// <param name="expFn">Function to wrap</param> /// <returns></returns> protected Func <Expression, Expression, Expression> ConvertEnumsIfRequired(Func <Expression, Expression, Expression> expFn) { return((left, right) => { var didConvertEnum = ExpressionConversions.TryEnumNumberConvert(ref left, ref right) || ExpressionConversions.TryEnumStringConvert(ref left, ref right, ignoreCase: true); return expFn(left, right); }); }
/// <summary> /// Applies the bracket operands. Executes the expressionBuilder with all the operands in the brackets. /// </summary> /// <param name="bracketOpen">The operator that opened the bracket.</param> /// <param name="bracketOperands">The list of operands within the brackets.</param> /// <param name="bracketClose">The operator that closed the bracket.</param> /// <param name="state">The current parse state.</param> /// <exception cref="FunctionArgumentCountException">When the number of opreands does not match the number of arguments</exception> /// <exception cref="FunctionArgumentTypeException">When argument Type does not match the type of the expression</exception> /// <exception cref="OperationInvalidException">When an error occured while executing the expressionBuilder</exception> public override void ApplyBracketOperands(Operator bracketOpen, Stack <Operand> bracketOperands, Operator bracketClose, ParseState state) { var operandSource = StringSegment.Encompass(bracketOperands.Select(x => x.SourceMap)); var functionArguments = bracketOperands.Select(x => x.Expression); //if we have been given specific argument types validate them if (ArgumentTypes != null) { var expectedArgumentCount = ArgumentTypes.Count; if (expectedArgumentCount != bracketOperands.Count) { throw new FunctionArgumentCountException( operandSource, expectedArgumentCount, bracketOperands.Count); } functionArguments = bracketOperands.Zip(ArgumentTypes, (o, t) => { try { return(ExpressionConversions.Convert(o.Expression, t)); } catch (InvalidOperationException) { //if we cant convert to the argument type then something is wrong with the argument //so we will throw it up throw new FunctionArgumentTypeException(o.SourceMap, t, o.Expression.Type); } }); } var functionSourceMap = StringSegment.Encompass(bracketOpen.SourceMap, operandSource); var functionArgumentsArray = functionArguments.ToArray(); Expression output; try { output = ExpressionBuilder(functionArgumentsArray); } catch (Exception ex) { throw new OperationInvalidException(functionSourceMap, ex); } if (output != null) { state.Operands.Push(new Operand(output, functionSourceMap)); } }
/// <summary> /// Initializes a new instance of the <see cref="BinaryOperatorDefinition"/> class. /// </summary> /// <param name="name">The name of the definition.</param> /// <param name="regex">The regex to match tokens.</param> /// <param name="orderOfPrecedence">The relative order this operator should be applied. Lower orders are applied first.</param> /// <param name="expressionBuilder">The function given the single operand expressions, outputs a new operand.</param> public BinaryOperatorDefinition(string name, string regex, int orderOfPrecedence, Func <Expression, Expression, Expression> expressionBuilder) : base( name: name, regex: regex, orderOfPrecedence: orderOfPrecedence, paramaterPositions: LeftRight, expressionBuilder: param => { var left = param[0]; var right = param[1]; ExpressionConversions.TryImplicitlyConvert(ref left, ref right); return(expressionBuilder(left, right)); }) { }