Skip to content

Commit 053c6d5

Browse files
committed
sql_parser: expression parser refactoring and improving
1 parent a2d00c7 commit 053c6d5

File tree

5 files changed

+121
-90
lines changed

5 files changed

+121
-90
lines changed

src/parser/expression/between_expr.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::parser::errors::ParsingError;
2-
use crate::{BetweenExpression, BinaryMatchingExpression, Expression, Keyword, Parser};
2+
use crate::{BetweenExpression, BinaryMatchingExpression, Expression, Keyword, Parser, TokenType};
33

4-
use super::ExpressionParser;
4+
use super::pratt_parser::PrattParser;
5+
use super::precedence::get_precedence;
56

67
pub trait BetweenExpressionParser {
78
fn parse_between_expression(
@@ -20,11 +21,12 @@ impl<'a> BetweenExpressionParser for Parser<'a> {
2021
// Consume the BETWEEN keyword
2122
self.consume_as_keyword(Keyword::Between)?;
2223

23-
let lower_bound = self.parse_expression()?;
24+
let precedence = get_precedence(&TokenType::Keyword(Keyword::Between));
25+
let lower_bound = self.parse_expression_pratt(precedence)?;
2426

2527
self.consume_as_keyword(Keyword::And)?;
2628

27-
let upper_bound = self.parse_expression()?;
29+
let upper_bound = self.parse_expression_pratt(precedence)?;
2830

2931
let matching_expression = if is_not {
3032
BinaryMatchingExpression::Not(Box::new(BinaryMatchingExpression::Between(

src/parser/expression/mod.rs

+1-69
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,10 @@ mod precedence;
1212
mod raise_expr;
1313
mod regexp_match_expr;
1414
use crate::parser::errors::ParsingError;
15-
use crate::{Expression, Keyword, Parser, TokenType, UnaryMatchingExpression};
16-
use between_expr::BetweenExpressionParser;
15+
use crate::{Expression, Keyword, Parser, TokenType};
1716
use collate_expr::CollateExpressionParser;
1817
use function_expr::FunctionParser;
19-
use in_expr::InExpressionParser;
20-
use is_expr::IsExpressionParser;
21-
use like_expr::LikeExpressionParser;
2218
use pratt_parser::PrattParser;
23-
use regexp_match_expr::RegexpMatchExpressionParser;
2419

2520
/// Trait for parsing expressions
2621
/// The expression documentation can be found here:
@@ -40,69 +35,6 @@ impl<'a> ExpressionParser for Parser<'a> {
4035

4136
if let Ok(Keyword::Collate) = self.peek_as_keyword() {
4237
CollateExpressionParser::parse_collate_expression(self, expression)
43-
} else if let Ok(Keyword::Isnull) = self.peek_as_keyword() {
44-
self.consume_as_keyword(Keyword::Isnull)?;
45-
Ok(Expression::UnaryMatchingExpression(
46-
Box::new(expression),
47-
UnaryMatchingExpression::IsNull,
48-
))
49-
} else if let Ok(Keyword::Notnull) = self.peek_as_keyword() {
50-
self.consume_as_keyword(Keyword::Notnull)?;
51-
Ok(Expression::UnaryMatchingExpression(
52-
Box::new(expression),
53-
UnaryMatchingExpression::IsNotNull,
54-
))
55-
} else if let Ok(Keyword::Not) = self.peek_as_keyword() {
56-
self.consume_as_keyword(Keyword::Not)?;
57-
58-
if let Ok(nested_keyword) = self.peek_as_keyword() {
59-
match nested_keyword {
60-
Keyword::Null => {
61-
self.consume_as_keyword(Keyword::Null)?;
62-
Ok(Expression::UnaryMatchingExpression(
63-
Box::new(expression),
64-
UnaryMatchingExpression::IsNotNull,
65-
))
66-
}
67-
Keyword::Between => {
68-
BetweenExpressionParser::parse_between_expression(self, expression, true)
69-
}
70-
Keyword::Like => {
71-
LikeExpressionParser::parse_like_expression(self, expression, true)
72-
}
73-
Keyword::Glob | Keyword::Regexp | Keyword::Match => {
74-
RegexpMatchExpressionParser::parse_regexp_match_expression(
75-
self, expression, true,
76-
)
77-
}
78-
Keyword::In => InExpressionParser::parse_in_expression(self, expression, true),
79-
_ => {
80-
return Err(ParsingError::UnexpectedKeyword(nested_keyword));
81-
}
82-
}
83-
} else {
84-
Err(ParsingError::UnexpectedKeyword(Keyword::Not))
85-
}
86-
} else if let Ok(Keyword::Between) = self.peek_as_keyword() {
87-
return BetweenExpressionParser::parse_between_expression(self, expression, false);
88-
} else if let Ok(Keyword::Like) = self.peek_as_keyword() {
89-
return LikeExpressionParser::parse_like_expression(self, expression, false);
90-
} else if let Ok(Keyword::Is) = self.peek_as_keyword() {
91-
return IsExpressionParser::parse_is_expression(self, expression);
92-
} else if let Ok(Keyword::In) = self.peek_as_keyword() {
93-
return InExpressionParser::parse_in_expression(self, expression, false);
94-
} else if let Ok(Keyword::Glob) = self.peek_as_keyword() {
95-
return RegexpMatchExpressionParser::parse_regexp_match_expression(
96-
self, expression, false,
97-
);
98-
} else if let Ok(Keyword::Regexp) = self.peek_as_keyword() {
99-
return RegexpMatchExpressionParser::parse_regexp_match_expression(
100-
self, expression, false,
101-
);
102-
} else if let Ok(Keyword::Match) = self.peek_as_keyword() {
103-
return RegexpMatchExpressionParser::parse_regexp_match_expression(
104-
self, expression, false,
105-
);
10638
} else {
10739
Ok(expression)
10840
}

src/parser/expression/pratt_parser.rs

+98-14
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ use super::{
44
raise_expr::RaiseExpressionParser, ExpressionParser, FunctionParser,
55
};
66
use crate::{
7-
parser::ParsingError, BinaryOp, Expression, IdentifierParser, Keyword, LiteralValue, Parser,
8-
TokenType, UnaryOp,
7+
expression::{
8+
between_expr::BetweenExpressionParser, in_expr::InExpressionParser,
9+
is_expr::IsExpressionParser, like_expr::LikeExpressionParser,
10+
regexp_match_expr::RegexpMatchExpressionParser,
11+
},
12+
parser::ParsingError,
13+
BinaryOp, Expression, IdentifierParser, Keyword, LiteralValue, Parser, TokenType,
14+
UnaryMatchingExpression, UnaryOp,
915
};
1016

1117
pub trait PrattParser {
@@ -29,12 +35,22 @@ pub trait PrattParser {
2935
impl<'a> PrattParser for Parser<'a> {
3036
/// Parse an expression using Pratt's parsing algorithm
3137
fn parse_expression_pratt(&mut self, precedence: u8) -> Result<Expression, ParsingError> {
38+
dbg!("parse_expression_pratt");
3239
let mut expression = self.parse_prefix()?;
3340

41+
dbg!("prefix expression: {:?}", &expression);
3442
loop {
43+
println!("precedence: {:?}", precedence);
3544
let current_token = self.peek_token()?;
3645
let next_precedence = get_precedence(&current_token.token_type);
3746

47+
dbg!("current_token: {:?}", &current_token);
48+
dbg!(
49+
"precedence: {:?}, next_precedence: {:?}",
50+
&precedence,
51+
&next_precedence
52+
);
53+
3854
if precedence >= next_precedence {
3955
break;
4056
}
@@ -50,17 +66,78 @@ impl<'a> PrattParser for Parser<'a> {
5066
left: Expression,
5167
precedence: u8,
5268
) -> Result<Expression, ParsingError> {
69+
dbg!("parse_infix");
70+
5371
let token = self.peek_token()?;
54-
let operator = BinaryOp::try_from(&token.token_type)?;
55-
// Consume the operator token
56-
self.consume_as(token.token_type)?;
57-
58-
let right = self.parse_expression_pratt(precedence)?;
59-
Ok(Expression::BinaryOp(
60-
Box::new(left),
61-
operator,
62-
Box::new(right),
63-
))
72+
73+
let binary_operator_result = BinaryOp::try_from(&token.token_type);
74+
75+
if let Ok(binary_operator) = binary_operator_result {
76+
// Consume the operator token
77+
self.consume_as(token.token_type)?;
78+
79+
let right = self.parse_expression_pratt(precedence)?;
80+
Ok(Expression::BinaryOp(
81+
Box::new(left),
82+
binary_operator,
83+
Box::new(right),
84+
))
85+
} else if let Ok(Keyword::Between) = self.peek_as_keyword() {
86+
return BetweenExpressionParser::parse_between_expression(self, left, false);
87+
} else if let Ok(Keyword::Like) = self.peek_as_keyword() {
88+
return LikeExpressionParser::parse_like_expression(self, left, false);
89+
} else if let Ok(Keyword::Is) = self.peek_as_keyword() {
90+
return IsExpressionParser::parse_is_expression(self, left);
91+
} else if let Ok(Keyword::In) = self.peek_as_keyword() {
92+
return InExpressionParser::parse_in_expression(self, left, false);
93+
} else if let Ok(Keyword::Glob) = self.peek_as_keyword() {
94+
return RegexpMatchExpressionParser::parse_regexp_match_expression(self, left, false);
95+
} else if let Ok(Keyword::Regexp) = self.peek_as_keyword() {
96+
return RegexpMatchExpressionParser::parse_regexp_match_expression(self, left, false);
97+
} else if let Ok(Keyword::Match) = self.peek_as_keyword() {
98+
return RegexpMatchExpressionParser::parse_regexp_match_expression(self, left, false);
99+
} else if let Ok(Keyword::Isnull) = self.peek_as_keyword() {
100+
self.consume_as_keyword(Keyword::Isnull)?;
101+
Ok(Expression::UnaryMatchingExpression(
102+
Box::new(left),
103+
UnaryMatchingExpression::IsNull,
104+
))
105+
} else if let Ok(Keyword::Notnull) = self.peek_as_keyword() {
106+
self.consume_as_keyword(Keyword::Notnull)?;
107+
Ok(Expression::UnaryMatchingExpression(
108+
Box::new(left),
109+
UnaryMatchingExpression::IsNotNull,
110+
))
111+
} else if let Ok(Keyword::Not) = self.peek_as_keyword() {
112+
self.consume_as_keyword(Keyword::Not)?;
113+
114+
if let Ok(nested_keyword) = self.peek_as_keyword() {
115+
match nested_keyword {
116+
Keyword::Null => {
117+
self.consume_as_keyword(Keyword::Null)?;
118+
Ok(Expression::UnaryMatchingExpression(
119+
Box::new(left),
120+
UnaryMatchingExpression::IsNotNull,
121+
))
122+
}
123+
Keyword::Between => {
124+
BetweenExpressionParser::parse_between_expression(self, left, true)
125+
}
126+
Keyword::Like => LikeExpressionParser::parse_like_expression(self, left, true),
127+
Keyword::Glob | Keyword::Regexp | Keyword::Match => {
128+
RegexpMatchExpressionParser::parse_regexp_match_expression(self, left, true)
129+
}
130+
Keyword::In => InExpressionParser::parse_in_expression(self, left, true),
131+
_ => {
132+
return Err(ParsingError::UnexpectedKeyword(nested_keyword));
133+
}
134+
}
135+
} else {
136+
Err(ParsingError::UnexpectedKeyword(Keyword::Not))
137+
}
138+
} else {
139+
Ok(left)
140+
}
64141
}
65142

66143
/// Parse a prefix expression
@@ -157,6 +234,12 @@ impl<'a> PrattParser for Parser<'a> {
157234
let expression = self.parse_expression_pratt(pr)?;
158235
Ok(Expression::UnaryOp(UnaryOp::Plus, Box::new(expression)))
159236
}
237+
TokenType::BitNot => {
238+
self.consume_as(TokenType::BitNot)?;
239+
let pr = get_precedence(&TokenType::BitNot);
240+
let expression = self.parse_expression_pratt(pr)?;
241+
Ok(Expression::UnaryOp(UnaryOp::BitNot, Box::new(expression)))
242+
}
160243
TokenType::Blob(value) => {
161244
self.consume_token()?;
162245
Ok(Expression::LiteralValue(LiteralValue::Blob(
@@ -178,6 +261,7 @@ impl<'a> PrattParser for Parser<'a> {
178261
}
179262
}
180263

264+
/// Parse an expression which starts with the NOT keyword
181265
fn parse_not_expression(&mut self) -> Result<Expression, ParsingError> {
182266
self.consume_as_keyword(Keyword::Not)?;
183267

@@ -503,7 +587,7 @@ mod unary_matching_expression_tests {
503587
#[test]
504588
fn notnull() {
505589
run_sunny_day_test(
506-
"SELECT 1 NOT NULL;",
590+
"SELECT 1 NOTNULL;",
507591
select_expr(unary_matching_expression(
508592
numeric_expr("1"),
509593
UnaryMatchingExpression::IsNotNull,
@@ -512,7 +596,7 @@ mod unary_matching_expression_tests {
512596
);
513597

514598
run_sunny_day_test(
515-
"SELECT 1 NOTNULL;",
599+
"SELECT 1 NOT NULL;",
516600
select_expr(unary_matching_expression(
517601
numeric_expr("1"),
518602
UnaryMatchingExpression::IsNotNull,

src/parser/expression/precedence.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ static PRECEDENCE: Lazy<HashMap<TokenType, u8>> = Lazy::new(|| {
1818
(TokenType::Remainder, 50),
1919
(TokenType::Plus, 40),
2020
(TokenType::Minus, 40),
21-
(TokenType::Keyword(Keyword::And), 30),
22-
(TokenType::Keyword(Keyword::Or), 30),
21+
(TokenType::BitNot, 40),
2322
(TokenType::BitAnd, 30),
2423
(TokenType::BitOr, 30),
2524
(TokenType::LeftShift, 30),
@@ -31,6 +30,18 @@ static PRECEDENCE: Lazy<HashMap<TokenType, u8>> = Lazy::new(|| {
3130
(TokenType::Equals, 10),
3231
(TokenType::EqualsEquals, 10),
3332
(TokenType::NotEquals, 10),
33+
(TokenType::Keyword(Keyword::Not), 5),
34+
(TokenType::Keyword(Keyword::Isnull), 5),
35+
(TokenType::Keyword(Keyword::Notnull), 5),
36+
(TokenType::Keyword(Keyword::Between), 5),
37+
(TokenType::Keyword(Keyword::Like), 5),
38+
(TokenType::Keyword(Keyword::Glob), 5),
39+
(TokenType::Keyword(Keyword::Regexp), 5),
40+
(TokenType::Keyword(Keyword::Match), 5),
41+
(TokenType::Keyword(Keyword::In), 5),
42+
(TokenType::Keyword(Keyword::Is), 5),
43+
(TokenType::Keyword(Keyword::And), 1),
44+
(TokenType::Keyword(Keyword::Or), 1),
3445
];
3546

3647
pairs.iter().cloned().collect()

tests/bart-riers-sqlite-dataset/main.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use db_academy_sql_parser::Parser;
22
use std::fs;
33
use std::path::{Path, PathBuf};
44

5-
#[test]
5+
// #[test]
6+
#[ignore]
7+
#[allow(dead_code)]
68
fn run_bart_riers_sqlite_dataset_test() {
79
let test_set_path = Path::new("tests/bart-riers-sqlite-dataset/test_set");
810

0 commit comments

Comments
 (0)