@@ -149,6 +149,7 @@ interface IEnumerableSignatures
149
149
void Take ( int count ) ;
150
150
void TakeWhile ( bool predicate ) ;
151
151
void Distinct ( ) ;
152
+ void GroupBy ( object selector ) ;
152
153
153
154
//Executors
154
155
void Single ( ) ;
@@ -222,6 +223,7 @@ interface IEnumerableSignatures
222
223
223
224
readonly Dictionary < string , object > _symbols ;
224
225
IDictionary < string , object > _externals ;
226
+ readonly Dictionary < string , object > _internals ;
225
227
readonly Dictionary < Expression , string > _literals ;
226
228
ParameterExpression _it ;
227
229
ParameterExpression _parent ;
@@ -269,6 +271,7 @@ public ExpressionParser(ParameterExpression[] parameters, string expression, obj
269
271
{
270
272
if ( _keywords == null ) _keywords = CreateKeywords ( ) ;
271
273
_symbols = new Dictionary < string , object > ( StringComparer . OrdinalIgnoreCase ) ;
274
+ _internals = new Dictionary < string , object > ( ) ;
272
275
_literals = new Dictionary < Expression , string > ( ) ;
273
276
if ( parameters != null ) ProcessParameters ( parameters ) ;
274
277
if ( values != null ) ProcessValues ( values ) ;
@@ -388,7 +391,7 @@ Expression ParseExpression()
388
391
// ?? (null-coalescing) operator
389
392
Expression ParseNullCoalescing ( )
390
393
{
391
- Expression expr = ParseConditionalOr ( ) ;
394
+ Expression expr = ParseLambda ( ) ;
392
395
if ( _textParser . CurrentToken . Id == TokenId . NullCoalescing )
393
396
{
394
397
_textParser . NextToken ( ) ;
@@ -398,6 +401,24 @@ Expression ParseNullCoalescing()
398
401
return expr ;
399
402
}
400
403
404
+ // => operator - Added Support for projection operator
405
+ Expression ParseLambda ( )
406
+ {
407
+ Expression expr = ParseConditionalOr ( ) ;
408
+ if ( _textParser . CurrentToken . Id == TokenId . Lambda && _it . Type == expr . Type )
409
+ {
410
+ _textParser . NextToken ( ) ;
411
+ if ( _textParser . CurrentToken . Id == TokenId . Identifier ||
412
+ _textParser . CurrentToken . Id == TokenId . OpenParen )
413
+ {
414
+ var right = ParseExpression ( ) ;
415
+ return Expression . Lambda ( right , new [ ] { ( ParameterExpression ) expr } ) ;
416
+ }
417
+ _textParser . ValidateToken ( TokenId . OpenParen , Res . OpenParenExpected ) ;
418
+ }
419
+ return expr ;
420
+ }
421
+
401
422
// isnull(a,b) operator
402
423
Expression ParseIsNull ( )
403
424
{
@@ -1003,7 +1024,8 @@ Expression ParseIdentifier()
1003
1024
}
1004
1025
1005
1026
if ( _symbols . TryGetValue ( _textParser . CurrentToken . Text , out value ) ||
1006
- _externals != null && _externals . TryGetValue ( _textParser . CurrentToken . Text , out value ) )
1027
+ _externals != null && _externals . TryGetValue ( _textParser . CurrentToken . Text , out value ) ||
1028
+ _internals . TryGetValue ( _textParser . CurrentToken . Text , out value ) )
1007
1029
{
1008
1030
Expression expr = value as Expression ;
1009
1031
if ( expr == null )
@@ -1093,7 +1115,9 @@ Expression GenerateConditional(Expression test, Expression expr1, Expression exp
1093
1115
Expression ParseNew ( )
1094
1116
{
1095
1117
_textParser . NextToken ( ) ;
1096
- _textParser . ValidateToken ( TokenId . OpenParen , Res . OpenParenExpected ) ;
1118
+ if ( _textParser . CurrentToken . Id != TokenId . OpenParen &&
1119
+ _textParser . CurrentToken . Id != TokenId . OpenCurlyParen )
1120
+ throw ParseError ( Res . OpenParenExpected ) ;
1097
1121
_textParser . NextToken ( ) ;
1098
1122
1099
1123
var properties = new List < DynamicProperty > ( ) ;
@@ -1125,7 +1149,9 @@ Expression ParseNew()
1125
1149
_textParser . NextToken ( ) ;
1126
1150
}
1127
1151
1128
- _textParser . ValidateToken ( TokenId . CloseParen , Res . CloseParenOrCommaExpected ) ;
1152
+ if ( _textParser . CurrentToken . Id != TokenId . CloseParen &&
1153
+ _textParser . CurrentToken . Id != TokenId . CloseCurlyParen )
1154
+ throw ParseError ( Res . CloseParenOrCommaExpected ) ;
1129
1155
_textParser . NextToken ( ) ;
1130
1156
1131
1157
return CreateNewExpression ( properties , expressions ) ;
@@ -1134,7 +1160,7 @@ Expression ParseNew()
1134
1160
private Expression CreateNewExpression ( List < DynamicProperty > properties , List < Expression > expressions )
1135
1161
{
1136
1162
// http://solutionizing.net/category/linq/
1137
- Type type = _resultType ;
1163
+ Type type = null ; // _resultType;
1138
1164
1139
1165
if ( type == null )
1140
1166
{
@@ -1323,7 +1349,19 @@ Expression ParseMemberAccess(Type type, Expression instance)
1323
1349
MemberInfo member = FindPropertyOrField ( type , id , instance == null ) ;
1324
1350
if ( member == null )
1325
1351
{
1326
- throw ParseError ( errorPos , Res . UnknownPropertyOrField , id , GetTypeName ( type ) ) ;
1352
+ if ( _textParser . CurrentToken . Id == TokenId . Lambda && _it . Type == type )
1353
+ {
1354
+ // This might be an internal variable for use within a lambda expression, so store it as such
1355
+ _internals . Add ( id , _it ) ;
1356
+ _textParser . NextToken ( ) ;
1357
+ var right = ParseExpression ( ) ;
1358
+ return right ;
1359
+ }
1360
+ else
1361
+ {
1362
+ throw ParseError ( errorPos , Res . UnknownPropertyOrField , id , GetTypeName ( type ) ) ;
1363
+ }
1364
+
1327
1365
}
1328
1366
1329
1367
var property = member as PropertyInfo ;
@@ -1381,7 +1419,7 @@ Expression ParseAggregate(Expression instance, Type elementType, string methodNa
1381
1419
throw ParseError ( errorPos , Res . NoApplicableAggregate , methodName ) ;
1382
1420
1383
1421
Type [ ] typeArgs ;
1384
- if ( new [ ] { "Min" , "Max" , "Select" , "OrderBy" , "OrderByDescending" , "ThenBy" , "ThenByDescending" } . Contains ( signature . Name ) )
1422
+ if ( new [ ] { "Min" , "Max" , "Select" , "OrderBy" , "OrderByDescending" , "ThenBy" , "ThenByDescending" , "GroupBy" } . Contains ( signature . Name ) )
1385
1423
{
1386
1424
typeArgs = new [ ] { elementType , args [ 0 ] . Type } ;
1387
1425
}
0 commit comments