@@ -173,13 +173,10 @@ impl Parser {
173
173
}
174
174
"CASE" => self . parse_case_expression ( ) ,
175
175
"CAST" => self . parse_cast_expression ( ) ,
176
- "NOT" => {
177
- let p = self . get_precedence ( & Token :: make_keyword ( "NOT" ) ) ?;
178
- Ok ( ASTNode :: SQLUnary {
179
- operator : SQLOperator :: Not ,
180
- expr : Box :: new ( self . parse_subexpr ( p) ?) ,
181
- } )
182
- }
176
+ "NOT" => Ok ( ASTNode :: SQLUnary {
177
+ operator : SQLOperator :: Not ,
178
+ expr : Box :: new ( self . parse_subexpr ( Self :: UNARY_NOT_PREC ) ?) ,
179
+ } ) ,
183
180
// Here `w` is a word, check if it's a part of a multi-part
184
181
// identifier, a function call, or a simple identifier:
185
182
_ => match self . peek_token ( ) {
@@ -213,15 +210,14 @@ impl Parser {
213
210
} , // End of Token::SQLWord
214
211
Token :: Mult => Ok ( ASTNode :: SQLWildcard ) ,
215
212
tok @ Token :: Minus | tok @ Token :: Plus => {
216
- let p = self . get_precedence ( & tok) ?;
217
213
let operator = if tok == Token :: Plus {
218
214
SQLOperator :: Plus
219
215
} else {
220
216
SQLOperator :: Minus
221
217
} ;
222
218
Ok ( ASTNode :: SQLUnary {
223
219
operator,
224
- expr : Box :: new ( self . parse_subexpr ( p ) ?) ,
220
+ expr : Box :: new ( self . parse_subexpr ( Self :: PLUS_MINUS_PREC ) ?) ,
225
221
} )
226
222
}
227
223
Token :: Number ( _) | Token :: SingleQuotedString ( _) | Token :: NationalStringLiteral ( _) => {
@@ -497,71 +493,80 @@ impl Parser {
497
493
} )
498
494
}
499
495
496
+ const UNARY_NOT_PREC : u8 = 15 ;
497
+ const PLUS_MINUS_PREC : u8 = 30 ;
498
+
500
499
/// Get the precedence of the next token
501
500
pub fn get_next_precedence ( & self ) -> Result < u8 , ParserError > {
502
501
if let Some ( token) = self . peek_token ( ) {
503
- self . get_precedence ( & token)
502
+ debug ! ( "get_precedence() {:?}" , token) ;
503
+
504
+ match & token {
505
+ Token :: SQLWord ( k) if k. keyword == "OR" => Ok ( 5 ) ,
506
+ Token :: SQLWord ( k) if k. keyword == "AND" => Ok ( 10 ) ,
507
+ Token :: SQLWord ( k) if k. keyword == "NOT" => match & self . peek_nth_token ( 1 ) {
508
+ // The precedence of NOT varies depending on keyword that
509
+ // follows it. If it is followed by IN, BETWEEN, or LIKE,
510
+ // it takes on the precedence of those tokens. Otherwise it
511
+ // takes on UNARY_NOT_PREC.
512
+ Some ( Token :: SQLWord ( k) ) if k. keyword == "IN" => Ok ( 20 ) ,
513
+ Some ( Token :: SQLWord ( k) ) if k. keyword == "BETWEEN" => Ok ( 20 ) ,
514
+ Some ( Token :: SQLWord ( k) ) if k. keyword == "LIKE" => Ok ( 20 ) ,
515
+ _ => Ok ( Self :: UNARY_NOT_PREC ) ,
516
+ } ,
517
+ Token :: SQLWord ( k) if k. keyword == "IS" => Ok ( 17 ) ,
518
+ Token :: SQLWord ( k) if k. keyword == "IN" => Ok ( 20 ) ,
519
+ Token :: SQLWord ( k) if k. keyword == "BETWEEN" => Ok ( 20 ) ,
520
+ Token :: SQLWord ( k) if k. keyword == "LIKE" => Ok ( 20 ) ,
521
+ Token :: Eq | Token :: Lt | Token :: LtEq | Token :: Neq | Token :: Gt | Token :: GtEq => {
522
+ Ok ( 20 )
523
+ }
524
+ Token :: Plus | Token :: Minus => Ok ( Self :: PLUS_MINUS_PREC ) ,
525
+ Token :: Mult | Token :: Div | Token :: Mod => Ok ( 40 ) ,
526
+ Token :: DoubleColon => Ok ( 50 ) ,
527
+ _ => Ok ( 0 ) ,
528
+ }
504
529
} else {
505
530
Ok ( 0 )
506
531
}
507
532
}
508
533
509
- /// Get the precedence of a token
510
- pub fn get_precedence ( & self , tok : & Token ) -> Result < u8 , ParserError > {
511
- debug ! ( "get_precedence() {:?}" , tok) ;
512
-
513
- match tok {
514
- Token :: SQLWord ( k) if k. keyword == "OR" => Ok ( 5 ) ,
515
- Token :: SQLWord ( k) if k. keyword == "AND" => Ok ( 10 ) ,
516
- Token :: SQLWord ( k) if k. keyword == "NOT" => Ok ( 15 ) ,
517
- Token :: SQLWord ( k) if k. keyword == "IS" => Ok ( 17 ) ,
518
- Token :: SQLWord ( k) if k. keyword == "IN" => Ok ( 20 ) ,
519
- Token :: SQLWord ( k) if k. keyword == "BETWEEN" => Ok ( 20 ) ,
520
- Token :: SQLWord ( k) if k. keyword == "LIKE" => Ok ( 20 ) ,
521
- Token :: Eq | Token :: Lt | Token :: LtEq | Token :: Neq | Token :: Gt | Token :: GtEq => Ok ( 20 ) ,
522
- Token :: Plus | Token :: Minus => Ok ( 30 ) ,
523
- Token :: Mult | Token :: Div | Token :: Mod => Ok ( 40 ) ,
524
- Token :: DoubleColon => Ok ( 50 ) ,
525
- _ => Ok ( 0 ) ,
526
- }
527
- }
528
-
529
534
/// Return first non-whitespace token that has not yet been processed
530
535
pub fn peek_token ( & self ) -> Option < Token > {
531
- if let Some ( n) = self . til_non_whitespace ( ) {
532
- self . token_at ( n)
533
- } else {
534
- None
535
- }
536
+ self . peek_nth_token ( 0 )
536
537
}
537
538
538
- /// Get the next token skipping whitespace and increment the token index
539
- pub fn next_token ( & mut self ) -> Option < Token > {
539
+ /// Return nth non-whitespace token that has not yet been processed
540
+ pub fn peek_nth_token ( & self , mut n : usize ) -> Option < Token > {
541
+ let mut index = self . index ;
540
542
loop {
541
- match self . next_token_no_skip ( ) {
543
+ match self . token_at ( index ) {
542
544
Some ( Token :: Whitespace ( _) ) => {
543
- continue ;
545
+ index += 1 ;
544
546
}
545
- token => {
546
- return token;
547
+ Some ( token) => {
548
+ if n == 0 {
549
+ return Some ( token) ;
550
+ }
551
+ index += 1 ;
552
+ n -= 1 ;
553
+ }
554
+ None => {
555
+ return None ;
547
556
}
548
557
}
549
558
}
550
559
}
551
560
552
- /// get the index for non whitepsace token
553
- fn til_non_whitespace ( & self ) -> Option < usize > {
554
- let mut index = self . index ;
561
+ /// Get the next token skipping whitespace and increment the token index
562
+ pub fn next_token ( & mut self ) -> Option < Token > {
555
563
loop {
556
- match self . token_at ( index ) {
564
+ match self . next_token_no_skip ( ) {
557
565
Some ( Token :: Whitespace ( _) ) => {
558
- index += 1 ;
559
- }
560
- Some ( _) => {
561
- return Some ( index) ;
566
+ continue ;
562
567
}
563
- None => {
564
- return None ;
568
+ token => {
569
+ return token ;
565
570
}
566
571
}
567
572
}
0 commit comments