@@ -218,11 +218,11 @@ internal IList<DynamicOrdering> ParseOrdering(bool forceThenBy = false)
218218        { 
219219            var  expr  =  ParseConditionalOperator ( ) ; 
220220            var  ascending  =  true ; 
221-             if  ( TokenIdentifierIs ( "asc" )  ||  TokenIdentifierIs ( "ascending" ) ) 
221+             if  ( TokenIsIdentifier ( "asc" )  ||  TokenIsIdentifier ( "ascending" ) ) 
222222            { 
223223                _textParser . NextToken ( ) ; 
224224            } 
225-             else  if  ( TokenIdentifierIs ( "desc" )  ||  TokenIdentifierIs ( "descending" ) ) 
225+             else  if  ( TokenIsIdentifier ( "desc" )  ||  TokenIsIdentifier ( "descending" ) ) 
226226            { 
227227                _textParser . NextToken ( ) ; 
228228                ascending  =  false ; 
@@ -337,19 +337,34 @@ private Expression ParseAndOperator()
337337        return  left ; 
338338    } 
339339
340-     // in operator for literals - example: "x in (1,2,3,4)" 
341-     // in operator to mimic contains - example: "x in @0", compare to @0.Contains(x) 
342-     // Adapted from ticket submitted by github user mlewis9548  
340+     // "in" / "not in" / "not_in" operator for literals - example: "x in (1,2,3,4)" 
341+     // "in" / "not in" / "not_in" operator to mimic contains - example: "x in @0", compare to @0.Contains(x) 
343342    private  Expression  ParseIn ( ) 
344343    { 
345344        Expression  left  =  ParseLogicalAndOrOperator ( ) ; 
346345        Expression  accumulate  =  left ; 
347346
348-         while  ( TokenIdentifierIs ( "in" ) ) 
347+         while  ( _textParser . TryGetToken ( [ "in" ,   "not_in" ,   "not" ] ,   [ TokenId . Exclamation ] ,   out   var   token ) ) 
349348        { 
350-             var  op  =  _textParser . CurrentToken ; 
349+             var  not  =  false ; 
350+             if  ( token . Text  ==  "not_in" ) 
351+             { 
352+                 not  =  true ; 
353+             } 
354+             else  if  ( token . Text  ==  "not"  ||  token . Id  ==  TokenId . Exclamation ) 
355+             { 
356+                 not  =  true ; 
357+ 
358+                 _textParser . NextToken ( ) ; 
359+ 
360+                 if  ( ! TokenIsIdentifier ( "in" ) ) 
361+                 { 
362+                     throw  ParseError ( token . Pos ,  Res . TokenExpected ,  "in" ) ; 
363+                 } 
364+             } 
351365
352366            _textParser . NextToken ( ) ; 
367+ 
353368            if  ( _textParser . CurrentToken . Id  ==  TokenId . OpenParen )  // literals (or other inline list) 
354369            { 
355370                while  ( _textParser . CurrentToken . Id  !=  TokenId . CloseParen ) 
@@ -364,18 +379,18 @@ private Expression ParseIn()
364379                    { 
365380                        if  ( right  is  ConstantExpression  constantExprRight ) 
366381                        { 
367-                             right  =  ParseEnumToConstantExpression ( op . Pos ,  left . Type ,  constantExprRight ) ; 
382+                             right  =  ParseEnumToConstantExpression ( token . Pos ,  left . Type ,  constantExprRight ) ; 
368383                        } 
369384                        else  if  ( _expressionHelper . TryUnwrapAsConstantExpression ( right ,  out  var  unwrappedConstantExprRight ) ) 
370385                        { 
371-                             right  =  ParseEnumToConstantExpression ( op . Pos ,  left . Type ,  unwrappedConstantExprRight ) ; 
386+                             right  =  ParseEnumToConstantExpression ( token . Pos ,  left . Type ,  unwrappedConstantExprRight ) ; 
372387                        } 
373388                    } 
374389
375390                    // else, check for direct type match 
376391                    else  if  ( left . Type  !=  right . Type ) 
377392                    { 
378-                         CheckAndPromoteOperands ( typeof ( IEqualitySignatures ) ,  TokenId . DoubleEqual ,  "==" ,  ref  left ,  ref  right ,  op . Pos ) ; 
393+                         CheckAndPromoteOperands ( typeof ( IEqualitySignatures ) ,  TokenId . DoubleEqual ,  "==" ,  ref  left ,  ref  right ,  token . Pos ) ; 
379394                    } 
380395
381396                    if  ( accumulate . Type  !=  typeof ( bool ) ) 
@@ -389,7 +404,7 @@ private Expression ParseIn()
389404
390405                    if  ( _textParser . CurrentToken . Id  ==  TokenId . End ) 
391406                    { 
392-                         throw  ParseError ( op . Pos ,  Res . CloseParenOrCommaExpected ) ; 
407+                         throw  ParseError ( token . Pos ,  Res . CloseParenOrCommaExpected ) ; 
393408                    } 
394409                } 
395410
@@ -413,7 +428,12 @@ private Expression ParseIn()
413428            } 
414429            else 
415430            { 
416-                 throw  ParseError ( op . Pos ,  Res . OpenParenOrIdentifierExpected ) ; 
431+                 throw  ParseError ( token . Pos ,  Res . OpenParenOrIdentifierExpected ) ; 
432+             } 
433+ 
434+             if  ( not ) 
435+             { 
436+                 accumulate  =  Expression . Not ( accumulate ) ; 
417437            } 
418438        } 
419439
@@ -759,7 +779,7 @@ private Expression ParseAdditive()
759779    private  Expression  ParseArithmetic ( ) 
760780    { 
761781        Expression  left  =  ParseUnary ( ) ; 
762-         while  ( _textParser . CurrentToken . Id  is  TokenId . Asterisk  or TokenId . Slash  or TokenId . Percent  ||  TokenIdentifierIs ( "mod" ) ) 
782+         while  ( _textParser . CurrentToken . Id  is  TokenId . Asterisk  or TokenId . Slash  or TokenId . Percent  ||  TokenIsIdentifier ( "mod" ) ) 
763783        { 
764784            Token  op  =  _textParser . CurrentToken ; 
765785            _textParser . NextToken ( ) ; 
@@ -787,11 +807,11 @@ private Expression ParseArithmetic()
787807    // -, !, not unary operators 
788808    private  Expression  ParseUnary ( ) 
789809    { 
790-         if  ( _textParser . CurrentToken . Id  ==  TokenId . Minus  ||  _textParser . CurrentToken . Id  ==  TokenId . Exclamation  ||  TokenIdentifierIs ( "not" ) ) 
810+         if  ( _textParser . CurrentToken . Id  ==  TokenId . Minus  ||  _textParser . CurrentToken . Id  ==  TokenId . Exclamation  ||  TokenIsIdentifier ( "not" ) ) 
791811        { 
792812            Token  op  =  _textParser . CurrentToken ; 
793813            _textParser . NextToken ( ) ; 
794-             if  ( op . Id  ==  TokenId . Minus  &&  ( _textParser . CurrentToken . Id  ==  TokenId . IntegerLiteral  ||   _textParser . CurrentToken . Id   ==   TokenId . RealLiteral ) ) 
814+             if  ( op . Id  ==  TokenId . Minus  &&  _textParser . CurrentToken . Id  is  TokenId . IntegerLiteral  or  TokenId . RealLiteral ) 
795815            { 
796816                _textParser . CurrentToken . Text  =  "-"  +  _textParser . CurrentToken . Text ; 
797817                _textParser . CurrentToken . Pos  =  op . Pos ; 
@@ -1445,7 +1465,7 @@ private Expression ParseNew()
14451465            if  ( ! arrayInitializer ) 
14461466            { 
14471467                string ?  propName ; 
1448-                 if  ( TokenIdentifierIs ( "as" ) ) 
1468+                 if  ( TokenIsIdentifier ( "as" ) ) 
14491469                { 
14501470                    _textParser . NextToken ( ) ; 
14511471                    propName  =  GetIdentifierAs ( ) ; 
@@ -2527,11 +2547,11 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef
25272547#endif
25282548    } 
25292549
2530-     private  bool  TokenIdentifierIs ( string  id ) 
2550+     private  bool  TokenIsIdentifier ( string  id ) 
25312551    { 
2532-         return  _textParser . CurrentToken . Id   ==   TokenId . Identifier   &&   string . Equals ( id ,   _textParser . CurrentToken . Text ,   StringComparison . OrdinalIgnoreCase ) ; 
2552+         return  _textParser . TokenIsIdentifier ( id ) ; 
25332553    } 
2534- 
2554+      
25352555    private  string  GetIdentifier ( ) 
25362556    { 
25372557        _textParser . ValidateToken ( TokenId . Identifier ,  Res . IdentifierExpected ) ; 
0 commit comments