Skip to content

Commit 982a29b

Browse files
committed
Reorganize the Parser module
I mostly did this as an exercise to get a general feel of how the Parser implementation is organized. The basics here are that for every top level keyword in Parser::parse_statement I created a new module and moved the corresponding function to that module. Then I spent a few hours checking `find references` and any method that was in a single new module got moved there. Towards the end I started making some arbitary decisions on where functions referenced from multiple modules lived. Some of these seemed obvious, while some were certainly arbitrary. Most of the motivation here was that working on a 13,000 line file was causing my editor to be very not happy. After this happy, the largest module is now src/parser/select.rs which clocks in at 2142 lines. I should note, that the only visible changes are hopefully a few functions that had visibility flipped from private to public because I forgot about pub(crate) when I first started. Other than that, this is purely copy/paste moving of code to new module files.
1 parent d0fcc06 commit 982a29b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+13519
-13227
lines changed

src/parser/alter.rs

+494-158
Large diffs are not rendered by default.

src/parser/analyze.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use crate::parser::*;
2+
3+
impl<'a> Parser<'a> {
4+
pub fn parse_analyze(&mut self) -> Result<Statement, ParserError> {
5+
self.expect_keyword(Keyword::TABLE)?;
6+
let table_name = self.parse_object_name(false)?;
7+
let mut for_columns = false;
8+
let mut cache_metadata = false;
9+
let mut noscan = false;
10+
let mut partitions = None;
11+
let mut compute_statistics = false;
12+
let mut columns = vec![];
13+
loop {
14+
match self.parse_one_of_keywords(&[
15+
Keyword::PARTITION,
16+
Keyword::FOR,
17+
Keyword::CACHE,
18+
Keyword::NOSCAN,
19+
Keyword::COMPUTE,
20+
]) {
21+
Some(Keyword::PARTITION) => {
22+
self.expect_token(&Token::LParen)?;
23+
partitions = Some(self.parse_comma_separated(Parser::parse_expr)?);
24+
self.expect_token(&Token::RParen)?;
25+
}
26+
Some(Keyword::NOSCAN) => noscan = true,
27+
Some(Keyword::FOR) => {
28+
self.expect_keyword(Keyword::COLUMNS)?;
29+
30+
columns = self
31+
.maybe_parse(|parser| {
32+
parser.parse_comma_separated(|p| p.parse_identifier(false))
33+
})?
34+
.unwrap_or_default();
35+
for_columns = true
36+
}
37+
Some(Keyword::CACHE) => {
38+
self.expect_keyword(Keyword::METADATA)?;
39+
cache_metadata = true
40+
}
41+
Some(Keyword::COMPUTE) => {
42+
self.expect_keyword(Keyword::STATISTICS)?;
43+
compute_statistics = true
44+
}
45+
_ => break,
46+
}
47+
}
48+
49+
Ok(Statement::Analyze {
50+
table_name,
51+
for_columns,
52+
columns,
53+
partitions,
54+
cache_metadata,
55+
noscan,
56+
compute_statistics,
57+
})
58+
}
59+
}

src/parser/assert.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use crate::parser::*;
2+
3+
impl<'a> Parser<'a> {
4+
pub fn parse_assert(&mut self) -> Result<Statement, ParserError> {
5+
let condition = self.parse_expr()?;
6+
let message = if self.parse_keyword(Keyword::AS) {
7+
Some(self.parse_expr()?)
8+
} else {
9+
None
10+
};
11+
12+
Ok(Statement::Assert { condition, message })
13+
}
14+
}

src/parser/assignment.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::parser::*;
2+
3+
impl<'a> Parser<'a> {
4+
/// Parse a `var = expr` assignment, used in an UPDATE statement
5+
pub fn parse_assignment(&mut self) -> Result<Assignment, ParserError> {
6+
let target = self.parse_assignment_target()?;
7+
self.expect_token(&Token::Eq)?;
8+
let value = self.parse_expr()?;
9+
Ok(Assignment { target, value })
10+
}
11+
12+
/// Parse the left-hand side of an assignment, used in an UPDATE statement
13+
pub fn parse_assignment_target(&mut self) -> Result<AssignmentTarget, ParserError> {
14+
if self.consume_token(&Token::LParen) {
15+
let columns = self.parse_comma_separated(|p| p.parse_object_name(false))?;
16+
self.expect_token(&Token::RParen)?;
17+
Ok(AssignmentTarget::Tuple(columns))
18+
} else {
19+
let column = self.parse_object_name(false)?;
20+
Ok(AssignmentTarget::ColumnName(column))
21+
}
22+
}
23+
}

src/parser/attach.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::parser::*;
2+
3+
impl<'a> Parser<'a> {
4+
pub fn parse_attach_database(&mut self) -> Result<Statement, ParserError> {
5+
let database = self.parse_keyword(Keyword::DATABASE);
6+
let database_file_name = self.parse_expr()?;
7+
self.expect_keyword(Keyword::AS)?;
8+
let schema_name = self.parse_identifier(false)?;
9+
Ok(Statement::AttachDatabase {
10+
database,
11+
schema_name,
12+
database_file_name,
13+
})
14+
}
15+
}

src/parser/cache.rs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use crate::parser::*;
2+
3+
impl<'a> Parser<'a> {
4+
/// Parse a CACHE TABLE statement
5+
pub fn parse_cache_table(&mut self) -> Result<Statement, ParserError> {
6+
let (mut table_flag, mut options, mut has_as, mut query) = (None, vec![], false, None);
7+
if self.parse_keyword(Keyword::TABLE) {
8+
let table_name = self.parse_object_name(false)?;
9+
if self.peek_token().token != Token::EOF {
10+
if let Token::Word(word) = self.peek_token().token {
11+
if word.keyword == Keyword::OPTIONS {
12+
options = self.parse_options(Keyword::OPTIONS)?
13+
}
14+
};
15+
16+
if self.peek_token().token != Token::EOF {
17+
let (a, q) = self.parse_as_query()?;
18+
has_as = a;
19+
query = Some(q);
20+
}
21+
22+
Ok(Statement::Cache {
23+
table_flag,
24+
table_name,
25+
has_as,
26+
options,
27+
query,
28+
})
29+
} else {
30+
Ok(Statement::Cache {
31+
table_flag,
32+
table_name,
33+
has_as,
34+
options,
35+
query,
36+
})
37+
}
38+
} else {
39+
table_flag = Some(self.parse_object_name(false)?);
40+
if self.parse_keyword(Keyword::TABLE) {
41+
let table_name = self.parse_object_name(false)?;
42+
if self.peek_token() != Token::EOF {
43+
if let Token::Word(word) = self.peek_token().token {
44+
if word.keyword == Keyword::OPTIONS {
45+
options = self.parse_options(Keyword::OPTIONS)?
46+
}
47+
};
48+
49+
if self.peek_token() != Token::EOF {
50+
let (a, q) = self.parse_as_query()?;
51+
has_as = a;
52+
query = Some(q);
53+
}
54+
55+
Ok(Statement::Cache {
56+
table_flag,
57+
table_name,
58+
has_as,
59+
options,
60+
query,
61+
})
62+
} else {
63+
Ok(Statement::Cache {
64+
table_flag,
65+
table_name,
66+
has_as,
67+
options,
68+
query,
69+
})
70+
}
71+
} else {
72+
if self.peek_token() == Token::EOF {
73+
self.prev_token();
74+
}
75+
self.expected("a `TABLE` keyword", self.peek_token())
76+
}
77+
}
78+
}
79+
80+
/// Parse 'AS' before as query,such as `WITH XXX AS SELECT XXX` oer `CACHE TABLE AS SELECT XXX`
81+
pub fn parse_as_query(&mut self) -> Result<(bool, Box<Query>), ParserError> {
82+
match self.peek_token().token {
83+
Token::Word(word) => match word.keyword {
84+
Keyword::AS => {
85+
self.next_token();
86+
Ok((true, self.parse_query()?))
87+
}
88+
_ => Ok((false, self.parse_query()?)),
89+
},
90+
_ => self.expected("a QUERY statement", self.peek_token()),
91+
}
92+
}
93+
}

src/parser/call.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use crate::parser::*;
2+
3+
use crate::parser_err;
4+
5+
impl<'a> Parser<'a> {
6+
/// Parse a `CALL procedure_name(arg1, arg2, ...)`
7+
/// or `CALL procedure_name` statement
8+
pub fn parse_call(&mut self) -> Result<Statement, ParserError> {
9+
let object_name = self.parse_object_name(false)?;
10+
if self.peek_token().token == Token::LParen {
11+
match self.parse_function(object_name)? {
12+
Expr::Function(f) => Ok(Statement::Call(f)),
13+
other => parser_err!(
14+
format!("Expected a simple procedure call but found: {other}"),
15+
self.peek_token().span.start
16+
),
17+
}
18+
} else {
19+
Ok(Statement::Call(Function {
20+
name: object_name,
21+
parameters: FunctionArguments::None,
22+
args: FunctionArguments::None,
23+
over: None,
24+
filter: None,
25+
null_treatment: None,
26+
within_group: vec![],
27+
}))
28+
}
29+
}
30+
31+
pub fn parse_function_desc(&mut self) -> Result<FunctionDesc, ParserError> {
32+
let name = self.parse_object_name(false)?;
33+
34+
let args = if self.consume_token(&Token::LParen) {
35+
if self.consume_token(&Token::RParen) {
36+
None
37+
} else {
38+
let args = self.parse_comma_separated(Parser::parse_function_arg)?;
39+
self.expect_token(&Token::RParen)?;
40+
Some(args)
41+
}
42+
} else {
43+
None
44+
};
45+
46+
Ok(FunctionDesc { name, args })
47+
}
48+
49+
pub(crate) fn parse_function_arg(&mut self) -> Result<OperateFunctionArg, ParserError> {
50+
let mode = if self.parse_keyword(Keyword::IN) {
51+
Some(ArgMode::In)
52+
} else if self.parse_keyword(Keyword::OUT) {
53+
Some(ArgMode::Out)
54+
} else if self.parse_keyword(Keyword::INOUT) {
55+
Some(ArgMode::InOut)
56+
} else {
57+
None
58+
};
59+
60+
// parse: [ argname ] argtype
61+
let mut name = None;
62+
let mut data_type = self.parse_data_type()?;
63+
if let DataType::Custom(n, _) = &data_type {
64+
// the first token is actually a name
65+
name = Some(n.0[0].clone());
66+
data_type = self.parse_data_type()?;
67+
}
68+
69+
let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq)
70+
{
71+
Some(self.parse_expr()?)
72+
} else {
73+
None
74+
};
75+
Ok(OperateFunctionArg {
76+
mode,
77+
name,
78+
data_type,
79+
default_expr,
80+
})
81+
}
82+
}

src/parser/close.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::parser::*;
2+
3+
impl<'a> Parser<'a> {
4+
pub fn parse_close(&mut self) -> Result<Statement, ParserError> {
5+
let cursor = if self.parse_keyword(Keyword::ALL) {
6+
CloseCursor::All
7+
} else {
8+
let name = self.parse_identifier(false)?;
9+
10+
CloseCursor::Specific { name }
11+
};
12+
13+
Ok(Statement::Close { cursor })
14+
}
15+
}

0 commit comments

Comments
 (0)