Skip to content

Commit e5c0c42

Browse files
committed
Simplify parse_infix()
- ASTNode::SQLBinaryExpr is now constructed in one location - There's no duplicate calls to parse_in/parse_between - The list of tokens that correspond to operators is not duplicated in parse_infix / to_sql_operator - ...which made it easy to distinguish between errors that could be caused by invalid input and internal errors. I switched the latter to `panic!()`
1 parent d65274b commit e5c0c42

File tree

1 file changed

+61
-62
lines changed

1 file changed

+61
-62
lines changed

src/sqlparser.rs

+61-62
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,13 @@ impl Parser {
208208
Token::Mult => Ok(ASTNode::SQLWildcard),
209209
tok @ Token::Minus | tok @ Token::Plus => {
210210
let p = self.get_precedence(&tok)?;
211+
let operator = if tok == Token::Plus {
212+
SQLOperator::Plus
213+
} else {
214+
SQLOperator::Minus
215+
};
211216
Ok(ASTNode::SQLUnary {
212-
operator: self.to_sql_operator(&tok)?,
217+
operator,
213218
expr: Box::new(self.parse_subexpr(p)?),
214219
})
215220
}
@@ -377,59 +382,75 @@ impl Parser {
377382
})
378383
}
379384

380-
/// Parse an expression infix (typically an operator)
385+
/// Parse an operator following an expression
381386
pub fn parse_infix(&mut self, expr: ASTNode, precedence: u8) -> Result<ASTNode, ParserError> {
382387
debug!("parsing infix");
383-
match self.next_token() {
384-
Some(tok) => match tok {
385-
Token::SQLWord(ref k) if k.keyword == "IS" => {
386-
if self.parse_keywords(vec!["NULL"]) {
388+
let tok = self.next_token().unwrap(); // safe as EOF's precedence is the lowest
389+
390+
let regular_binary_operator = match tok {
391+
Token::Eq => Some(SQLOperator::Eq),
392+
Token::Neq => Some(SQLOperator::NotEq),
393+
Token::Gt => Some(SQLOperator::Gt),
394+
Token::GtEq => Some(SQLOperator::GtEq),
395+
Token::Lt => Some(SQLOperator::Lt),
396+
Token::LtEq => Some(SQLOperator::LtEq),
397+
Token::Plus => Some(SQLOperator::Plus),
398+
Token::Minus => Some(SQLOperator::Minus),
399+
Token::Mult => Some(SQLOperator::Multiply),
400+
Token::Mod => Some(SQLOperator::Modulus),
401+
Token::Div => Some(SQLOperator::Divide),
402+
Token::SQLWord(ref k) => match k.keyword.as_ref() {
403+
"AND" => Some(SQLOperator::And),
404+
"OR" => Some(SQLOperator::Or),
405+
"LIKE" => Some(SQLOperator::Like),
406+
"NOT" => {
407+
if self.parse_keyword("LIKE") {
408+
Some(SQLOperator::NotLike)
409+
} else {
410+
None
411+
}
412+
}
413+
_ => None,
414+
},
415+
_ => None,
416+
};
417+
418+
if let Some(op) = regular_binary_operator {
419+
Ok(ASTNode::SQLBinaryExpr {
420+
left: Box::new(expr),
421+
op,
422+
right: Box::new(self.parse_subexpr(precedence)?),
423+
})
424+
} else if let Token::SQLWord(ref k) = tok {
425+
match k.keyword.as_ref() {
426+
"IS" => {
427+
if self.parse_keyword("NULL") {
387428
Ok(ASTNode::SQLIsNull(Box::new(expr)))
388429
} else if self.parse_keywords(vec!["NOT", "NULL"]) {
389430
Ok(ASTNode::SQLIsNotNull(Box::new(expr)))
390431
} else {
391432
self.expected("NULL or NOT NULL after IS", self.peek_token())
392433
}
393434
}
394-
Token::SQLWord(ref k) if k.keyword == "NOT" => {
435+
"NOT" | "IN" | "BETWEEN" => {
436+
self.prev_token();
437+
let negated = self.parse_keyword("NOT");
395438
if self.parse_keyword("IN") {
396-
self.parse_in(expr, true)
439+
self.parse_in(expr, negated)
397440
} else if self.parse_keyword("BETWEEN") {
398-
self.parse_between(expr, true)
399-
} else if self.parse_keyword("LIKE") {
400-
Ok(ASTNode::SQLBinaryExpr {
401-
left: Box::new(expr),
402-
op: SQLOperator::NotLike,
403-
right: Box::new(self.parse_subexpr(precedence)?),
404-
})
441+
self.parse_between(expr, negated)
405442
} else {
406-
self.expected("BETWEEN, IN or LIKE after NOT", self.peek_token())
443+
panic!()
407444
}
408445
}
409-
Token::SQLWord(ref k) if k.keyword == "IN" => self.parse_in(expr, false),
410-
Token::SQLWord(ref k) if k.keyword == "BETWEEN" => self.parse_between(expr, false),
411-
Token::DoubleColon => self.parse_pg_cast(expr),
412-
Token::SQLWord(_)
413-
| Token::Eq
414-
| Token::Neq
415-
| Token::Gt
416-
| Token::GtEq
417-
| Token::Lt
418-
| Token::LtEq
419-
| Token::Plus
420-
| Token::Minus
421-
| Token::Mult
422-
| Token::Mod
423-
| Token::Div => Ok(ASTNode::SQLBinaryExpr {
424-
left: Box::new(expr),
425-
op: self.to_sql_operator(&tok)?,
426-
right: Box::new(self.parse_subexpr(precedence)?),
427-
}),
428-
_ => parser_err!(format!("No infix parser for token {:?}", tok)),
429-
},
430-
// This is not supposed to happen, because of the precedence check
431-
// in parse_subexpr.
432-
None => parser_err!("Unexpected EOF in parse_infix"),
446+
// Can only happen if `get_precedence` got out of sync with this function
447+
_ => panic!("No infix parser for token {:?}", tok),
448+
}
449+
} else if Token::DoubleColon == tok {
450+
self.parse_pg_cast(expr)
451+
} else {
452+
// Can only happen if `get_precedence` got out of sync with this function
453+
panic!("No infix parser for token {:?}", tok)
433454
}
434455
}
435456

@@ -475,28 +496,6 @@ impl Parser {
475496
})
476497
}
477498

478-
/// Convert a token operator to an AST operator
479-
pub fn to_sql_operator(&self, tok: &Token) -> Result<SQLOperator, ParserError> {
480-
match tok {
481-
Token::Eq => Ok(SQLOperator::Eq),
482-
Token::Neq => Ok(SQLOperator::NotEq),
483-
Token::Lt => Ok(SQLOperator::Lt),
484-
Token::LtEq => Ok(SQLOperator::LtEq),
485-
Token::Gt => Ok(SQLOperator::Gt),
486-
Token::GtEq => Ok(SQLOperator::GtEq),
487-
Token::Plus => Ok(SQLOperator::Plus),
488-
Token::Minus => Ok(SQLOperator::Minus),
489-
Token::Mult => Ok(SQLOperator::Multiply),
490-
Token::Div => Ok(SQLOperator::Divide),
491-
Token::Mod => Ok(SQLOperator::Modulus),
492-
Token::SQLWord(ref k) if k.keyword == "AND" => Ok(SQLOperator::And),
493-
Token::SQLWord(ref k) if k.keyword == "OR" => Ok(SQLOperator::Or),
494-
//Token::SQLWord(ref k) if k.keyword == "NOT" => Ok(SQLOperator::Not),
495-
Token::SQLWord(ref k) if k.keyword == "LIKE" => Ok(SQLOperator::Like),
496-
_ => parser_err!(format!("Unsupported SQL operator {:?}", tok)),
497-
}
498-
}
499-
500499
/// Get the precedence of the next token
501500
pub fn get_next_precedence(&self) -> Result<u8, ParserError> {
502501
if let Some(token) = self.peek_token() {

0 commit comments

Comments
 (0)