1
1
/******************************************************************************************************
2
2
Title : ExpressionEvaluator (https://github.com/codingseb/ExpressionEvaluator)
3
- Version : 1.3.1 .0
3
+ Version : 1.3.2 .0
4
4
(if last digit is not a zero, the version is an intermediate version and can be unstable)
5
5
6
6
Author : Coding Seb
@@ -29,11 +29,10 @@ public class ExpressionEvaluator
29
29
private static readonly string diactitics = "áàâãåǎăāąæéèêëěēĕėęěìíîïīĭįijóôõöōŏőøðœùúûüǔũūŭůűųýþÿŷıćĉċčçďđĝğġģĥħĵķĺļľŀłńņňŋñŕŗřśŝşšţťŧŵźżžÁÀÂÃÅǍĂĀĄÆÉÈÊËĚĒĔĖĘĚÌÍÎÏĪĬĮIJÓÔÕÖŌŎŐØÐŒÙÚÛÜǓŨŪŬŮŰŲÝÞŸŶIĆĈĊČÇĎĐĜĞĠĢĤĦĴĶĹĻĽĿŁŃŅŇŊÑŔŖŘŚŜŞŠŢŤŦŴŹŻŽß" ;
30
30
private static readonly string diactiticsKeywordsRegexPattern = "a-zA-Z_" + diactitics ;
31
31
32
- private static readonly Regex varOrFunctionRegEx = new Regex ( @"^((?<sign>[+-])|(?<inObject>(?<nullConditional>[?])?\.)?)(?<name>[" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @" 0-9]*)\s*((?<assignationOperator>(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>]))|(?<postfixOperator>([+][+]|--)(?![" + diactiticsKeywordsRegexPattern + @" 0-9]))|((?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?))", RegexOptions . IgnoreCase | RegexOptions . Compiled ) ;
32
+ private static readonly Regex varOrFunctionRegEx = new Regex ( $ @ "^((?<sign>[+-])|(?<inObject>(?<nullConditional>[?])?\.)?)(?<name>[{ diactiticsKeywordsRegexPattern } ][ { diactiticsKeywordsRegexPattern } 0-9]*)\s*((?<assignationOperator>(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>]))|(?<postfixOperator>([+][+]|--)(?![{ diactiticsKeywordsRegexPattern } 0-9]))|((?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?))", RegexOptions . IgnoreCase | RegexOptions . Compiled ) ;
33
33
private static readonly Regex numberRegex = new Regex ( @"^(?<sign>[+-])?\d+(?<hasdecimal>\.?\d+(e[+-]?\d+)?)?(?<type>ul|[fdulm])?" , RegexOptions . IgnoreCase ) ;
34
34
private static readonly Regex stringBeginningRegex = new Regex ( "^(?<interpolated>[$])?(?<escaped>[@])?[\" ]" ) ;
35
35
private static readonly Regex internalCharRegex = new Regex ( @"^['](\\[']|[^'])*[']" ) ;
36
- private static readonly Regex castRegex = new Regex ( @"^\(\s*(?<typeName>[" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @"0-9\.\[\]<>]*[?]?)\s*\)" ) ;
37
36
private static readonly Regex indexingBeginningRegex = new Regex ( @"^[?]?\[" ) ;
38
37
private static readonly Regex assignationOrPostFixOperatorRegex = new Regex ( @"^\s*((?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>])|(?<postfixOperator>([+][+]|--)(?![" + diactiticsKeywordsRegexPattern + @"0-9])))" ) ;
39
38
@@ -43,13 +42,18 @@ public class ExpressionEvaluator
43
42
private static readonly Regex endOfStringWithoutDollarWithAt = new Regex ( "^[^\" ]*[\" ]" ) ;
44
43
private static readonly Regex endOfStringInterpolationRegex = new Regex ( "^('\" '|[^}\" ])*[}\" ]" ) ;
45
44
private static readonly Regex stringBeginningForEndBlockRegex = new Regex ( "[$]?[@]?[\" ]$" ) ;
46
- private static readonly Regex lambdaExpressionRegex = new Regex ( @"^\s*(?<args>(\s*[(]\s*([" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @" 0-9]*\s*([,]\s*[" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @" 0-9]*\s*)*)?[)])|[" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @" 0-9]*)\s*=>(?<expression>.*)$", RegexOptions . Singleline ) ;
47
- private static readonly Regex lambdaArgRegex = new Regex ( @"[" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @" 0-9]*") ;
45
+ private static readonly Regex lambdaExpressionRegex = new Regex ( $ @ "^\s*(?<args>(\s*[(]\s*([{ diactiticsKeywordsRegexPattern } ][ { diactiticsKeywordsRegexPattern } 0-9]*\s*([,]\s*[{ diactiticsKeywordsRegexPattern } ][ { diactiticsKeywordsRegexPattern } 0-9]*\s*)*)?[)])|[{ diactiticsKeywordsRegexPattern } ][ { diactiticsKeywordsRegexPattern } 0-9]*)\s*=>(?<expression>.*)$", RegexOptions . Singleline ) ;
46
+ private static readonly Regex lambdaArgRegex = new Regex ( $ @ "[{ diactiticsKeywordsRegexPattern } ][ { diactiticsKeywordsRegexPattern } 0-9]*") ;
48
47
private static readonly Regex initInNewBeginningRegex = new Regex ( @"^\s*{" ) ;
49
48
private static readonly Regex OtherDimentionArrayInNewBeginningRegex = new Regex ( @"^\s*\[" ) ;
50
49
51
- private static readonly string instanceCreationWithNewKeywordRegexPattern = @"^new\s+(?<name>[" + diactiticsKeywordsRegexPattern + @"][" + diactiticsKeywordsRegexPattern + @"0-9.]*)\s*(?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?\s*((?<isfunction>[(])|(?<isArray>\[))?" ;
52
- private Regex instanceCreationWithNewKeywordRegex = new Regex ( instanceCreationWithNewKeywordRegexPattern ) ;
50
+
51
+ // Depending on OptionInlineNamespacesEvaluationActive. Initialized in constructor
52
+ private string CastRegexPattern { get { return $@ "^\(\s*(?<typeName>[{ diactiticsKeywordsRegexPattern } ][{ diactiticsKeywordsRegexPattern } 0-9\{ ( OptionInlineNamespacesEvaluationActive ? @"\." : string . Empty ) } [\]<>]*[?]?)\s*\)"; } }
53
+ private string InstanceCreationWithNewKeywordRegexPattern { get { return $@ "^new\s+(?<name>[{ diactiticsKeywordsRegexPattern } ][{ diactiticsKeywordsRegexPattern } 0-9{ ( OptionInlineNamespacesEvaluationActive ? @"\." : string . Empty ) } ]*)\s*(?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?\s*((?<isfunction>[(])|(?<isArray>\[))?"; } }
54
+ private Regex instanceCreationWithNewKeywordRegex = null ;
55
+ private Regex castRegex = null ;
56
+
53
57
private static readonly string primaryTypesRegexPattern = @"(?<=^|[^" + diactiticsKeywordsRegexPattern + @"])(?<primaryType>object|string|bool[?]?|byte[?]?|char[?]?|decimal[?]?|double[?]?|short[?]?|int[?]?|long[?]?|sbyte[?]?|float[?]?|ushort[?]?|uint[?]?|void)(?=[^a-zA-Z_]|$)" ;
54
58
private Regex primaryTypesRegex = new Regex ( primaryTypesRegexPattern ) ;
55
59
@@ -462,7 +466,7 @@ public bool OptionCaseSensitiveEvaluationActive
462
466
simpleDoubleMathFuncsDictionary = new Dictionary < string , Func < double , double > > ( simpleDoubleMathFuncsDictionary , StringComparerForCasing ) ;
463
467
doubleDoubleMathFuncsDictionary = new Dictionary < string , Func < double , double , double > > ( doubleDoubleMathFuncsDictionary , StringComparerForCasing ) ;
464
468
complexStandardFuncsDictionary = new Dictionary < string , Func < ExpressionEvaluator , List < string > , object > > ( complexStandardFuncsDictionary , StringComparerForCasing ) ;
465
- instanceCreationWithNewKeywordRegex = new Regex ( instanceCreationWithNewKeywordRegexPattern , ( optionCaseSensitiveEvaluationActive ? RegexOptions . None : RegexOptions . IgnoreCase ) ) ;
469
+ instanceCreationWithNewKeywordRegex = new Regex ( InstanceCreationWithNewKeywordRegexPattern , ( optionCaseSensitiveEvaluationActive ? RegexOptions . None : RegexOptions . IgnoreCase ) ) ;
466
470
primaryTypesRegex = new Regex ( primaryTypesRegexPattern , ( optionCaseSensitiveEvaluationActive ? RegexOptions . None : RegexOptions . IgnoreCase ) ) ;
467
471
}
468
472
}
@@ -489,6 +493,22 @@ private StringComparer StringComparerForCasing
489
493
/// </summary>
490
494
public bool OptionNewKeywordEvaluationActive { get ; set ; } = true ;
491
495
496
+ /// <summary>
497
+ /// if <c>true</c> allow the use of inline namespace (Can be slow, and is less secure).
498
+ /// if <c>false</c> unactive inline namespace (only namespaces in Namespaces list are available).
499
+ /// By default : true
500
+ /// </summary>
501
+ public bool OptionInlineNamespacesEvaluationActive
502
+ {
503
+ get { return optionInlineNamespacesEvaluationActive ; }
504
+ set
505
+ {
506
+ optionInlineNamespacesEvaluationActive = value ;
507
+ instanceCreationWithNewKeywordRegex = new Regex ( InstanceCreationWithNewKeywordRegexPattern , ( optionCaseSensitiveEvaluationActive ? RegexOptions . None : RegexOptions . IgnoreCase ) ) ;
508
+ castRegex = new Regex ( CastRegexPattern , ( optionCaseSensitiveEvaluationActive ? RegexOptions . None : RegexOptions . IgnoreCase ) ) ;
509
+ }
510
+ }
511
+
492
512
private Func < ExpressionEvaluator , List < string > , object > newMethodMem ;
493
513
494
514
/// <summary>
@@ -673,6 +693,8 @@ public Dictionary<string, object> Variables
673
693
public ExpressionEvaluator ( )
674
694
{
675
695
Assemblies . AddRange ( AppDomain . CurrentDomain . GetAssemblies ( ) ) ;
696
+ instanceCreationWithNewKeywordRegex = new Regex ( InstanceCreationWithNewKeywordRegexPattern ) ;
697
+ castRegex = new Regex ( CastRegexPattern ) ;
676
698
}
677
699
678
700
/// <summary>
@@ -689,6 +711,7 @@ public ExpressionEvaluator(Dictionary<string, object> variables) : this()
689
711
#region Main evaluate methods (Expressions and scripts ==> public)
690
712
691
713
private bool inScript = false ;
714
+ private bool optionInlineNamespacesEvaluationActive = true ;
692
715
693
716
/// <summary>
694
717
/// Evaluate a script (multiple expressions separated by semicolon)
@@ -1766,6 +1789,35 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
1766
1789
string typeName = $ "{ varFuncName } { ( ( i < expr . Length && expr . Substring ( i ) [ 0 ] == '?' ) ? "?" : "" ) } ";
1767
1790
Type staticType = GetTypeByFriendlyName ( typeName ) ;
1768
1791
1792
+ if ( staticType == null && OptionInlineNamespacesEvaluationActive )
1793
+ {
1794
+ int subIndex = 0 ;
1795
+ Match namespaceMatch = varOrFunctionRegEx . Match ( expr . Substring ( i + subIndex ) ) ;
1796
+
1797
+ while ( staticType == null &&
1798
+ namespaceMatch . Success &&
1799
+ ! namespaceMatch . Groups [ "sign" ] . Success &&
1800
+ ! namespaceMatch . Groups [ "assignationOperator" ] . Success &&
1801
+ ! namespaceMatch . Groups [ "postfixOperator" ] . Success &&
1802
+ ! namespaceMatch . Groups [ "postfixOperator" ] . Success &&
1803
+ ! namespaceMatch . Groups [ "isfunction" ] . Success &&
1804
+ i + subIndex < expr . Length &&
1805
+ ! typeName . EndsWith ( "?" ) )
1806
+ {
1807
+ subIndex += namespaceMatch . Length ;
1808
+ typeName += $ "{ namespaceMatch . Value } { ( ( i + subIndex < expr . Length && expr . Substring ( i + subIndex ) [ 0 ] == '?' ) ? "?" : "" ) } ";
1809
+ staticType = GetTypeByFriendlyName ( typeName ) ;
1810
+
1811
+ if ( staticType != null )
1812
+ {
1813
+ i += subIndex ;
1814
+ break ;
1815
+ }
1816
+
1817
+ namespaceMatch = varOrFunctionRegEx . Match ( expr . Substring ( i + subIndex ) ) ;
1818
+ }
1819
+ }
1820
+
1769
1821
if ( typeName . EndsWith ( "?" ) && staticType != null )
1770
1822
i ++ ;
1771
1823
@@ -2584,11 +2636,14 @@ private Type GetTypeByFriendlyName(string typeName)
2584
2636
2585
2637
for ( int a = 0 ; a < Assemblies . Count && result == null ; a ++ )
2586
2638
{
2587
- result = Type . GetType ( $ " { typeName } , { Assemblies [ a ] . FullName } " , false , ! OptionCaseSensitiveEvaluationActive ) ;
2588
-
2589
- for ( int i = 0 ; i < Namespaces . Count && result == null ; i ++ )
2639
+ if ( typeName . Contains ( "." ) )
2640
+ result = Type . GetType ( $ " { typeName } , { Assemblies [ a ] . FullName } " , false , ! OptionCaseSensitiveEvaluationActive ) ;
2641
+ else
2590
2642
{
2591
- result = Type . GetType ( $ "{ Namespaces [ i ] } .{ typeName } ,{ Assemblies [ a ] . FullName } ", false , ! OptionCaseSensitiveEvaluationActive ) ;
2643
+ for ( int i = 0 ; i < Namespaces . Count && result == null ; i ++ )
2644
+ {
2645
+ result = Type . GetType ( $ "{ Namespaces [ i ] } .{ typeName } ,{ Assemblies [ a ] . FullName } ", false , ! OptionCaseSensitiveEvaluationActive ) ;
2646
+ }
2592
2647
}
2593
2648
}
2594
2649
}
0 commit comments