Skip to content

Commit

Permalink
unit test for custom infix parser
Browse files Browse the repository at this point in the history
  • Loading branch information
andygrove committed Aug 17, 2022
1 parent c2e096e commit f518c30
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 3 deletions.
14 changes: 11 additions & 3 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,29 @@ pub trait Dialect: Debug + Any {
fn is_identifier_start(&self, ch: char) -> bool;
/// Determine if a character is a valid unquoted identifier character
fn is_identifier_part(&self, ch: char) -> bool;
/// Custom prefix parser
/// Dialect-specific prefix parser override
fn parse_prefix(&self, _parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
// return None to fall back to the default behavior
None
}
/// Custom infix parser
/// Dialect-specific infix parser override
fn parse_infix(
&self,
_parser: &mut Parser,
_expr: &Expr,
_precendence: u8,
) -> Option<Result<Expr, ParserError>> {
// return None to fall back to the default behavior
None
}
/// Custom statement parser
/// Dialect-specific precedence override
fn get_next_precedence(&self, _parser: &Parser) -> Option<Result<u8, ParserError>> {
// return None to fall back to the default behavior
None
}
/// Dialect-specific statement parser override
fn parse_statement(&self, _parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
// return None to fall back to the default behavior
None
}
}
Expand Down
53 changes: 53 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,11 @@ impl<'a> Parser<'a> {

/// Get the precedence of the next token
pub fn get_next_precedence(&self) -> Result<u8, ParserError> {
// allow the dialect to override precedence logic
if let Some(precedence) = self.dialect.get_next_precedence(self) {
return precedence;
}

let token = self.peek_token();
debug!("get_next_precedence() {:?}", token);
let token_0 = self.peek_nth_token(0);
Expand Down Expand Up @@ -4905,4 +4910,52 @@ mod tests {
assert_eq!(ast.to_string(), sql.to_string());
});
}

#[test]
fn custom_infix_parser() -> Result<(), ParserError> {
#[derive(Debug)]
struct MyDialect {}

impl Dialect for MyDialect {
fn is_identifier_start(&self, ch: char) -> bool {
// See https://www.postgresql.org/docs/11/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
// We don't yet support identifiers beginning with "letters with
// diacritical marks and non-Latin letters"
('a'..='z').contains(&ch) || ('A'..='Z').contains(&ch) || ch == '_'
}

fn is_identifier_part(&self, ch: char) -> bool {
('a'..='z').contains(&ch)
|| ('A'..='Z').contains(&ch)
|| ('0'..='9').contains(&ch)
|| ch == '$'
|| ch == '_'
}

fn parse_infix(
&self,
parser: &mut Parser,
expr: &Expr,
_precendence: u8,
) -> Option<Result<Expr, ParserError>> {
if parser.peek_token() == Token::Plus {
assert!(parser.consume_token(&Token::Plus));
Some(Ok(Expr::BinaryOp {
left: Box::new(expr.clone()),
op: BinaryOperator::Multiply, // translate Plus to Multiply
right: Box::new(parser.parse_expr().unwrap()),
}))
} else {
None
}
}
}

let dialect = MyDialect {};
let sql = "SELECT 1 + 2";
let ast = Parser::parse_sql(&dialect, sql)?;
let query = &ast[0];
assert_eq!("SELECT 1 * 2", &format!("{}", query));
Ok(())
}
}

0 comments on commit f518c30

Please sign in to comment.