@@ -190,13 +190,10 @@ impl Parser {
190
190
}
191
191
"CASE" => self . parse_case_expression ( ) ,
192
192
"CAST" => self . parse_cast_expression ( ) ,
193
- "NOT" => {
194
- let p = self . get_precedence ( & Token :: make_keyword ( "NOT" ) ) ?;
195
- Ok ( ASTNode :: SQLUnary {
196
- operator : SQLOperator :: Not ,
197
- expr : Box :: new ( self . parse_subexpr ( p) ?) ,
198
- } )
199
- }
193
+ "NOT" => Ok ( ASTNode :: SQLUnary {
194
+ operator : SQLOperator :: Not ,
195
+ expr : Box :: new ( self . parse_subexpr ( Self :: UNARY_NOT_PREC ) ?) ,
196
+ } ) ,
200
197
// Here `w` is a word, check if it's a part of a multi-part
201
198
// identifier, a function call, or a simple identifier:
202
199
_ => match self . peek_token ( ) {
@@ -230,15 +227,14 @@ impl Parser {
230
227
} , // End of Token::SQLWord
231
228
Token :: Mult => Ok ( ASTNode :: SQLWildcard ) ,
232
229
tok @ Token :: Minus | tok @ Token :: Plus => {
233
- let p = self . get_precedence ( & tok) ?;
234
230
let operator = if tok == Token :: Plus {
235
231
SQLOperator :: Plus
236
232
} else {
237
233
SQLOperator :: Minus
238
234
} ;
239
235
Ok ( ASTNode :: SQLUnary {
240
236
operator,
241
- expr : Box :: new ( self . parse_subexpr ( p ) ?) ,
237
+ expr : Box :: new ( self . parse_subexpr ( Self :: PLUS_MINUS_PREC ) ?) ,
242
238
} )
243
239
}
244
240
Token :: Number ( _) | Token :: SingleQuotedString ( _) | Token :: NationalStringLiteral ( _) => {
@@ -510,10 +506,9 @@ impl Parser {
510
506
pub fn parse_between ( & mut self , expr : ASTNode , negated : bool ) -> Result < ASTNode , ParserError > {
511
507
// Stop parsing subexpressions for <low> and <high> on tokens with
512
508
// precedence lower than that of `BETWEEN`, such as `AND`, `IS`, etc.
513
- let prec = self . get_precedence ( & Token :: make_keyword ( "BETWEEN" ) ) ?;
514
- let low = self . parse_subexpr ( prec) ?;
509
+ let low = self . parse_subexpr ( Self :: BETWEEN_PREC ) ?;
515
510
self . expect_keyword ( "AND" ) ?;
516
- let high = self . parse_subexpr ( prec ) ?;
511
+ let high = self . parse_subexpr ( Self :: BETWEEN_PREC ) ?;
517
512
Ok ( ASTNode :: SQLBetween {
518
513
expr : Box :: new ( expr) ,
519
514
negated,
@@ -530,71 +525,81 @@ impl Parser {
530
525
} )
531
526
}
532
527
528
+ const UNARY_NOT_PREC : u8 = 15 ;
529
+ const BETWEEN_PREC : u8 = 20 ;
530
+ const PLUS_MINUS_PREC : u8 = 30 ;
531
+
533
532
/// Get the precedence of the next token
534
533
pub fn get_next_precedence ( & self ) -> Result < u8 , ParserError > {
535
534
if let Some ( token) = self . peek_token ( ) {
536
- self . get_precedence ( & token)
535
+ debug ! ( "get_precedence() {:?}" , token) ;
536
+
537
+ match & token {
538
+ Token :: SQLWord ( k) if k. keyword == "OR" => Ok ( 5 ) ,
539
+ Token :: SQLWord ( k) if k. keyword == "AND" => Ok ( 10 ) ,
540
+ Token :: SQLWord ( k) if k. keyword == "NOT" => match & self . peek_nth_token ( 1 ) {
541
+ // The precedence of NOT varies depending on keyword that
542
+ // follows it. If it is followed by IN, BETWEEN, or LIKE,
543
+ // it takes on the precedence of those tokens. Otherwise it
544
+ // takes on UNARY_NOT_PREC.
545
+ Some ( Token :: SQLWord ( k) ) if k. keyword == "IN" => Ok ( Self :: BETWEEN_PREC ) ,
546
+ Some ( Token :: SQLWord ( k) ) if k. keyword == "BETWEEN" => Ok ( Self :: BETWEEN_PREC ) ,
547
+ Some ( Token :: SQLWord ( k) ) if k. keyword == "LIKE" => Ok ( Self :: BETWEEN_PREC ) ,
548
+ _ => Ok ( Self :: UNARY_NOT_PREC ) ,
549
+ } ,
550
+ Token :: SQLWord ( k) if k. keyword == "IS" => Ok ( 17 ) ,
551
+ Token :: SQLWord ( k) if k. keyword == "IN" => Ok ( Self :: BETWEEN_PREC ) ,
552
+ Token :: SQLWord ( k) if k. keyword == "BETWEEN" => Ok ( Self :: BETWEEN_PREC ) ,
553
+ Token :: SQLWord ( k) if k. keyword == "LIKE" => Ok ( Self :: BETWEEN_PREC ) ,
554
+ Token :: Eq | Token :: Lt | Token :: LtEq | Token :: Neq | Token :: Gt | Token :: GtEq => {
555
+ Ok ( 20 )
556
+ }
557
+ Token :: Plus | Token :: Minus => Ok ( Self :: PLUS_MINUS_PREC ) ,
558
+ Token :: Mult | Token :: Div | Token :: Mod => Ok ( 40 ) ,
559
+ Token :: DoubleColon => Ok ( 50 ) ,
560
+ _ => Ok ( 0 ) ,
561
+ }
537
562
} else {
538
563
Ok ( 0 )
539
564
}
540
565
}
541
566
542
- /// Get the precedence of a token
543
- pub fn get_precedence ( & self , tok : & Token ) -> Result < u8 , ParserError > {
544
- debug ! ( "get_precedence() {:?}" , tok) ;
545
-
546
- match tok {
547
- Token :: SQLWord ( k) if k. keyword == "OR" => Ok ( 5 ) ,
548
- Token :: SQLWord ( k) if k. keyword == "AND" => Ok ( 10 ) ,
549
- Token :: SQLWord ( k) if k. keyword == "NOT" => Ok ( 15 ) ,
550
- Token :: SQLWord ( k) if k. keyword == "IS" => Ok ( 17 ) ,
551
- Token :: SQLWord ( k) if k. keyword == "IN" => Ok ( 20 ) ,
552
- Token :: SQLWord ( k) if k. keyword == "BETWEEN" => Ok ( 20 ) ,
553
- Token :: SQLWord ( k) if k. keyword == "LIKE" => Ok ( 20 ) ,
554
- Token :: Eq | Token :: Lt | Token :: LtEq | Token :: Neq | Token :: Gt | Token :: GtEq => Ok ( 20 ) ,
555
- Token :: Plus | Token :: Minus => Ok ( 30 ) ,
556
- Token :: Mult | Token :: Div | Token :: Mod => Ok ( 40 ) ,
557
- Token :: DoubleColon => Ok ( 50 ) ,
558
- _ => Ok ( 0 ) ,
559
- }
560
- }
561
-
562
567
/// Return first non-whitespace token that has not yet been processed
563
568
pub fn peek_token ( & self ) -> Option < Token > {
564
- if let Some ( n) = self . til_non_whitespace ( ) {
565
- self . token_at ( n)
566
- } else {
567
- None
568
- }
569
+ self . peek_nth_token ( 0 )
569
570
}
570
571
571
- /// Get the next token skipping whitespace and increment the token index
572
- pub fn next_token ( & mut self ) -> Option < Token > {
572
+ /// Return nth non-whitespace token that has not yet been processed
573
+ pub fn peek_nth_token ( & self , mut n : usize ) -> Option < Token > {
574
+ let mut index = self . index ;
573
575
loop {
574
- match self . next_token_no_skip ( ) {
576
+ match self . token_at ( index ) {
575
577
Some ( Token :: Whitespace ( _) ) => {
576
- continue ;
578
+ index += 1 ;
577
579
}
578
- token => {
579
- return token;
580
+ Some ( token) => {
581
+ if n == 0 {
582
+ return Some ( token) ;
583
+ }
584
+ index += 1 ;
585
+ n -= 1 ;
586
+ }
587
+ None => {
588
+ return None ;
580
589
}
581
590
}
582
591
}
583
592
}
584
593
585
- /// get the index for non whitepsace token
586
- fn til_non_whitespace ( & self ) -> Option < usize > {
587
- let mut index = self . index ;
594
+ /// Get the next token skipping whitespace and increment the token index
595
+ pub fn next_token ( & mut self ) -> Option < Token > {
588
596
loop {
589
- match self . token_at ( index ) {
597
+ match self . next_token_no_skip ( ) {
590
598
Some ( Token :: Whitespace ( _) ) => {
591
- index += 1 ;
592
- }
593
- Some ( _) => {
594
- return Some ( index) ;
599
+ continue ;
595
600
}
596
- None => {
597
- return None ;
601
+ token => {
602
+ return token ;
598
603
}
599
604
}
600
605
}
0 commit comments