@@ -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