11using System . Collections . Generic ;
2+ using System . Diagnostics . CodeAnalysis ;
3+ using System . Linq . Dynamic . Core . Validation ;
24using System . Linq . Expressions ;
35
4- namespace System . Linq . Dynamic . Core . Parser
6+ namespace System . Linq . Dynamic . Core . Parser ;
7+
8+ internal class KeywordsHelper : IKeywordsHelper
59{
6- internal class KeywordsHelper : IKeywordsHelper
10+ public const string KEYWORD_IT = "it" ;
11+ public const string KEYWORD_PARENT = "parent" ;
12+ public const string KEYWORD_ROOT = "root" ;
13+
14+ public const string SYMBOL_IT = "$" ;
15+ public const string SYMBOL_PARENT = "^" ;
16+ public const string SYMBOL_ROOT = "~" ;
17+
18+ public const string FUNCTION_IIF = "iif" ;
19+ public const string FUNCTION_ISNULL = "isnull" ;
20+ public const string FUNCTION_NEW = "new" ;
21+ public const string FUNCTION_NULLPROPAGATION = "np" ;
22+ public const string FUNCTION_IS = "is" ;
23+ public const string FUNCTION_AS = "as" ;
24+ public const string FUNCTION_CAST = "cast" ;
25+
26+ private readonly ParsingConfig _config ;
27+
28+ // Keywords are IgnoreCase
29+ private readonly Dictionary < string , object > _keywordMapping = new ( StringComparer . OrdinalIgnoreCase )
730 {
8- public const string SYMBOL_IT = "$" ;
9- public const string SYMBOL_PARENT = "^" ;
10- public const string SYMBOL_ROOT = "~" ;
11-
12- public const string KEYWORD_IT = "it" ;
13- public const string KEYWORD_PARENT = "parent" ;
14- public const string KEYWORD_ROOT = "root" ;
15-
16- public const string FUNCTION_IIF = "iif" ;
17- public const string FUNCTION_ISNULL = "isnull" ;
18- public const string FUNCTION_NEW = "new" ;
19- public const string FUNCTION_NULLPROPAGATION = "np" ;
20- public const string FUNCTION_IS = "is" ;
21- public const string FUNCTION_AS = "as" ;
22- public const string FUNCTION_CAST = "cast" ;
23-
24- private readonly IDictionary < string , object > _keywords = new Dictionary < string , object > ( StringComparer . OrdinalIgnoreCase )
25- {
26- { "true" , Expression . Constant ( true ) } ,
27- { "false" , Expression . Constant ( false ) } ,
28- { "null" , Expression . Constant ( null ) }
29- } ;
31+ { "true" , Expression . Constant ( true ) } ,
32+ { "false" , Expression . Constant ( false ) } ,
33+ { "null" , Expression . Constant ( null ) } ,
34+
35+ { SYMBOL_IT , SYMBOL_IT } ,
36+ { SYMBOL_PARENT , SYMBOL_PARENT } ,
37+ { SYMBOL_ROOT , SYMBOL_ROOT } ,
38+
39+ { FUNCTION_IIF , FUNCTION_IIF } ,
40+ { FUNCTION_ISNULL , FUNCTION_ISNULL } ,
41+ { FUNCTION_NEW , FUNCTION_NEW } ,
42+ { FUNCTION_NULLPROPAGATION , FUNCTION_NULLPROPAGATION } ,
43+ { FUNCTION_IS , FUNCTION_IS } ,
44+ { FUNCTION_AS , FUNCTION_AS } ,
45+ { FUNCTION_CAST , FUNCTION_CAST }
46+ } ;
47+
48+ // PreDefined Types are not IgnoreCase
49+ private static readonly Dictionary < string , object > _preDefinedTypeMapping = new ( ) ;
50+
51+ // Custom DefinedTypes are not IgnoreCase
52+ private readonly Dictionary < string , object > _customTypeMapping = new ( ) ;
3053
31- public KeywordsHelper ( ParsingConfig config )
54+ static KeywordsHelper ( )
55+ {
56+ foreach ( var type in PredefinedTypesHelper . PredefinedTypes . OrderBy ( kvp => kvp . Value ) . Select ( kvp => kvp . Key ) )
3257 {
33- if ( config . AreContextKeywordsEnabled )
34- {
35- _keywords . Add ( KEYWORD_IT , KEYWORD_IT ) ;
36- _keywords . Add ( KEYWORD_PARENT , KEYWORD_PARENT ) ;
37- _keywords . Add ( KEYWORD_ROOT , KEYWORD_ROOT ) ;
38- }
58+ _preDefinedTypeMapping [ type . FullName ! ] = type ;
59+ _preDefinedTypeMapping [ type . Name ] = type ;
60+ }
61+ }
3962
40- _keywords . Add ( SYMBOL_IT , SYMBOL_IT ) ;
41- _keywords . Add ( SYMBOL_PARENT , SYMBOL_PARENT ) ;
42- _keywords . Add ( SYMBOL_ROOT , SYMBOL_ROOT ) ;
63+ public KeywordsHelper ( ParsingConfig config )
64+ {
65+ _config = Check . NotNull ( config ) ;
4366
44- _keywords . Add ( FUNCTION_IIF , FUNCTION_IIF ) ;
45- _keywords . Add ( FUNCTION_ISNULL , FUNCTION_ISNULL ) ;
46- _keywords . Add ( FUNCTION_NEW , FUNCTION_NEW ) ;
47- _keywords . Add ( FUNCTION_NULLPROPAGATION , FUNCTION_NULLPROPAGATION ) ;
48- _keywords . Add ( FUNCTION_IS , FUNCTION_IS ) ;
49- _keywords . Add ( FUNCTION_AS , FUNCTION_AS ) ;
50- _keywords . Add ( FUNCTION_CAST , FUNCTION_CAST ) ;
67+ if ( config . AreContextKeywordsEnabled )
68+ {
69+ _keywordMapping . Add ( KEYWORD_IT , KEYWORD_IT ) ;
70+ _keywordMapping . Add ( KEYWORD_PARENT , KEYWORD_PARENT ) ;
71+ _keywordMapping . Add ( KEYWORD_ROOT , KEYWORD_ROOT ) ;
72+ }
5173
52- foreach ( Type type in PredefinedTypesHelper . PredefinedTypes . OrderBy ( kvp => kvp . Value ) . Select ( kvp => kvp . Key ) )
74+ // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
75+ if ( config . CustomTypeProvider != null )
76+ {
77+ foreach ( var type in config . CustomTypeProvider . GetCustomTypes ( ) )
5378 {
54- if ( ! string . IsNullOrEmpty ( type . FullName ) )
55- {
56- _keywords [ type . FullName ] = type ;
57- }
58- _keywords [ type . Name ] = type ;
79+ _customTypeMapping [ type . FullName ! ] = type ;
80+ _customTypeMapping [ type . Name ] = type ;
5981 }
82+ }
83+ }
6084
61- foreach ( var pair in PredefinedTypesHelper . PredefinedTypesShorthands )
62- {
63- _keywords . Add ( pair . Key , pair . Value ) ;
64- }
85+ public bool TryGetValue ( string name , [ NotNullWhen ( true ) ] out object ? keyWordOrType )
86+ {
87+ // 1. Try to get as keyword
88+ if ( _keywordMapping . TryGetValue ( name , out var keyWord ) )
89+ {
90+ keyWordOrType = keyWord ;
91+ return true ;
92+ }
6593
66- if ( config . SupportEnumerationsFromSystemNamespace )
67- {
68- foreach ( var pair in EnumerationsFromMscorlib . PredefinedEnumerationTypes )
69- {
70- _keywords . Add ( pair . Key , pair . Value ) ;
71- }
72- }
94+ // 2. Try to get as predefined shorttype ("bool", "char", ...)
95+ if ( PredefinedTypesHelper . PredefinedTypesShorthands . TryGetValue ( name , out var predefinedShortHandType ) )
96+ {
97+ keyWordOrType = predefinedShortHandType ;
98+ return true ;
99+ }
73100
74- if ( config . CustomTypeProvider != null )
75- {
76- foreach ( Type type in config . CustomTypeProvider . GetCustomTypes ( ) )
77- {
78- _keywords [ type . FullName ] = type ;
79- _keywords [ type . Name ] = type ;
80- }
81- }
101+ // 3. Try to get as predefined type ("Boolean", "System.Boolean", ..., "DateTime", "System.DateTime", ...)
102+ if ( _preDefinedTypeMapping . TryGetValue ( name , out var predefinedType ) )
103+ {
104+ keyWordOrType = predefinedType ;
105+ return true ;
82106 }
83107
84- public bool TryGetValue ( string name , out object type )
108+ // 4. Try to get as an enum from the system namespace
109+ if ( _config . SupportEnumerationsFromSystemNamespace && EnumerationsFromMscorlib . PredefinedEnumerationTypes . TryGetValue ( name , out var predefinedEnumType ) )
85110 {
86- return _keywords . TryGetValue ( name , out type ) ;
111+ keyWordOrType = predefinedEnumType ;
112+ return true ;
87113 }
114+
115+ // 5. Try to get as custom type
116+ if ( _customTypeMapping . TryGetValue ( name , out var customType ) )
117+ {
118+ keyWordOrType = customType ;
119+ return true ;
120+ }
121+
122+ // 6. Not found, return false
123+ keyWordOrType = null ;
124+ return false ;
88125 }
89- }
126+ }
0 commit comments