mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-07 06:30:36 +00:00
Add Parser::expected()
for more succinct error handling
This commit is contained in:
parent
c679c7a5b4
commit
787cd9a717
1 changed files with 33 additions and 60 deletions
|
@ -28,6 +28,7 @@ pub enum ParserError {
|
||||||
ParserError(String),
|
ParserError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use `Parser::expected` instead, if possible
|
||||||
macro_rules! parser_err {
|
macro_rules! parser_err {
|
||||||
($MSG:expr) => {
|
($MSG:expr) => {
|
||||||
Err(ParserError::ParserError($MSG.to_string()))
|
Err(ParserError::ParserError($MSG.to_string()))
|
||||||
|
@ -69,10 +70,7 @@ impl Parser {
|
||||||
if parser.peek_token().is_none() {
|
if parser.peek_token().is_none() {
|
||||||
break;
|
break;
|
||||||
} else if expecting_statement_delimiter {
|
} else if expecting_statement_delimiter {
|
||||||
return parser_err!(format!(
|
return parser.expected("end of statement", parser.peek_token());
|
||||||
"Expected end of statement, found: {}",
|
|
||||||
parser.peek_token().unwrap().to_string()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let statement = parser.parse_statement()?;
|
let statement = parser.parse_statement()?;
|
||||||
|
@ -102,12 +100,12 @@ impl Parser {
|
||||||
w.to_string()
|
w.to_string()
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
unexpected => parser_err!(format!(
|
unexpected => self.expected(
|
||||||
"Unexpected {:?} at the beginning of a statement",
|
"a keyword at the beginning of a statement",
|
||||||
unexpected
|
Some(unexpected),
|
||||||
)),
|
),
|
||||||
},
|
},
|
||||||
_ => parser_err!("Unexpected end of file"),
|
None => self.expected("SQL statement", None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,10 +186,10 @@ impl Parser {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unexpected => {
|
unexpected => {
|
||||||
return parser_err!(format!(
|
return self.expected(
|
||||||
"Expected an identifier or a '*' after '.', got: {:?}",
|
"an identifier or a '*' after '.'",
|
||||||
unexpected
|
unexpected,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,10 +229,7 @@ impl Parser {
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
_ => parser_err!(format!(
|
_ => self.expected("an expression", Some(t)),
|
||||||
"Did not expect {:?} at the beginning of an expression",
|
|
||||||
t
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
None => parser_err!("Prefix parser expected a keyword but hit EOF"),
|
None => parser_err!("Prefix parser expected a keyword but hit EOF"),
|
||||||
}
|
}
|
||||||
|
@ -302,12 +297,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Token::RParen) => None,
|
Some(Token::RParen) => None,
|
||||||
unexpected => {
|
unexpected => return self.expected("'ROWS', 'RANGE', 'GROUPS', or ')'", unexpected),
|
||||||
return parser_err!(format!(
|
|
||||||
"Expected 'ROWS', 'RANGE', 'GROUPS', or ')', got {:?}",
|
|
||||||
unexpected
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(window_frame)
|
Ok(window_frame)
|
||||||
|
@ -335,10 +325,7 @@ impl Parser {
|
||||||
} else if self.parse_keyword("FOLLOWING") {
|
} else if self.parse_keyword("FOLLOWING") {
|
||||||
Ok(SQLWindowFrameBound::Following(rows))
|
Ok(SQLWindowFrameBound::Following(rows))
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected("PRECEDING or FOLLOWING", self.peek_token())
|
||||||
"Expected PRECEDING or FOLLOWING, found {:?}",
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,10 +388,7 @@ impl Parser {
|
||||||
} else if self.parse_keywords(vec!["NOT", "NULL"]) {
|
} else if self.parse_keywords(vec!["NOT", "NULL"]) {
|
||||||
Ok(ASTNode::SQLIsNotNull(Box::new(expr)))
|
Ok(ASTNode::SQLIsNotNull(Box::new(expr)))
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected("NULL or NOT NULL after IS", self.peek_token())
|
||||||
"Expected NULL or NOT NULL after IS, found {:?}",
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::SQLWord(ref k) if k.keyword == "NOT" => {
|
Token::SQLWord(ref k) if k.keyword == "NOT" => {
|
||||||
|
@ -419,10 +403,7 @@ impl Parser {
|
||||||
right: Box::new(self.parse_subexpr(precedence)?),
|
right: Box::new(self.parse_subexpr(precedence)?),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected("BETWEEN, IN or LIKE after NOT", self.peek_token())
|
||||||
"Expected BETWEEN, IN or LIKE after NOT, found {:?}",
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::SQLWord(ref k) if k.keyword == "IN" => self.parse_in(expr, false),
|
Token::SQLWord(ref k) if k.keyword == "IN" => self.parse_in(expr, false),
|
||||||
|
@ -629,6 +610,15 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Report unexpected token
|
||||||
|
fn expected<T>(&self, expected: &str, found: Option<Token>) -> Result<T, ParserError> {
|
||||||
|
parser_err!(format!(
|
||||||
|
"Expected {}, found: {}",
|
||||||
|
expected,
|
||||||
|
found.map_or("EOF".to_string(), |t| t.to_string())
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Look for an expected keyword and consume it if it exists
|
/// Look for an expected keyword and consume it if it exists
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn parse_keyword(&mut self, expected: &'static str) -> bool {
|
pub fn parse_keyword(&mut self, expected: &'static str) -> bool {
|
||||||
|
@ -666,11 +656,7 @@ impl Parser {
|
||||||
if self.parse_keyword(expected) {
|
if self.parse_keyword(expected) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected(expected, self.peek_token())
|
||||||
"Expected keyword {}, found {:?}",
|
|
||||||
expected,
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,11 +681,7 @@ impl Parser {
|
||||||
if self.consume_token(expected) {
|
if self.consume_token(expected) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected(&expected.to_string(), self.peek_token())
|
||||||
"Expected token {:?}, found {:?}",
|
|
||||||
expected,
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,10 +695,7 @@ impl Parser {
|
||||||
} else if self.parse_keyword("EXTERNAL") {
|
} else if self.parse_keyword("EXTERNAL") {
|
||||||
self.parse_create_external_table()
|
self.parse_create_external_table()
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected("TABLE or VIEW after CREATE", self.peek_token())
|
||||||
"Unexpected token after CREATE: {:?}",
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,7 +1137,7 @@ impl Parser {
|
||||||
Ok(SQLType::Custom(type_name))
|
Ok(SQLType::Custom(type_name))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
other => parser_err!(format!("Invalid data type: '{:?}'", other)),
|
other => self.expected("a data type name", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1218,10 +1197,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expect_identifier {
|
if expect_identifier {
|
||||||
parser_err!(format!(
|
self.expected("identifier", self.peek_token())
|
||||||
"Expecting identifier, found {:?}",
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(idents)
|
Ok(idents)
|
||||||
}
|
}
|
||||||
|
@ -1237,7 +1213,7 @@ impl Parser {
|
||||||
pub fn parse_identifier(&mut self) -> Result<SQLIdent, ParserError> {
|
pub fn parse_identifier(&mut self) -> Result<SQLIdent, ParserError> {
|
||||||
match self.next_token() {
|
match self.next_token() {
|
||||||
Some(Token::SQLWord(w)) => Ok(w.as_sql_ident()),
|
Some(Token::SQLWord(w)) => Ok(w.as_sql_ident()),
|
||||||
unexpected => parser_err!(format!("Expected identifier, found {:?}", unexpected)),
|
unexpected => self.expected("identifier", unexpected),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,7 +1344,7 @@ impl Parser {
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
SQLSetExpr::Query(Box::new(subquery))
|
SQLSetExpr::Query(Box::new(subquery))
|
||||||
} else {
|
} else {
|
||||||
parser_err!("Expected SELECT or a subquery in the query body!")?
|
return self.expected("SELECT or a subquery in the query body", self.peek_token());
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -1476,10 +1452,7 @@ impl Parser {
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(JoinConstraint::Using(attributes))
|
Ok(JoinConstraint::Using(attributes))
|
||||||
} else {
|
} else {
|
||||||
parser_err!(format!(
|
self.expected("ON, or USING after JOIN", self.peek_token())
|
||||||
"Unexpected token after JOIN: {:?}",
|
|
||||||
self.peek_token()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue