@@ -220,11 +220,11 @@ internal IList<DynamicOrdering> ParseOrdering(bool forceThenBy = false)
220220 {
221221 var expr = ParseConditionalOperator ( ) ;
222222 var ascending = true ;
223- if ( TokenIdentifierIs ( "asc" ) || TokenIdentifierIs ( "ascending" ) )
223+ if ( TokenIsIdentifier ( "asc" ) || TokenIsIdentifier ( "ascending" ) )
224224 {
225225 _textParser . NextToken ( ) ;
226226 }
227- else if ( TokenIdentifierIs ( "desc" ) || TokenIdentifierIs ( "descending" ) )
227+ else if ( TokenIsIdentifier ( "desc" ) || TokenIsIdentifier ( "descending" ) )
228228 {
229229 _textParser . NextToken ( ) ;
230230 ascending = false ;
@@ -339,19 +339,34 @@ private Expression ParseAndOperator()
339339 return left ;
340340 }
341341
342- // in operator for literals - example: "x in (1,2,3,4)"
343- // in operator to mimic contains - example: "x in @0", compare to @0.Contains(x)
344- // Adapted from ticket submitted by github user mlewis9548
342+ // "in" / "not in" / "not_in" operator for literals - example: "x in (1,2,3,4)"
343+ // "in" / "not in" / "not_in" operator to mimic contains - example: "x in @0", compare to @0.Contains(x)
345344 private Expression ParseIn ( )
346345 {
347346 Expression left = ParseLogicalAndOrOperator ( ) ;
348347 Expression accumulate = left ;
349348
350- while ( TokenIdentifierIs ( "in" ) )
349+ while ( _textParser . TryGetToken ( [ "in" , "not_in" , "not" ] , [ TokenId . Exclamation ] , out var token ) )
351350 {
352- var op = _textParser . CurrentToken ;
351+ var not = false ;
352+ if ( token . Text == "not_in" )
353+ {
354+ not = true ;
355+ }
356+ else if ( token . Text == "not" || token . Id == TokenId . Exclamation )
357+ {
358+ not = true ;
359+
360+ _textParser . NextToken ( ) ;
361+
362+ if ( ! TokenIsIdentifier ( "in" ) )
363+ {
364+ throw ParseError ( token . Pos , Res . TokenExpected , "in" ) ;
365+ }
366+ }
353367
354368 _textParser . NextToken ( ) ;
369+
355370 if ( _textParser . CurrentToken . Id == TokenId . OpenParen ) // literals (or other inline list)
356371 {
357372 while ( _textParser . CurrentToken . Id != TokenId . CloseParen )
@@ -366,18 +381,18 @@ private Expression ParseIn()
366381 {
367382 if ( right is ConstantExpression constantExprRight )
368383 {
369- right = ParseEnumToConstantExpression ( op . Pos , left . Type , constantExprRight ) ;
384+ right = ParseEnumToConstantExpression ( token . Pos , left . Type , constantExprRight ) ;
370385 }
371386 else if ( _expressionHelper . TryUnwrapAsConstantExpression ( right , out var unwrappedConstantExprRight ) )
372387 {
373- right = ParseEnumToConstantExpression ( op . Pos , left . Type , unwrappedConstantExprRight ) ;
388+ right = ParseEnumToConstantExpression ( token . Pos , left . Type , unwrappedConstantExprRight ) ;
374389 }
375390 }
376391
377392 // else, check for direct type match
378393 else if ( left . Type != right . Type )
379394 {
380- CheckAndPromoteOperands ( typeof ( IEqualitySignatures ) , TokenId . DoubleEqual , "==" , ref left , ref right , op . Pos ) ;
395+ CheckAndPromoteOperands ( typeof ( IEqualitySignatures ) , TokenId . DoubleEqual , "==" , ref left , ref right , token . Pos ) ;
381396 }
382397
383398 if ( accumulate . Type != typeof ( bool ) )
@@ -391,7 +406,7 @@ private Expression ParseIn()
391406
392407 if ( _textParser . CurrentToken . Id == TokenId . End )
393408 {
394- throw ParseError ( op . Pos , Res . CloseParenOrCommaExpected ) ;
409+ throw ParseError ( token . Pos , Res . CloseParenOrCommaExpected ) ;
395410 }
396411 }
397412
@@ -415,7 +430,12 @@ private Expression ParseIn()
415430 }
416431 else
417432 {
418- throw ParseError ( op . Pos , Res . OpenParenOrIdentifierExpected ) ;
433+ throw ParseError ( token . Pos , Res . OpenParenOrIdentifierExpected ) ;
434+ }
435+
436+ if ( not )
437+ {
438+ accumulate = Expression . Not ( accumulate ) ;
419439 }
420440 }
421441
@@ -761,7 +781,7 @@ private Expression ParseAdditive()
761781 private Expression ParseArithmetic ( )
762782 {
763783 Expression left = ParseUnary ( ) ;
764- while ( _textParser . CurrentToken . Id is TokenId . Asterisk or TokenId . Slash or TokenId . Percent || TokenIdentifierIs ( "mod" ) )
784+ while ( _textParser . CurrentToken . Id is TokenId . Asterisk or TokenId . Slash or TokenId . Percent || TokenIsIdentifier ( "mod" ) )
765785 {
766786 Token op = _textParser . CurrentToken ;
767787 _textParser . NextToken ( ) ;
@@ -789,11 +809,11 @@ private Expression ParseArithmetic()
789809 // -, !, not unary operators
790810 private Expression ParseUnary ( )
791811 {
792- if ( _textParser . CurrentToken . Id == TokenId . Minus || _textParser . CurrentToken . Id == TokenId . Exclamation || TokenIdentifierIs ( "not" ) )
812+ if ( _textParser . CurrentToken . Id == TokenId . Minus || _textParser . CurrentToken . Id == TokenId . Exclamation || TokenIsIdentifier ( "not" ) )
793813 {
794814 Token op = _textParser . CurrentToken ;
795815 _textParser . NextToken ( ) ;
796- if ( op . Id == TokenId . Minus && ( _textParser . CurrentToken . Id == TokenId . IntegerLiteral || _textParser . CurrentToken . Id == TokenId . RealLiteral ) )
816+ if ( op . Id == TokenId . Minus && _textParser . CurrentToken . Id is TokenId . IntegerLiteral or TokenId . RealLiteral )
797817 {
798818 _textParser . CurrentToken . Text = "-" + _textParser . CurrentToken . Text ;
799819 _textParser . CurrentToken . Pos = op . Pos ;
@@ -1447,7 +1467,7 @@ private Expression ParseNew()
14471467 if ( ! arrayInitializer )
14481468 {
14491469 string ? propName ;
1450- if ( TokenIdentifierIs ( "as" ) )
1470+ if ( TokenIsIdentifier ( "as" ) )
14511471 {
14521472 _textParser . NextToken ( ) ;
14531473 propName = GetIdentifierAs ( ) ;
@@ -2531,11 +2551,11 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef
25312551#endif
25322552 }
25332553
2534- private bool TokenIdentifierIs ( string id )
2554+ private bool TokenIsIdentifier ( string id )
25352555 {
2536- return _textParser . CurrentToken . Id == TokenId . Identifier && string . Equals ( id , _textParser . CurrentToken . Text , StringComparison . OrdinalIgnoreCase ) ;
2556+ return _textParser . TokenIsIdentifier ( id ) ;
25372557 }
2538-
2558+
25392559 private string GetIdentifier ( )
25402560 {
25412561 _textParser . ValidateToken ( TokenId . Identifier , Res . IdentifierExpected ) ;
0 commit comments