-
Notifications
You must be signed in to change notification settings - Fork 567
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
Showing
71 changed files
with
13,519 additions
and
13,227 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use crate::parser::*; | ||
|
||
impl<'a> Parser<'a> { | ||
pub fn parse_analyze(&mut self) -> Result<Statement, ParserError> { | ||
self.expect_keyword(Keyword::TABLE)?; | ||
let table_name = self.parse_object_name(false)?; | ||
let mut for_columns = false; | ||
let mut cache_metadata = false; | ||
let mut noscan = false; | ||
let mut partitions = None; | ||
let mut compute_statistics = false; | ||
let mut columns = vec![]; | ||
loop { | ||
match self.parse_one_of_keywords(&[ | ||
Keyword::PARTITION, | ||
Keyword::FOR, | ||
Keyword::CACHE, | ||
Keyword::NOSCAN, | ||
Keyword::COMPUTE, | ||
]) { | ||
Some(Keyword::PARTITION) => { | ||
self.expect_token(&Token::LParen)?; | ||
partitions = Some(self.parse_comma_separated(Parser::parse_expr)?); | ||
self.expect_token(&Token::RParen)?; | ||
} | ||
Some(Keyword::NOSCAN) => noscan = true, | ||
Some(Keyword::FOR) => { | ||
self.expect_keyword(Keyword::COLUMNS)?; | ||
|
||
columns = self | ||
.maybe_parse(|parser| { | ||
parser.parse_comma_separated(|p| p.parse_identifier(false)) | ||
})? | ||
.unwrap_or_default(); | ||
for_columns = true | ||
} | ||
Some(Keyword::CACHE) => { | ||
self.expect_keyword(Keyword::METADATA)?; | ||
cache_metadata = true | ||
} | ||
Some(Keyword::COMPUTE) => { | ||
self.expect_keyword(Keyword::STATISTICS)?; | ||
compute_statistics = true | ||
} | ||
_ => break, | ||
} | ||
} | ||
|
||
Ok(Statement::Analyze { | ||
table_name, | ||
for_columns, | ||
columns, | ||
partitions, | ||
cache_metadata, | ||
noscan, | ||
compute_statistics, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use crate::parser::*; | ||
|
||
impl<'a> Parser<'a> { | ||
pub fn parse_assert(&mut self) -> Result<Statement, ParserError> { | ||
let condition = self.parse_expr()?; | ||
let message = if self.parse_keyword(Keyword::AS) { | ||
Some(self.parse_expr()?) | ||
} else { | ||
None | ||
}; | ||
|
||
Ok(Statement::Assert { condition, message }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use crate::parser::*; | ||
|
||
impl<'a> Parser<'a> { | ||
/// Parse a `var = expr` assignment, used in an UPDATE statement | ||
pub fn parse_assignment(&mut self) -> Result<Assignment, ParserError> { | ||
let target = self.parse_assignment_target()?; | ||
self.expect_token(&Token::Eq)?; | ||
let value = self.parse_expr()?; | ||
Ok(Assignment { target, value }) | ||
} | ||
|
||
/// Parse the left-hand side of an assignment, used in an UPDATE statement | ||
pub fn parse_assignment_target(&mut self) -> Result<AssignmentTarget, ParserError> { | ||
if self.consume_token(&Token::LParen) { | ||
let columns = self.parse_comma_separated(|p| p.parse_object_name(false))?; | ||
self.expect_token(&Token::RParen)?; | ||
Ok(AssignmentTarget::Tuple(columns)) | ||
} else { | ||
let column = self.parse_object_name(false)?; | ||
Ok(AssignmentTarget::ColumnName(column)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use crate::parser::*; | ||
|
||
impl<'a> Parser<'a> { | ||
pub fn parse_attach_database(&mut self) -> Result<Statement, ParserError> { | ||
let database = self.parse_keyword(Keyword::DATABASE); | ||
let database_file_name = self.parse_expr()?; | ||
self.expect_keyword(Keyword::AS)?; | ||
let schema_name = self.parse_identifier(false)?; | ||
Ok(Statement::AttachDatabase { | ||
database, | ||
schema_name, | ||
database_file_name, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use crate::parser::*; | ||
|
||
impl<'a> Parser<'a> { | ||
/// Parse a CACHE TABLE statement | ||
pub fn parse_cache_table(&mut self) -> Result<Statement, ParserError> { | ||
let (mut table_flag, mut options, mut has_as, mut query) = (None, vec![], false, None); | ||
if self.parse_keyword(Keyword::TABLE) { | ||
let table_name = self.parse_object_name(false)?; | ||
if self.peek_token().token != Token::EOF { | ||
if let Token::Word(word) = self.peek_token().token { | ||
if word.keyword == Keyword::OPTIONS { | ||
options = self.parse_options(Keyword::OPTIONS)? | ||
} | ||
}; | ||
|
||
if self.peek_token().token != Token::EOF { | ||
let (a, q) = self.parse_as_query()?; | ||
has_as = a; | ||
query = Some(q); | ||
} | ||
|
||
Ok(Statement::Cache { | ||
table_flag, | ||
table_name, | ||
has_as, | ||
options, | ||
query, | ||
}) | ||
} else { | ||
Ok(Statement::Cache { | ||
table_flag, | ||
table_name, | ||
has_as, | ||
options, | ||
query, | ||
}) | ||
} | ||
} else { | ||
table_flag = Some(self.parse_object_name(false)?); | ||
if self.parse_keyword(Keyword::TABLE) { | ||
let table_name = self.parse_object_name(false)?; | ||
if self.peek_token() != Token::EOF { | ||
if let Token::Word(word) = self.peek_token().token { | ||
if word.keyword == Keyword::OPTIONS { | ||
options = self.parse_options(Keyword::OPTIONS)? | ||
} | ||
}; | ||
|
||
if self.peek_token() != Token::EOF { | ||
let (a, q) = self.parse_as_query()?; | ||
has_as = a; | ||
query = Some(q); | ||
} | ||
|
||
Ok(Statement::Cache { | ||
table_flag, | ||
table_name, | ||
has_as, | ||
options, | ||
query, | ||
}) | ||
} else { | ||
Ok(Statement::Cache { | ||
table_flag, | ||
table_name, | ||
has_as, | ||
options, | ||
query, | ||
}) | ||
} | ||
} else { | ||
if self.peek_token() == Token::EOF { | ||
self.prev_token(); | ||
} | ||
self.expected("a `TABLE` keyword", self.peek_token()) | ||
} | ||
} | ||
} | ||
|
||
/// Parse 'AS' before as query,such as `WITH XXX AS SELECT XXX` oer `CACHE TABLE AS SELECT XXX` | ||
pub fn parse_as_query(&mut self) -> Result<(bool, Box<Query>), ParserError> { | ||
match self.peek_token().token { | ||
Token::Word(word) => match word.keyword { | ||
Keyword::AS => { | ||
self.next_token(); | ||
Ok((true, self.parse_query()?)) | ||
} | ||
_ => Ok((false, self.parse_query()?)), | ||
}, | ||
_ => self.expected("a QUERY statement", self.peek_token()), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use crate::parser::*; | ||
|
||
use crate::parser_err; | ||
|
||
impl<'a> Parser<'a> { | ||
/// Parse a `CALL procedure_name(arg1, arg2, ...)` | ||
/// or `CALL procedure_name` statement | ||
pub fn parse_call(&mut self) -> Result<Statement, ParserError> { | ||
let object_name = self.parse_object_name(false)?; | ||
if self.peek_token().token == Token::LParen { | ||
match self.parse_function(object_name)? { | ||
Expr::Function(f) => Ok(Statement::Call(f)), | ||
other => parser_err!( | ||
format!("Expected a simple procedure call but found: {other}"), | ||
self.peek_token().span.start | ||
), | ||
} | ||
} else { | ||
Ok(Statement::Call(Function { | ||
name: object_name, | ||
parameters: FunctionArguments::None, | ||
args: FunctionArguments::None, | ||
over: None, | ||
filter: None, | ||
null_treatment: None, | ||
within_group: vec![], | ||
})) | ||
} | ||
} | ||
|
||
pub fn parse_function_desc(&mut self) -> Result<FunctionDesc, ParserError> { | ||
let name = self.parse_object_name(false)?; | ||
|
||
let args = if self.consume_token(&Token::LParen) { | ||
if self.consume_token(&Token::RParen) { | ||
None | ||
} else { | ||
let args = self.parse_comma_separated(Parser::parse_function_arg)?; | ||
self.expect_token(&Token::RParen)?; | ||
Some(args) | ||
} | ||
} else { | ||
None | ||
}; | ||
|
||
Ok(FunctionDesc { name, args }) | ||
} | ||
|
||
pub(crate) fn parse_function_arg(&mut self) -> Result<OperateFunctionArg, ParserError> { | ||
let mode = if self.parse_keyword(Keyword::IN) { | ||
Some(ArgMode::In) | ||
} else if self.parse_keyword(Keyword::OUT) { | ||
Some(ArgMode::Out) | ||
} else if self.parse_keyword(Keyword::INOUT) { | ||
Some(ArgMode::InOut) | ||
} else { | ||
None | ||
}; | ||
|
||
// parse: [ argname ] argtype | ||
let mut name = None; | ||
let mut data_type = self.parse_data_type()?; | ||
if let DataType::Custom(n, _) = &data_type { | ||
// the first token is actually a name | ||
name = Some(n.0[0].clone()); | ||
data_type = self.parse_data_type()?; | ||
} | ||
|
||
let default_expr = if self.parse_keyword(Keyword::DEFAULT) || self.consume_token(&Token::Eq) | ||
{ | ||
Some(self.parse_expr()?) | ||
} else { | ||
None | ||
}; | ||
Ok(OperateFunctionArg { | ||
mode, | ||
name, | ||
data_type, | ||
default_expr, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use crate::parser::*; | ||
|
||
impl<'a> Parser<'a> { | ||
pub fn parse_close(&mut self) -> Result<Statement, ParserError> { | ||
let cursor = if self.parse_keyword(Keyword::ALL) { | ||
CloseCursor::All | ||
} else { | ||
let name = self.parse_identifier(false)?; | ||
|
||
CloseCursor::Specific { name } | ||
}; | ||
|
||
Ok(Statement::Close { cursor }) | ||
} | ||
} |
Oops, something went wrong.