1- // Copyright (c) Microsoft Corporation.
2- // Licensed under the MIT License.
3-
4- using FastExpressionCompiler ;
5- using RulesEngine . HelperFunctions ;
6- using RulesEngine . Models ;
7- using System ;
8- using System . Collections . Generic ;
9- using System . Linq ;
10- using System . Linq . Dynamic . Core ;
11- using System . Linq . Dynamic . Core . Exceptions ;
12- using System . Linq . Dynamic . Core . Parser ;
13- using System . Linq . Expressions ;
14- using System . Reflection ;
15- using System . Text . RegularExpressions ;
16-
17- namespace RulesEngine . ExpressionBuilders
18- {
19- public class RuleExpressionParser
20- {
21- private readonly ReSettings _reSettings ;
22- private readonly IDictionary < string , MethodInfo > _methodInfo ;
23-
24- public RuleExpressionParser ( ReSettings reSettings = null )
25- {
26- _reSettings = reSettings ?? new ReSettings ( ) ;
27- _methodInfo = new Dictionary < string , MethodInfo > ( ) ;
28- PopulateMethodInfo ( ) ;
29- }
30-
31- private void PopulateMethodInfo ( )
32- {
33- var dict_add = typeof ( Dictionary < string , object > ) . GetMethod ( "Add" , BindingFlags . Public | BindingFlags . Instance , null , new [ ] { typeof ( string ) , typeof ( object ) } , null ) ;
34- _methodInfo . Add ( "dict_add" , dict_add ) ;
35- }
36- public Expression Parse ( string expression , ParameterExpression [ ] parameters , Type returnType )
37- {
1+ // Copyright (c) Microsoft Corporation.
2+ // Licensed under the MIT License.
3+
4+ using FastExpressionCompiler ;
5+ using RulesEngine . HelperFunctions ;
6+ using RulesEngine . Models ;
7+ using System ;
8+ using System . Collections . Generic ;
9+ using System . Linq ;
10+ using System . Linq . Dynamic . Core ;
11+ using System . Linq . Dynamic . Core . Exceptions ;
12+ using System . Linq . Dynamic . Core . Parser ;
13+ using System . Linq . Expressions ;
14+ using System . Reflection ;
15+ using System . Text . RegularExpressions ;
16+
17+ namespace RulesEngine . ExpressionBuilders
18+ {
19+ public class RuleExpressionParser
20+ {
21+ private readonly ReSettings _reSettings ;
22+ private readonly IDictionary < string , MethodInfo > _methodInfo ;
23+
24+ public RuleExpressionParser ( ReSettings reSettings = null )
25+ {
26+ _reSettings = reSettings ?? new ReSettings ( ) ;
27+ _methodInfo = new Dictionary < string , MethodInfo > ( ) ;
28+ PopulateMethodInfo ( ) ;
29+ }
30+
31+ private void PopulateMethodInfo ( )
32+ {
33+ var dict_add = typeof ( Dictionary < string , object > ) . GetMethod ( "Add" , BindingFlags . Public | BindingFlags . Instance , null , new [ ] { typeof ( string ) , typeof ( object ) } , null ) ;
34+ _methodInfo . Add ( "dict_add" , dict_add ) ;
35+ }
36+
37+ public Expression Parse ( string expression , ParameterExpression [ ] parameters , Type returnType )
38+ {
3839 var config = new ParsingConfig {
39- CustomTypeProvider = new CustomTypeProvider ( _reSettings . CustomTypes ) ,
40- IsCaseSensitive = _reSettings . IsExpressionCaseSensitive
40+ CustomTypeProvider = new CustomTypeProvider ( _reSettings . CustomTypes ) ,
41+ IsCaseSensitive = _reSettings . IsExpressionCaseSensitive
4142 } ;
4243
4344 // Instead of immediately returning default values, allow for expression parsing to handle dynamic evaluation.
@@ -47,14 +48,18 @@ public Expression Parse(string expression, ParameterExpression[] parameters, Typ
4748 }
4849 catch ( ParseException )
4950 {
51+ if ( _reSettings . EnableExceptionAsErrorMessageForRuleExpressionParsing )
52+ {
53+ throw ;
54+ }
5055 return Expression . Constant ( GetDefaultValueForType ( returnType ) ) ;
5156 }
52- catch ( Exception ex )
57+ catch ( Exception )
5358 {
54- throw new Exception ( $ "Expression parsing error: { ex . Message } " , ex ) ;
55- }
56- }
57-
59+ throw ;
60+ }
61+ }
62+
5863 private object GetDefaultValueForType ( Type type )
5964 {
6065 if ( type == typeof ( bool ) )
@@ -63,124 +68,124 @@ private object GetDefaultValueForType(Type type)
6368 return int . MinValue ;
6469 return null ;
6570 }
66-
67- public Func < object [ ] , T > Compile < T > ( string expression , RuleParameter [ ] ruleParams )
68- {
69- var rtype = typeof ( T ) ;
70- if ( rtype == typeof ( object ) )
71- {
72- rtype = null ;
73- }
71+
72+ public Func < object [ ] , T > Compile < T > ( string expression , RuleParameter [ ] ruleParams )
73+ {
74+ var rtype = typeof ( T ) ;
75+ if ( rtype == typeof ( object ) )
76+ {
77+ rtype = null ;
78+ }
7479 var parameterExpressions = GetParameterExpression ( ruleParams ) . ToArray ( ) ;
7580
76- var e = Parse ( expression , parameterExpressions , rtype ) ;
77- if ( rtype == null )
78- {
79- e = Expression . Convert ( e , typeof ( T ) ) ;
80- }
81- var expressionBody = new List < Expression > ( ) { e } ;
82- var wrappedExpression = WrapExpression < T > ( expressionBody , parameterExpressions , new ParameterExpression [ ] { } ) ;
83- return CompileExpression ( wrappedExpression ) ;
84-
85- }
86-
87- private Func < object [ ] , T > CompileExpression < T > ( Expression < Func < object [ ] , T > > expression )
88- {
89- if ( _reSettings . UseFastExpressionCompiler )
90- {
91- return expression . CompileFast ( ) ;
92- }
93- return expression . Compile ( ) ;
94- }
95-
96- private Expression < Func < object [ ] , T > > WrapExpression < T > ( List < Expression > expressionList , ParameterExpression [ ] parameters , ParameterExpression [ ] variables )
97- {
98- var argExp = Expression . Parameter ( typeof ( object [ ] ) , "args" ) ;
99- var paramExps = parameters . Select ( ( c , i ) => {
100- var arg = Expression . ArrayAccess ( argExp , Expression . Constant ( i ) ) ;
101- return ( Expression ) Expression . Assign ( c , Expression . Convert ( arg , c . Type ) ) ;
102- } ) ;
103- var blockExpSteps = paramExps . Concat ( expressionList ) ;
104- var blockExp = Expression . Block ( parameters . Concat ( variables ) , blockExpSteps ) ;
105- return Expression . Lambda < Func < object [ ] , T > > ( blockExp , argExp ) ;
106- }
107-
108- internal Func < object [ ] , Dictionary < string , object > > CompileRuleExpressionParameters ( RuleParameter [ ] ruleParams , RuleExpressionParameter [ ] ruleExpParams = null )
109- {
110- ruleExpParams = ruleExpParams ?? new RuleExpressionParameter [ ] { } ;
111- var expression = CreateDictionaryExpression ( ruleParams , ruleExpParams ) ;
112- return CompileExpression ( expression ) ;
113- }
114-
115- public T Evaluate < T > ( string expression , RuleParameter [ ] ruleParams )
81+ var e = Parse ( expression , parameterExpressions , rtype ) ;
82+ if ( rtype == null )
83+ {
84+ e = Expression . Convert ( e , typeof ( T ) ) ;
85+ }
86+ var expressionBody = new List < Expression > ( ) { e } ;
87+ var wrappedExpression = WrapExpression < T > ( expressionBody , parameterExpressions , new ParameterExpression [ ] { } ) ;
88+ return CompileExpression ( wrappedExpression ) ;
89+
90+ }
91+
92+ private Func < object [ ] , T > CompileExpression < T > ( Expression < Func < object [ ] , T > > expression )
11693 {
117- var func = Compile < T > ( expression , ruleParams ) ;
118- return func ( ruleParams . Select ( c => c . Value ) . ToArray ( ) ) ;
119- }
120-
121- private IEnumerable < Expression > CreateAssignedParameterExpression ( RuleExpressionParameter [ ] ruleExpParams )
122- {
123- return ruleExpParams . Select ( ( c , i ) => {
124- return Expression . Assign ( c . ParameterExpression , c . ValueExpression ) ;
125- } ) ;
126- }
127-
128- // <summary>
129- /// Gets the parameter expression.
130- /// </summary>
131- /// <param name="ruleParams">The types.</param>
132- /// <returns></returns>
133- /// <exception cref="ArgumentException">
134- /// types
135- /// or
136- /// type
137- /// </exception>
138- private IEnumerable < ParameterExpression > GetParameterExpression ( RuleParameter [ ] ruleParams )
139- {
140- foreach ( var ruleParam in ruleParams )
141- {
142- if ( ruleParam == null )
143- {
144- throw new ArgumentException ( $ "{ nameof ( ruleParam ) } can't be null.") ;
145- }
146-
147- yield return ruleParam . ParameterExpression ;
148- }
149- }
150-
151- private Expression < Func < object [ ] , Dictionary < string , object > > > CreateDictionaryExpression ( RuleParameter [ ] ruleParams , RuleExpressionParameter [ ] ruleExpParams )
152- {
153- var body = new List < Expression > ( ) ;
154- var paramExp = new List < ParameterExpression > ( ) ;
155- var variableExp = new List < ParameterExpression > ( ) ;
156-
157-
158- var variableExpressions = CreateAssignedParameterExpression ( ruleExpParams ) ;
159-
160- body . AddRange ( variableExpressions ) ;
161-
162- var dict = Expression . Variable ( typeof ( Dictionary < string , object > ) ) ;
163- var add = _methodInfo [ "dict_add" ] ;
164-
165- body . Add ( Expression . Assign ( dict , Expression . New ( typeof ( Dictionary < string , object > ) ) ) ) ;
166- variableExp . Add ( dict ) ;
167-
168- for ( var i = 0 ; i < ruleParams . Length ; i ++ )
169- {
170- paramExp . Add ( ruleParams [ i ] . ParameterExpression ) ;
171- }
172- for ( var i = 0 ; i < ruleExpParams . Length ; i ++ )
173- {
174- var key = Expression . Constant ( ruleExpParams [ i ] . ParameterExpression . Name ) ;
175- var value = Expression . Convert ( ruleExpParams [ i ] . ParameterExpression , typeof ( object ) ) ;
176- variableExp . Add ( ruleExpParams [ i ] . ParameterExpression ) ;
94+ if ( _reSettings . UseFastExpressionCompiler )
95+ {
96+ return expression . CompileFast ( ) ;
97+ }
98+ return expression . Compile ( ) ;
99+ }
100+
101+ private Expression < Func < object [ ] , T > > WrapExpression < T > ( List < Expression > expressionList , ParameterExpression [ ] parameters , ParameterExpression [ ] variables )
102+ {
103+ var argExp = Expression . Parameter ( typeof ( object [ ] ) , "args" ) ;
104+ var paramExps = parameters . Select ( ( c , i ) => {
105+ var arg = Expression . ArrayAccess ( argExp , Expression . Constant ( i ) ) ;
106+ return ( Expression ) Expression . Assign ( c , Expression . Convert ( arg , c . Type ) ) ;
107+ } ) ;
108+ var blockExpSteps = paramExps . Concat ( expressionList ) ;
109+ var blockExp = Expression . Block ( parameters . Concat ( variables ) , blockExpSteps ) ;
110+ return Expression . Lambda < Func < object [ ] , T > > ( blockExp , argExp ) ;
111+ }
112+
113+ internal Func < object [ ] , Dictionary < string , object > > CompileRuleExpressionParameters ( RuleParameter [ ] ruleParams , RuleExpressionParameter [ ] ruleExpParams = null )
114+ {
115+ ruleExpParams = ruleExpParams ?? new RuleExpressionParameter [ ] { } ;
116+ var expression = CreateDictionaryExpression ( ruleParams , ruleExpParams ) ;
117+ return CompileExpression ( expression ) ;
118+ }
119+
120+ public T Evaluate < T > ( string expression , RuleParameter [ ] ruleParams )
121+ {
122+ var func = Compile < T > ( expression , ruleParams ) ;
123+ return func ( ruleParams . Select ( c => c . Value ) . ToArray ( ) ) ;
124+ }
125+
126+ private IEnumerable < Expression > CreateAssignedParameterExpression ( RuleExpressionParameter [ ] ruleExpParams )
127+ {
128+ return ruleExpParams . Select ( ( c , i ) => {
129+ return Expression . Assign ( c . ParameterExpression , c . ValueExpression ) ;
130+ } ) ;
131+ }
132+
133+ // <summary>
134+ /// Gets the parameter expression.
135+ /// </summary>
136+ /// <param name="ruleParams">The types.</param>
137+ /// <returns></returns>
138+ /// <exception cref="ArgumentException">
139+ /// types
140+ /// or
141+ /// type
142+ /// </exception>
143+ private IEnumerable < ParameterExpression > GetParameterExpression ( RuleParameter [ ] ruleParams )
144+ {
145+ foreach ( var ruleParam in ruleParams )
146+ {
147+ if ( ruleParam == null )
148+ {
149+ throw new ArgumentException ( $ "{ nameof ( ruleParam ) } can't be null.") ;
150+ }
151+
152+ yield return ruleParam . ParameterExpression ;
153+ }
154+ }
155+
156+ private Expression < Func < object [ ] , Dictionary < string , object > > > CreateDictionaryExpression ( RuleParameter [ ] ruleParams , RuleExpressionParameter [ ] ruleExpParams )
157+ {
158+ var body = new List < Expression > ( ) ;
159+ var paramExp = new List < ParameterExpression > ( ) ;
160+ var variableExp = new List < ParameterExpression > ( ) ;
161+
162+
163+ var variableExpressions = CreateAssignedParameterExpression ( ruleExpParams ) ;
164+
165+ body . AddRange ( variableExpressions ) ;
166+
167+ var dict = Expression . Variable ( typeof ( Dictionary < string , object > ) ) ;
168+ var add = _methodInfo [ "dict_add" ] ;
169+
170+ body . Add ( Expression . Assign ( dict , Expression . New ( typeof ( Dictionary < string , object > ) ) ) ) ;
171+ variableExp . Add ( dict ) ;
172+
173+ for ( var i = 0 ; i < ruleParams . Length ; i ++ )
174+ {
175+ paramExp . Add ( ruleParams [ i ] . ParameterExpression ) ;
176+ }
177+ for ( var i = 0 ; i < ruleExpParams . Length ; i ++ )
178+ {
179+ var key = Expression . Constant ( ruleExpParams [ i ] . ParameterExpression . Name ) ;
180+ var value = Expression . Convert ( ruleExpParams [ i ] . ParameterExpression , typeof ( object ) ) ;
181+ variableExp . Add ( ruleExpParams [ i ] . ParameterExpression ) ;
177182 body . Add ( Expression . Call ( dict , add , key , value ) ) ;
178183
179- }
180- // Return value
181- body . Add ( dict ) ;
182-
183- return WrapExpression < Dictionary < string , object > > ( body , paramExp . ToArray ( ) , variableExp . ToArray ( ) ) ;
184- }
185- }
184+ }
185+ // Return value
186+ body . Add ( dict ) ;
187+
188+ return WrapExpression < Dictionary < string , object > > ( body , paramExp . ToArray ( ) , variableExp . ToArray ( ) ) ;
189+ }
190+ }
186191}
0 commit comments