Add Parser::expected() for more succinct error handling

This commit is contained in:
Nickolay Ponomarev 2019-04-27 04:01:19 +03:00
parent c679c7a5b4
commit 787cd9a717

View file

@ -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()
))
} }
} }