use super::ast::*;
use super::parser::Parser;
use super::precedence::Precedence;
use super::token::{Token, TokenType};
impl Parser {
pub fn parse_expression(&mut self, precedence: Precedence) -> Option<Expression> {
let mut left = self.parse_prefix_expression()?;
while !self.peek_token_is(TokenType::Eof) && precedence < self.peek_precedence() {
if !self.is_infix_token() {
return Some(left);
}
self.next_token();
left = self.parse_infix_expression(left)?;
}
Some(left)
}
fn is_infix_token(&self) -> bool {
match self.peek_token.token_type {
TokenType::Operator => true,
TokenType::Keyword => {
let kw = self.peek_token.literal.to_uppercase();
matches!(
kw.as_str(),
"AND"
| "OR"
| "XOR"
| "LIKE"
| "ILIKE"
| "GLOB"
| "REGEXP"
| "RLIKE"
| "IS"
| "IN"
| "BETWEEN"
| "AS"
| "NOT"
)
}
TokenType::Punctuator => {
matches!(self.peek_token.literal.as_str(), "." | "(" | "[")
}
_ => false,
}
}
fn parse_prefix_expression(&mut self) -> Option<Expression> {
match self.cur_token.token_type {
TokenType::Identifier => Some(self.parse_identifier()),
TokenType::Integer => self.parse_integer_literal(),
TokenType::Float => self.parse_float_literal(),
TokenType::String => Some(self.parse_string_literal()),
TokenType::Parameter => self.parse_parameter(),
TokenType::Keyword => self.parse_keyword_expression(),
TokenType::Operator => self.parse_unary_expression(),
TokenType::Punctuator => self.parse_punctuator_expression(),
_ => {
self.add_error(format!(
"no prefix parse function for {:?} at {}",
self.cur_token.token_type, self.cur_token.position
));
None
}
}
}
fn parse_identifier(&self) -> Expression {
Expression::Identifier(Identifier::new(
self.cur_token.clone(),
self.cur_token.literal.clone(),
))
}
fn parse_integer_literal(&mut self) -> Option<Expression> {
match self.cur_token.literal.parse::<i64>() {
Ok(value) => Some(Expression::IntegerLiteral(IntegerLiteral {
token: self.cur_token.clone(),
value,
})),
Err(e) => {
self.add_error(format!(
"could not parse {} as integer: {}",
self.cur_token.literal, e
));
None
}
}
}
fn parse_float_literal(&mut self) -> Option<Expression> {
match self.cur_token.literal.parse::<f64>() {
Ok(value) => Some(Expression::FloatLiteral(FloatLiteral {
token: self.cur_token.clone(),
value,
})),
Err(e) => {
self.add_error(format!(
"could not parse {} as float: {}",
self.cur_token.literal, e
));
None
}
}
}
fn parse_string_literal(&self) -> Expression {
let literal = &self.cur_token.literal;
let value = if literal.len() >= 2 {
let inner = &literal[1..literal.len() - 1];
inner
.replace("\\n", "\n")
.replace("\\t", "\t")
.replace("\\r", "\r")
.replace("\\'", "'")
.replace("\\\\", "\\")
} else {
literal.clone()
};
let type_hint = if value.starts_with('{') && value.ends_with('}') {
Some("JSON".to_string())
} else {
None
};
Expression::StringLiteral(StringLiteral {
token: self.cur_token.clone(),
value,
type_hint,
})
}
fn parse_parameter(&mut self) -> Option<Expression> {
let name = self.cur_token.literal.clone();
let index = if name == "?" {
self.next_parameter_index()
} else if let Some(stripped) = name.strip_prefix('$') {
match stripped.parse::<usize>() {
Ok(idx) => idx,
Err(e) => {
self.add_error(format!("invalid parameter index: {}", e));
return None;
}
}
} else if name.starts_with(':') {
0
} else {
self.add_error(format!("invalid parameter format: {}", name));
return None;
};
Some(Expression::Parameter(Parameter {
token: self.cur_token.clone(),
name,
index,
}))
}
fn parse_keyword_expression(&mut self) -> Option<Expression> {
let keyword = self.cur_token.literal.to_uppercase();
match keyword.as_str() {
"TRUE" => Some(Expression::BooleanLiteral(BooleanLiteral {
token: self.cur_token.clone(),
value: true,
})),
"FALSE" => Some(Expression::BooleanLiteral(BooleanLiteral {
token: self.cur_token.clone(),
value: false,
})),
"NULL" => Some(Expression::NullLiteral(NullLiteral {
token: self.cur_token.clone(),
})),
"CASE" => self.parse_case_expression(),
"CAST" => self.parse_cast_expression(),
"EXTRACT" => self.parse_extract_expression(),
"EXISTS" => self.parse_exists_expression(),
"NOT" => self.parse_not_expression(),
"INTERVAL" => self.parse_interval_literal(),
"DEFAULT" => Some(Expression::Default(DefaultExpression {
token: self.cur_token.clone(),
})),
"TIMESTAMP" | "DATE" | "TIME" => {
if self.peek_token_is(TokenType::String) {
self.parse_typed_literal()
} else {
Some(Expression::Identifier(Identifier::new(
self.cur_token.clone(),
self.cur_token.literal.clone(),
)))
}
}
"LEFT" | "RIGHT" | "CHAR" | "FIRST" | "LAST" | "TRUNCATE" => {
if self.peek_token_is_punctuator("(") {
let ident = Expression::Identifier(Identifier::new(
self.cur_token.clone(),
self.cur_token.literal.clone(),
));
self.next_token(); self.parse_function_call(ident)
} else {
Some(Expression::Identifier(Identifier::new(
self.cur_token.clone(),
self.cur_token.literal.clone(),
)))
}
}
_ if !Self::is_reserved_keyword(&keyword) => Some(Expression::Identifier(
Identifier::new(self.cur_token.clone(), self.cur_token.literal.clone()),
)),
_ => {
self.add_error(format!(
"unexpected keyword: {} at {}",
keyword, self.cur_token.position
));
None
}
}
}
fn parse_unary_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
let operator = self.cur_token.literal.clone();
if operator == "*" {
if self.peek_token.is_eof()
|| self.peek_token.is_punctuator(",")
|| self.peek_token.is_punctuator(";")
|| self.peek_token.is_punctuator(")")
|| self.peek_token_is_keyword("FROM")
|| self.peek_token_is_keyword("WHERE")
|| self.peek_token_is_keyword("ORDER")
|| self.peek_token_is_keyword("GROUP")
|| self.peek_token_is_keyword("HAVING")
|| self.peek_token_is_keyword("LIMIT")
|| self.peek_token_is_keyword("UNION")
|| self.peek_token_is_keyword("INTERSECT")
|| self.peek_token_is_keyword("EXCEPT")
{
return Some(Expression::Star(StarExpression { token }));
}
}
self.next_token();
if operator == "-"
&& (self.cur_token_is(TokenType::Integer) || self.cur_token_is(TokenType::Float))
{
if self.cur_token_is(TokenType::Integer) {
if self.cur_token.literal == "9223372036854775808" {
return Some(Expression::IntegerLiteral(IntegerLiteral {
token: self.cur_token.clone(),
value: i64::MIN,
}));
}
if let Ok(value) = self.cur_token.literal.parse::<i64>() {
return Some(Expression::IntegerLiteral(IntegerLiteral {
token: self.cur_token.clone(),
value: -value,
}));
}
} else if let Ok(value) = self.cur_token.literal.parse::<f64>() {
return Some(Expression::FloatLiteral(FloatLiteral {
token: self.cur_token.clone(),
value: -value,
}));
}
}
let right = self.parse_expression(Precedence::Prefix)?;
Some(Expression::Prefix(PrefixExpression::new(
token,
operator,
Box::new(right),
)))
}
fn parse_punctuator_expression(&mut self) -> Option<Expression> {
match self.cur_token.literal.as_str() {
"(" => self.parse_grouped_expression(),
"*" => Some(Expression::Star(StarExpression {
token: self.cur_token.clone(),
})),
_ => {
self.add_error(format!(
"unexpected punctuator: {} at {}",
self.cur_token.literal, self.cur_token.position
));
None
}
}
}
fn parse_grouped_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
if self.peek_token_is_keyword("SELECT") {
self.next_token(); let subquery = self.parse_select_statement()?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after scalar subquery at {}",
self.cur_token.position
));
return None;
}
return Some(Expression::ScalarSubquery(ScalarSubquery {
token,
subquery: Box::new(subquery),
}));
}
self.next_token();
if self.cur_token_is_punctuator(")") {
return Some(Expression::Identifier(Identifier::new(
self.cur_token.clone(),
"()".to_string(),
)));
}
let first_expr = self.parse_expression(Precedence::Lowest)?;
if self.peek_token_is_punctuator(",") {
let mut expressions = vec![first_expr];
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
expressions.push(expr);
}
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!("expected ')' at {}", self.cur_token.position));
return None;
}
return Some(Expression::ExpressionList(ExpressionList {
token,
expressions,
}));
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!("expected ')' at {}", self.cur_token.position));
return None;
}
Some(first_expr)
}
fn parse_infix_expression(&mut self, left: Expression) -> Option<Expression> {
match self.cur_token.token_type {
TokenType::Operator => self.parse_binary_expression(left),
TokenType::Keyword => self.parse_keyword_infix(left),
TokenType::Punctuator => self.parse_punctuator_infix(left),
_ => {
self.add_error(format!(
"unexpected infix token: {:?} at {}",
self.cur_token.token_type, self.cur_token.position
));
None
}
}
}
fn parse_binary_expression(&mut self, left: Expression) -> Option<Expression> {
let token = self.cur_token.clone();
let operator = self.cur_token.literal.clone();
let precedence = self.cur_precedence();
self.next_token();
if self.cur_token_is_keyword("ALL")
|| self.cur_token_is_keyword("ANY")
|| self.cur_token_is_keyword("SOME")
{
return self.parse_all_any_expression(left, token, operator);
}
let right = self.parse_expression(precedence)?;
Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
operator,
Box::new(right),
)))
}
fn parse_all_any_expression(
&mut self,
left: Expression,
token: Token,
operator: String,
) -> Option<Expression> {
use super::ast::{AllAnyExpression, AllAnyType};
let all_any_type = if self.cur_token_is_keyword("ALL") {
AllAnyType::All
} else {
AllAnyType::Any };
self.next_token();
if !self.cur_token_is_punctuator("(") {
self.add_error(format!(
"expected '(' after {} at {}",
all_any_type, self.cur_token.position
));
return None;
}
self.next_token();
if !self.cur_token_is_keyword("SELECT") {
self.add_error(format!(
"expected SELECT in {} subquery at {}",
all_any_type, self.cur_token.position
));
return None;
}
let subquery = self.parse_select_statement()?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after {} subquery at {}",
all_any_type, self.cur_token.position
));
return None;
}
Some(Expression::AllAny(AllAnyExpression {
token,
left: Box::new(left),
operator,
all_any_type,
subquery: Box::new(subquery),
}))
}
fn parse_keyword_infix(&mut self, left: Expression) -> Option<Expression> {
let keyword = self.cur_token.literal.to_uppercase();
match keyword.as_str() {
"AND" | "OR" | "XOR" => {
let token = self.cur_token.clone();
let operator = keyword.clone();
let precedence = self.cur_precedence();
self.next_token();
let right = self.parse_expression(precedence)?;
Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
operator,
Box::new(right),
)))
}
"LIKE" | "ILIKE" | "GLOB" | "REGEXP" | "RLIKE" => {
self.parse_like_expression(left, keyword.clone(), false)
}
"IS" => self.parse_is_expression(left),
"IN" => self.parse_in_expression(left, false),
"BETWEEN" => self.parse_between_expression(left, false),
"AS" => self.parse_alias_expression(left),
"NOT" => {
if self.peek_token_is_keyword("IN") {
self.next_token(); self.parse_in_expression(left, true)
} else if self.peek_token_is_keyword("BETWEEN") {
self.next_token(); self.parse_between_expression(left, true)
} else if self.peek_token_is_keyword("LIKE") {
self.next_token(); self.parse_like_expression(left, "LIKE".to_string(), true)
} else if self.peek_token_is_keyword("ILIKE") {
self.next_token(); self.parse_like_expression(left, "ILIKE".to_string(), true)
} else if self.peek_token_is_keyword("GLOB") {
self.next_token(); self.parse_like_expression(left, "GLOB".to_string(), true)
} else if self.peek_token_is_keyword("REGEXP") {
self.next_token(); self.parse_like_expression(left, "REGEXP".to_string(), true)
} else if self.peek_token_is_keyword("RLIKE") {
self.next_token(); self.parse_like_expression(left, "RLIKE".to_string(), true)
} else {
let token = self.cur_token.clone();
self.next_token();
let right = self.parse_expression(Precedence::Not)?;
Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
"NOT".to_string(),
Box::new(right),
)))
}
}
_ => {
self.add_error(format!(
"unexpected infix keyword: {} at {}",
keyword, self.cur_token.position
));
None
}
}
}
fn parse_punctuator_infix(&mut self, left: Expression) -> Option<Expression> {
match self.cur_token.literal.as_str() {
"." => self.parse_qualified_identifier(left),
"(" => self.parse_function_call(left),
"[" => self.parse_index_expression(left),
"*" => {
let token = self.cur_token.clone();
let precedence = Precedence::Product;
self.next_token();
let right = self.parse_expression(precedence)?;
Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
"*".to_string(),
Box::new(right),
)))
}
_ => {
self.add_error(format!(
"unexpected infix punctuator: {} at {}",
self.cur_token.literal, self.cur_token.position
));
None
}
}
}
fn parse_qualified_identifier(&mut self, left: Expression) -> Option<Expression> {
let left_ident = match left {
Expression::Identifier(id) => id,
_ => {
self.add_error(format!(
"left side of '.' must be an identifier at {}",
self.cur_token.position
));
return None;
}
};
if self.peek_token_is_operator("*") {
self.next_token(); return Some(Expression::QualifiedStar(QualifiedStarExpression {
token: left_ident.token.clone(),
qualifier: left_ident.value,
}));
}
if !self.peek_token_is(TokenType::Identifier) && !self.peek_token_is(TokenType::Keyword) {
self.peek_error(TokenType::Identifier);
return None;
}
self.next_token();
Some(Expression::QualifiedIdentifier(QualifiedIdentifier {
token: left_ident.token.clone(),
qualifier: Box::new(left_ident),
name: Box::new(Identifier::new(
self.cur_token.clone(),
self.cur_token.literal.clone(),
)),
}))
}
fn parse_function_call(&mut self, left: Expression) -> Option<Expression> {
let left_ident = match left {
Expression::Identifier(id) => id,
_ => {
self.add_error(format!(
"left side of '(' must be an identifier at {}",
self.cur_token.position
));
return None;
}
};
let mut call = FunctionCall {
token: left_ident.token.clone(),
function: left_ident.value.to_uppercase(),
arguments: Vec::new(),
is_distinct: false,
order_by: Vec::new(),
filter: None,
};
if self.peek_token_is_punctuator(")") {
self.next_token();
if self.peek_token_is_keyword("FILTER") {
call.filter = self.parse_filter_clause();
}
if self.peek_token_is_keyword("OVER") {
return self.parse_window_expression(call);
}
return Some(Expression::FunctionCall(call));
}
if self.peek_token_is_operator("*") {
self.next_token();
call.arguments.push(Expression::Star(StarExpression {
token: self.cur_token.clone(),
}));
if self.peek_token_is_keyword("ORDER") {
self.parse_function_order_by(&mut call);
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!("expected ')' at {}", self.cur_token.position));
return None;
}
if self.peek_token_is_keyword("FILTER") {
call.filter = self.parse_filter_clause();
}
if self.peek_token_is_keyword("OVER") {
return self.parse_window_expression(call);
}
return Some(Expression::FunctionCall(call));
}
if self.peek_token_is_keyword("DISTINCT") {
self.next_token();
call.is_distinct = true;
}
self.next_token();
let first_arg_precedence = if call.function == "POSITION" {
Precedence::LessGreater } else {
Precedence::Lowest
};
if let Some(arg) = self.parse_expression(first_arg_precedence) {
call.arguments.push(arg);
}
if call.function == "POSITION" && self.peek_token_is_keyword("IN") {
self.next_token(); self.next_token();
if let Some(string_arg) = self.parse_expression(Precedence::Lowest) {
call.arguments.push(string_arg);
} else {
self.add_error(format!(
"expected expression after IN in POSITION at {}",
self.cur_token.position
));
return None;
}
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(arg) = self.parse_expression(Precedence::Lowest) {
call.arguments.push(arg);
} else {
self.add_error(format!(
"expected expression after ',' at {}",
self.cur_token.position
));
return None;
}
}
if self.peek_token_is_keyword("ORDER") {
self.parse_function_order_by(&mut call);
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!("expected ')' at {}", self.cur_token.position));
return None;
}
if self.peek_token_is_keyword("FILTER") {
call.filter = self.parse_filter_clause();
}
if self.peek_token_is_keyword("OVER") {
return self.parse_window_expression(call);
}
Some(Expression::FunctionCall(call))
}
fn parse_filter_clause(&mut self) -> Option<Box<Expression>> {
self.next_token();
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' after FILTER at {}",
self.cur_token.position
));
return None;
}
if !self.expect_keyword("WHERE") {
self.add_error(format!(
"expected WHERE after FILTER( at {}",
self.cur_token.position
));
return None;
}
self.next_token();
let condition = self.parse_expression(Precedence::Lowest)?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after FILTER condition at {}",
self.cur_token.position
));
return None;
}
Some(Box::new(condition))
}
fn parse_function_order_by(&mut self, call: &mut FunctionCall) {
self.next_token();
if !self.expect_keyword("BY") {
return;
}
self.next_token();
if let Some(order_expr) = self.parse_order_by_expression() {
call.order_by.push(order_expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(order_expr) = self.parse_order_by_expression() {
call.order_by.push(order_expr);
}
}
}
fn parse_window_expression(&mut self, function: FunctionCall) -> Option<Expression> {
self.next_token(); let token = self.cur_token.clone();
if self.peek_token_is(TokenType::Identifier) {
self.next_token(); let window_ref = self.cur_token.literal.clone();
return Some(Expression::Window(WindowExpression {
token,
function: Box::new(function),
window_ref: Some(window_ref),
partition_by: Vec::new(),
order_by: Vec::new(),
frame: None,
}));
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' or window name after OVER at {}",
self.cur_token.position
));
return None;
}
let mut partition_by = Vec::new();
let mut order_by = Vec::new();
let mut frame = None;
if self.peek_token_is_keyword("PARTITION") {
self.next_token(); if !self.expect_keyword("BY") {
return None;
}
self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
partition_by.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
partition_by.push(expr);
}
}
}
if self.peek_token_is_keyword("ORDER") {
self.next_token(); if !self.expect_keyword("BY") {
return None;
}
self.next_token();
if let Some(order_expr) = self.parse_order_by_expression() {
order_by.push(order_expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(order_expr) = self.parse_order_by_expression() {
order_by.push(order_expr);
}
}
}
if self.peek_token_is_keyword("ROWS") || self.peek_token_is_keyword("RANGE") {
frame = self.parse_window_frame();
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after window specification at {}",
self.cur_token.position
));
return None;
}
Some(Expression::Window(WindowExpression {
token,
function: Box::new(function),
window_ref: None,
partition_by,
order_by,
frame,
}))
}
fn parse_window_frame(&mut self) -> Option<WindowFrame> {
self.next_token();
let unit = if self.cur_token_is_keyword("ROWS") {
WindowFrameUnit::Rows
} else {
WindowFrameUnit::Range
};
self.next_token();
let (start, end) = if self.cur_token_is_keyword("BETWEEN") {
self.next_token();
let start = self.parse_window_frame_bound()?;
if !self.expect_keyword("AND") {
return None;
}
self.next_token();
let end = self.parse_window_frame_bound()?;
(start, Some(end))
} else {
let start = self.parse_window_frame_bound()?;
(start, None)
};
Some(WindowFrame { unit, start, end })
}
fn parse_window_frame_bound(&mut self) -> Option<WindowFrameBound> {
if self.cur_token_is_keyword("CURRENT") {
if !self.expect_keyword("ROW") {
return None;
}
Some(WindowFrameBound::CurrentRow)
} else if self.cur_token_is_keyword("UNBOUNDED") {
self.next_token();
if self.cur_token_is_keyword("PRECEDING") {
Some(WindowFrameBound::UnboundedPreceding)
} else if self.cur_token_is_keyword("FOLLOWING") {
Some(WindowFrameBound::UnboundedFollowing)
} else {
self.add_error(format!(
"expected PRECEDING or FOLLOWING after UNBOUNDED at {}",
self.cur_token.position
));
None
}
} else {
let expr = self.parse_expression(Precedence::Lowest)?;
self.next_token();
if self.cur_token_is_keyword("PRECEDING") {
Some(WindowFrameBound::Preceding(Box::new(expr)))
} else if self.cur_token_is_keyword("FOLLOWING") {
Some(WindowFrameBound::Following(Box::new(expr)))
} else {
self.add_error(format!(
"expected PRECEDING or FOLLOWING at {}",
self.cur_token.position
));
None
}
}
}
fn parse_index_expression(&mut self, left: Expression) -> Option<Expression> {
let token = self.cur_token.clone();
self.next_token();
let index = self.parse_expression(Precedence::Lowest)?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "]" {
self.add_error(format!("expected ']' at {}", self.cur_token.position));
return None;
}
Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
"[]".to_string(),
Box::new(index),
)))
}
fn parse_is_expression(&mut self, left: Expression) -> Option<Expression> {
let token = self.cur_token.clone();
let mut operator = "IS".to_string();
if self.peek_token_is_keyword("NOT") {
self.next_token();
operator = "IS NOT".to_string();
}
self.next_token();
if self.cur_token_is_keyword("NULL") {
return Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
operator,
Box::new(Expression::NullLiteral(NullLiteral {
token: self.cur_token.clone(),
})),
)));
}
if self.cur_token_is_keyword("TRUE") {
return Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
operator,
Box::new(Expression::BooleanLiteral(BooleanLiteral {
token: self.cur_token.clone(),
value: true,
})),
)));
}
if self.cur_token_is_keyword("FALSE") {
return Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
operator,
Box::new(Expression::BooleanLiteral(BooleanLiteral {
token: self.cur_token.clone(),
value: false,
})),
)));
}
if self.cur_token_is_keyword("DISTINCT") {
if !self.expect_keyword("FROM") {
return None;
}
self.next_token();
let right = self.parse_expression(Precedence::Equals)?;
let distinct_op = if operator == "IS" {
"IS DISTINCT FROM".to_string()
} else {
"IS NOT DISTINCT FROM".to_string()
};
return Some(Expression::Infix(InfixExpression::new(
token,
Box::new(left),
distinct_op,
Box::new(right),
)));
}
self.add_error(format!(
"expected NULL, TRUE, FALSE, or DISTINCT FROM after IS at {}",
self.cur_token.position
));
None
}
fn parse_in_expression(&mut self, left: Expression, not: bool) -> Option<Expression> {
let token = self.cur_token.clone();
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' after IN at {}",
self.cur_token.position
));
return None;
}
if self.peek_token_is_keyword("SELECT") {
self.next_token();
let subquery = self.parse_select_statement()?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after IN subquery at {}",
self.cur_token.position
));
return None;
}
return Some(Expression::In(InExpression {
token,
left: Box::new(left),
right: Box::new(Expression::ScalarSubquery(ScalarSubquery {
token: self.cur_token.clone(),
subquery: Box::new(subquery),
})),
not,
}));
}
let list_token = self.cur_token.clone();
self.next_token();
let mut expressions = Vec::new();
if self.cur_token_is_punctuator(")") {
return Some(Expression::In(InExpression {
token,
left: Box::new(left),
right: Box::new(Expression::ExpressionList(ExpressionList {
token: list_token,
expressions,
})),
not,
}));
}
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
expressions.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
expressions.push(expr);
}
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' in IN expression at {}",
self.cur_token.position
));
return None;
}
Some(Expression::In(InExpression {
token,
left: Box::new(left),
right: Box::new(Expression::ExpressionList(ExpressionList {
token: list_token,
expressions,
})),
not,
}))
}
fn parse_between_expression(&mut self, left: Expression, not: bool) -> Option<Expression> {
let token = self.cur_token.clone();
self.next_token();
let lower = self.parse_expression(Precedence::Equals)?;
if !self.expect_keyword("AND") {
return None;
}
self.next_token();
let upper = self.parse_expression(Precedence::Equals)?;
Some(Expression::Between(BetweenExpression {
token,
expr: Box::new(left),
lower: Box::new(lower),
upper: Box::new(upper),
not,
}))
}
fn parse_like_expression(
&mut self,
left: Expression,
op: String,
not: bool,
) -> Option<Expression> {
let token = self.cur_token.clone();
let operator = if not { format!("NOT {}", op) } else { op };
let precedence = self.cur_precedence();
self.next_token();
let pattern = self.parse_expression(precedence)?;
let escape = if self.peek_token_is_keyword("ESCAPE") {
self.next_token(); self.next_token(); Some(Box::new(self.parse_expression(Precedence::Lowest)?))
} else {
None
};
Some(Expression::Like(LikeExpression {
token,
left: Box::new(left),
pattern: Box::new(pattern),
operator,
escape,
}))
}
fn parse_alias_expression(&mut self, left: Expression) -> Option<Expression> {
let token = self.cur_token.clone();
if !self.peek_token_is(TokenType::Identifier) && !self.peek_token_is(TokenType::Keyword) {
self.peek_error(TokenType::Identifier);
return None;
}
self.next_token();
Some(Expression::Aliased(AliasedExpression {
token,
expression: Box::new(left),
alias: Identifier::new(self.cur_token.clone(), self.cur_token.literal.clone()),
}))
}
fn parse_case_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
let mut value = None;
let mut when_clauses = Vec::new();
let mut else_value = None;
if !self.peek_token_is_keyword("WHEN") {
self.next_token();
value = Some(Box::new(self.parse_expression(Precedence::Lowest)?));
}
while self.peek_token_is_keyword("WHEN") {
self.next_token(); let when_token = self.cur_token.clone();
self.next_token();
let condition = self.parse_expression(Precedence::Lowest)?;
if !self.expect_keyword("THEN") {
return None;
}
self.next_token();
let then_result = self.parse_expression(Precedence::Lowest)?;
when_clauses.push(WhenClause {
token: when_token,
condition,
then_result,
});
}
if when_clauses.is_empty() {
self.add_error(format!(
"expected at least one WHEN clause in CASE at {}",
self.cur_token.position
));
return None;
}
if self.peek_token_is_keyword("ELSE") {
self.next_token(); self.next_token();
else_value = Some(Box::new(self.parse_expression(Precedence::Lowest)?));
}
if !self.expect_keyword("END") {
return None;
}
Some(Expression::Case(CaseExpression {
token,
value,
when_clauses,
else_value,
}))
}
fn parse_cast_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' after CAST at {}",
self.cur_token.position
));
return None;
}
self.next_token();
let expr = self.parse_expression(Precedence::Equals)?;
if !self.expect_keyword("AS") {
return None;
}
if !self.peek_token_is(TokenType::Keyword) && !self.peek_token_is(TokenType::Identifier) {
self.add_error(format!(
"expected type name after AS in CAST at {}",
self.peek_token.position
));
return None;
}
self.next_token();
let type_name = self.cur_token.literal.clone();
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after type name in CAST at {}",
self.cur_token.position
));
return None;
}
Some(Expression::Cast(CastExpression {
token,
expr: Box::new(expr),
type_name,
}))
}
fn parse_extract_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' after EXTRACT at {}",
self.cur_token.position
));
return None;
}
if !self.peek_token_is(TokenType::Keyword) && !self.peek_token_is(TokenType::Identifier) {
self.add_error(format!(
"expected field name (YEAR, MONTH, DAY, etc.) in EXTRACT at {}",
self.peek_token.position
));
return None;
}
self.next_token();
let field = self.cur_token.literal.to_uppercase();
let valid_fields = [
"YEAR",
"MONTH",
"DAY",
"HOUR",
"MINUTE",
"SECOND",
"DOW",
"DAYOFWEEK",
"ISODOW",
"DOY",
"DAYOFYEAR",
"WEEK",
"ISOWEEK",
"QUARTER",
"EPOCH",
"MILLISECOND",
"MILLISECONDS",
"MICROSECOND",
"MICROSECONDS",
];
if !valid_fields.contains(&field.as_str()) {
self.add_error(format!(
"invalid EXTRACT field '{}'. Valid fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DOW, DOY, WEEK, QUARTER, EPOCH, etc.",
field
));
return None;
}
if !self.expect_keyword("FROM") {
return None;
}
self.next_token();
let source = self.parse_expression(Precedence::Lowest)?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after source in EXTRACT at {}",
self.cur_token.position
));
return None;
}
let basic_fields = ["YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND"];
if basic_fields.contains(&field.as_str()) {
Some(Expression::FunctionCall(FunctionCall {
token,
function: field,
arguments: vec![source],
is_distinct: false,
order_by: Vec::new(),
filter: None,
}))
} else {
let field_literal = Expression::StringLiteral(StringLiteral {
token: Token {
token_type: TokenType::String,
literal: field.to_lowercase(),
position: token.position,
error: None,
},
value: field.to_lowercase(),
type_hint: None,
});
Some(Expression::FunctionCall(FunctionCall {
token,
function: "EXTRACT".to_string(),
arguments: vec![field_literal, source],
is_distinct: false,
order_by: Vec::new(),
filter: None,
}))
}
}
fn parse_exists_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' after EXISTS at {}",
self.cur_token.position
));
return None;
}
self.next_token();
if !self.cur_token_is_keyword("SELECT") {
self.add_error(format!(
"expected SELECT in EXISTS subquery at {}",
self.cur_token.position
));
return None;
}
let subquery = self.parse_select_statement()?;
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after EXISTS subquery at {}",
self.cur_token.position
));
return None;
}
Some(Expression::Exists(ExistsExpression {
token,
subquery: Box::new(subquery),
}))
}
fn parse_not_expression(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
if self.peek_token_is_keyword("EXISTS") {
self.next_token();
let exists_expr = self.parse_exists_expression()?;
return Some(Expression::Prefix(PrefixExpression::new(
token,
"NOT".to_string(),
Box::new(exists_expr),
)));
}
self.next_token();
let right = self.parse_expression(Precedence::Not)?;
Some(Expression::Prefix(PrefixExpression::new(
token,
"NOT".to_string(),
Box::new(right),
)))
}
fn parse_interval_literal(&mut self) -> Option<Expression> {
let token = self.cur_token.clone();
if self.peek_token_is(TokenType::Integer) {
self.next_token();
let quantity = match self.cur_token.literal.parse::<i64>() {
Ok(q) => q,
Err(_) => {
self.add_error(format!(
"invalid interval quantity: {} at {}",
self.cur_token.literal, self.cur_token.position
));
return None;
}
};
self.next_token();
let unit_raw = self.cur_token.literal.to_uppercase();
let unit = match unit_raw.as_str() {
"SECOND" | "SECONDS" => "second",
"MINUTE" | "MINUTES" => "minute",
"HOUR" | "HOURS" => "hour",
"DAY" | "DAYS" => "day",
"WEEK" | "WEEKS" => "week",
"MONTH" | "MONTHS" => "month",
"YEAR" | "YEARS" => "year",
_ => {
self.add_error(format!(
"invalid interval unit: {} at {}. Expected SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, or YEAR",
self.cur_token.literal, self.cur_token.position
));
return None;
}
};
let value = format!("{} {}", quantity, unit);
Some(Expression::IntervalLiteral(IntervalLiteral {
token,
value,
quantity,
unit: unit.to_string(),
}))
} else if self.expect_peek(TokenType::String) {
let literal = &self.cur_token.literal;
let value = if literal.len() >= 2 {
literal[1..literal.len() - 1].to_string()
} else {
literal.clone()
};
let parts: Vec<&str> = value.split_whitespace().collect();
if parts.len() < 2 {
self.add_error(format!(
"invalid interval format: {} at {}",
value, self.cur_token.position
));
return None;
}
let quantity = match parts[0].parse::<i64>() {
Ok(q) => q,
Err(_) => {
self.add_error(format!(
"invalid interval quantity: {} at {}",
parts[0], self.cur_token.position
));
return None;
}
};
let unit = parts[1].to_lowercase().trim_end_matches('s').to_string();
Some(Expression::IntervalLiteral(IntervalLiteral {
token,
value,
quantity,
unit,
}))
} else {
None
}
}
fn parse_typed_literal(&mut self) -> Option<Expression> {
let type_hint = self.cur_token.literal.clone();
if !self.peek_token_is(TokenType::String) {
self.add_error(format!(
"expected string literal after {} at {}",
type_hint, self.cur_token.position
));
return None;
}
self.next_token();
let literal = &self.cur_token.literal;
let value = if literal.len() >= 2 && literal.starts_with('\'') && literal.ends_with('\'') {
literal[1..literal.len() - 1].to_string()
} else {
literal.clone()
};
Some(Expression::StringLiteral(StringLiteral {
token: self.cur_token.clone(),
value,
type_hint: Some(type_hint),
}))
}
pub fn parse_expression_list(&mut self) -> Vec<Expression> {
let mut list = Vec::new();
self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
list.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
list.push(expr);
}
}
list
}
pub fn parse_group_by_clause(&mut self) -> GroupByClause {
use crate::parser::ast::{GroupByClause, GroupByModifier};
self.next_token();
let modifier = if self.cur_token.token_type == TokenType::Identifier
|| self.cur_token.token_type == TokenType::Keyword
{
let upper = self.cur_token.literal.to_uppercase();
if upper == "ROLLUP" {
self.next_token(); if self.cur_token.literal == "(" {
self.next_token(); let columns = self.parse_group_by_columns();
return GroupByClause {
columns,
modifier: GroupByModifier::Rollup,
};
}
GroupByModifier::None
} else if upper == "CUBE" {
self.next_token(); if self.cur_token.literal == "(" {
self.next_token(); let columns = self.parse_group_by_columns();
return GroupByClause {
columns,
modifier: GroupByModifier::Cube,
};
}
GroupByModifier::None
} else if upper == "GROUPING" {
if self.peek_token.literal.to_uppercase() == "SETS" {
self.next_token(); self.next_token(); if self.cur_token.literal == "(" {
self.next_token(); let sets = self.parse_grouping_sets();
return GroupByClause {
columns: Vec::new(),
modifier: GroupByModifier::GroupingSets(sets),
};
}
}
GroupByModifier::None
} else {
GroupByModifier::None
}
} else {
GroupByModifier::None
};
let mut columns = Vec::new();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
columns.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
columns.push(expr);
}
}
GroupByClause { columns, modifier }
}
fn parse_group_by_columns(&mut self) -> Vec<Expression> {
let mut columns = Vec::new();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
columns.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
columns.push(expr);
}
}
if self.peek_token_is_punctuator(")") {
self.next_token();
}
columns
}
fn parse_grouping_sets(&mut self) -> Vec<Vec<Expression>> {
let mut sets = Vec::new();
if self.cur_token.literal == "(" {
sets.push(self.parse_single_grouping_set());
}
while self.cur_token.literal == "," {
self.next_token(); if self.cur_token.literal == "(" {
sets.push(self.parse_single_grouping_set());
}
}
sets
}
fn parse_single_grouping_set(&mut self) -> Vec<Expression> {
let mut columns = Vec::new();
self.next_token();
if self.cur_token.literal == ")" {
self.next_token(); return columns;
}
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
columns.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token(); if let Some(expr) = self.parse_expression(Precedence::Lowest) {
columns.push(expr);
}
}
if self.peek_token_is_punctuator(")") {
self.next_token(); }
self.next_token();
columns
}
pub fn parse_window_definitions(&mut self) -> Vec<WindowDefinition> {
let mut defs = Vec::new();
if let Some(def) = self.parse_single_window_definition() {
defs.push(def);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token(); if let Some(def) = self.parse_single_window_definition() {
defs.push(def);
}
}
defs
}
fn parse_single_window_definition(&mut self) -> Option<WindowDefinition> {
self.next_token();
let name = if self.cur_token_is(TokenType::Identifier) {
self.cur_token.literal.clone()
} else if self.cur_token_is(TokenType::Keyword) {
self.cur_token.literal.clone()
} else {
self.add_error(format!(
"expected window name at {}",
self.cur_token.position
));
return None;
};
if !self.expect_keyword("AS") {
return None;
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
self.add_error(format!(
"expected '(' after AS in window definition at {}",
self.cur_token.position
));
return None;
}
let mut partition_by = Vec::new();
let mut order_by = Vec::new();
let mut frame = None;
if self.peek_token_is_keyword("PARTITION") {
self.next_token(); if !self.expect_keyword("BY") {
return None;
}
self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
partition_by.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_expression(Precedence::Lowest) {
partition_by.push(expr);
}
}
}
if self.peek_token_is_keyword("ORDER") {
self.next_token(); if !self.expect_keyword("BY") {
return None;
}
self.next_token();
if let Some(order_expr) = self.parse_order_by_expression() {
order_by.push(order_expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(order_expr) = self.parse_order_by_expression() {
order_by.push(order_expr);
}
}
}
if self.peek_token_is_keyword("ROWS") || self.peek_token_is_keyword("RANGE") {
frame = self.parse_window_frame();
}
if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
self.add_error(format!(
"expected ')' after window specification at {}",
self.cur_token.position
));
return None;
}
Some(WindowDefinition {
name,
partition_by,
order_by,
frame,
})
}
pub fn parse_order_by_expression(&mut self) -> Option<OrderByExpression> {
let expression = self.parse_expression(Precedence::Lowest)?;
let mut ascending = true;
if self.peek_token_is_keyword("ASC") {
self.next_token();
ascending = true;
} else if self.peek_token_is_keyword("DESC") {
self.next_token();
ascending = false;
}
let nulls_first = if self.peek_token_is_keyword("NULLS") {
self.next_token(); if self.peek_token_is_keyword("FIRST") {
self.next_token(); Some(true)
} else if self.peek_token_is_keyword("LAST") {
self.next_token(); Some(false)
} else {
None
}
} else {
None
};
Some(OrderByExpression {
expression,
ascending,
nulls_first,
})
}
pub fn parse_order_by_expressions(&mut self) -> Vec<OrderByExpression> {
let mut list = Vec::new();
self.next_token();
if let Some(expr) = self.parse_order_by_expression() {
list.push(expr);
}
while self.peek_token_is_punctuator(",") {
self.next_token(); self.next_token();
if let Some(expr) = self.parse_order_by_expression() {
list.push(expr);
}
}
list
}
}
#[cfg(test)]
mod tests {
use super::*;
fn parse_expr(input: &str) -> Option<Expression> {
let mut parser = Parser::new(input);
parser.parse_expression(Precedence::Lowest)
}
#[test]
fn test_parse_identifier() {
let expr = parse_expr("users").unwrap();
match expr {
Expression::Identifier(id) => assert_eq!(id.value, "users"),
_ => panic!("expected Identifier"),
}
}
#[test]
fn test_parse_integer() {
let expr = parse_expr("42").unwrap();
match expr {
Expression::IntegerLiteral(lit) => assert_eq!(lit.value, 42),
_ => panic!("expected IntegerLiteral"),
}
}
#[test]
fn test_parse_float() {
let expr = parse_expr("3.5").unwrap();
match expr {
Expression::FloatLiteral(lit) => assert!((lit.value - 3.5).abs() < 0.001),
_ => panic!("expected FloatLiteral"),
}
}
#[test]
fn test_parse_string() {
let expr = parse_expr("'hello'").unwrap();
match expr {
Expression::StringLiteral(lit) => assert_eq!(lit.value, "hello"),
_ => panic!("expected StringLiteral"),
}
}
#[test]
fn test_parse_boolean() {
let expr = parse_expr("TRUE").unwrap();
match expr {
Expression::BooleanLiteral(lit) => assert!(lit.value),
_ => panic!("expected BooleanLiteral"),
}
let expr = parse_expr("FALSE").unwrap();
match expr {
Expression::BooleanLiteral(lit) => assert!(!lit.value),
_ => panic!("expected BooleanLiteral"),
}
}
#[test]
fn test_parse_null() {
let expr = parse_expr("NULL").unwrap();
match expr {
Expression::NullLiteral(_) => {}
_ => panic!("expected NullLiteral"),
}
}
#[test]
fn test_parse_infix() {
let expr = parse_expr("1 + 2").unwrap();
match expr {
Expression::Infix(infix) => {
assert_eq!(infix.operator, "+");
}
_ => panic!("expected InfixExpression"),
}
}
#[test]
fn test_parse_precedence() {
let expr = parse_expr("1 + 2 * 3").unwrap();
match expr {
Expression::Infix(infix) => {
assert_eq!(infix.operator, "+");
match infix.right.as_ref() {
Expression::Infix(right) => {
assert_eq!(right.operator, "*");
}
_ => panic!("expected nested InfixExpression"),
}
}
_ => panic!("expected InfixExpression"),
}
}
#[test]
fn test_parse_qualified_identifier() {
let expr = parse_expr("users.id").unwrap();
match expr {
Expression::QualifiedIdentifier(qi) => {
assert_eq!(qi.qualifier.value, "users");
assert_eq!(qi.name.value, "id");
}
_ => panic!("expected QualifiedIdentifier"),
}
}
#[test]
fn test_parse_function_call() {
let expr = parse_expr("COUNT(*)").unwrap();
match expr {
Expression::FunctionCall(fc) => {
assert_eq!(fc.function, "COUNT");
assert_eq!(fc.arguments.len(), 1);
}
_ => panic!("expected FunctionCall"),
}
}
#[test]
fn test_parse_count_star_with_filter() {
let expr = parse_expr("COUNT(*) FILTER (WHERE x = 1)").unwrap();
match expr {
Expression::FunctionCall(fc) => {
assert_eq!(fc.function, "COUNT");
assert_eq!(fc.arguments.len(), 1);
assert!(
fc.filter.is_some(),
"FILTER clause should be parsed for COUNT(*)"
);
}
_ => panic!("expected FunctionCall"),
}
}
#[test]
fn test_parse_function_call_with_multiple_args() {
let expr = parse_expr("STRING_AGG(name, '; ')").unwrap();
match expr {
Expression::FunctionCall(fc) => {
assert_eq!(fc.function, "STRING_AGG");
assert_eq!(
fc.arguments.len(),
2,
"Expected 2 arguments, got: {:?}",
fc.arguments
);
match &fc.arguments[0] {
Expression::Identifier(id) => assert_eq!(id.value, "name"),
other => panic!("Expected Identifier, got: {:?}", other),
}
match &fc.arguments[1] {
Expression::StringLiteral(lit) => assert_eq!(lit.value, "; "),
other => panic!("Expected StringLiteral, got: {:?}", other),
}
}
_ => panic!("expected FunctionCall"),
}
}
#[test]
fn test_parse_is_null() {
let expr = parse_expr("x IS NULL").unwrap();
match expr {
Expression::Infix(infix) => {
assert_eq!(infix.operator, "IS");
}
_ => panic!("expected InfixExpression"),
}
}
#[test]
fn test_parse_is_not_null() {
let expr = parse_expr("x IS NOT NULL").unwrap();
match expr {
Expression::Infix(infix) => {
assert_eq!(infix.operator, "IS NOT");
}
_ => panic!("expected InfixExpression"),
}
}
#[test]
fn test_parse_in() {
let expr = parse_expr("x IN (1, 2, 3)").unwrap();
match expr {
Expression::In(in_expr) => {
assert!(!in_expr.not);
}
_ => panic!("expected InExpression"),
}
}
#[test]
fn test_parse_not_in() {
let expr = parse_expr("x NOT IN (1, 2, 3)").unwrap();
match expr {
Expression::In(in_expr) => {
assert!(in_expr.not);
}
_ => panic!("expected InExpression"),
}
}
#[test]
fn test_parse_between() {
let expr = parse_expr("x BETWEEN 1 AND 10").unwrap();
match expr {
Expression::Between(between) => {
assert!(!between.not);
}
_ => panic!("expected BetweenExpression"),
}
}
#[test]
fn test_parse_case() {
let expr = parse_expr("CASE WHEN x = 1 THEN 'one' ELSE 'other' END").unwrap();
match expr {
Expression::Case(case) => {
assert!(case.value.is_none());
assert_eq!(case.when_clauses.len(), 1);
assert!(case.else_value.is_some());
}
_ => panic!("expected CaseExpression"),
}
}
#[test]
fn test_parse_cast() {
let expr = parse_expr("CAST(x AS INTEGER)").unwrap();
match expr {
Expression::Cast(cast) => {
assert_eq!(cast.type_name, "INTEGER");
}
_ => panic!("expected CastExpression"),
}
}
}