use crate::error::{DbError, DbResult};
use crate::sdbql::ast::Expression;
use crate::sdbql::lexer::Token;
use crate::sdbql::parser::Parser;
use serde_json::Value;
impl Parser {
pub(super) fn parse_postfix_expression(&mut self) -> DbResult<Expression> {
let mut expr = self.parse_primary_expression()?;
loop {
match self.current_token() {
Token::Dot => {
expr = self.parse_field_access(expr)?;
}
Token::QuestionDot => {
expr = self.parse_optional_field_access(expr)?;
}
Token::LeftBracket => {
expr = self.parse_bracket_access(expr)?;
}
_ => break,
}
}
Ok(expr)
}
fn parse_field_access(&mut self, base: Expression) -> DbResult<Expression> {
self.advance();
if let Some(field_name) = self.get_field_name() {
self.advance();
Ok(Expression::FieldAccess(Box::new(base), field_name))
} else {
Err(DbError::ParseError(format!(
"Expected field name after '.', found {:?}. \
If the field name conflicts with a reserved word, \
use bracket notation: doc[\"field\"].",
self.current_token()
)))
}
}
fn parse_optional_field_access(&mut self, base: Expression) -> DbResult<Expression> {
self.advance();
if let Some(field_name) = self.get_field_name() {
self.advance();
Ok(Expression::OptionalFieldAccess(Box::new(base), field_name))
} else {
Err(DbError::ParseError(format!(
"Expected field name after '?.', found {:?}. \
If the field name conflicts with a reserved word, \
use bracket notation: doc[\"field\"].",
self.current_token()
)))
}
}
fn parse_bracket_access(&mut self, base: Expression) -> DbResult<Expression> {
self.advance();
if matches!(self.current_token(), Token::Star) {
return self.parse_array_spread_access(base);
}
let index_expr = self.parse_expression()?;
self.expect(Token::RightBracket)?;
Ok(match &index_expr {
Expression::Literal(Value::Number(_)) => {
Expression::ArrayAccess(Box::new(base), Box::new(index_expr))
}
Expression::Literal(Value::String(s)) => {
Expression::FieldAccess(Box::new(base), s.clone())
}
_ => {
Expression::DynamicFieldAccess(Box::new(base), Box::new(index_expr))
}
})
}
fn parse_array_spread_access(&mut self, base: Expression) -> DbResult<Expression> {
self.advance(); self.expect(Token::RightBracket)?;
let field_path = if matches!(self.current_token(), Token::Dot) {
let mut path = String::new();
while matches!(self.current_token(), Token::Dot) {
self.advance();
if let Some(name) = Self::token_to_field_name(self.current_token()) {
if !path.is_empty() {
path.push('.');
}
path.push_str(&name);
self.advance();
} else {
break;
}
}
if path.is_empty() {
None
} else {
Some(path)
}
} else {
None
};
Ok(Expression::ArraySpreadAccess(Box::new(base), field_path))
}
pub(super) fn parse_primary_expression(&mut self) -> DbResult<Expression> {
match self.current_token() {
Token::Identifier(ref name) => {
if name.eq_ignore_ascii_case("NONE") && self.is_none_quantifier() {
let parenthesized = matches!(self.peek_token(1), Token::LeftParen);
self.advance(); if parenthesized {
self.advance(); }
return self.parse_quantifier_expression_after_keyword("NONE", parenthesized);
}
self.parse_identifier_expression(name.clone())
}
Token::Any => self.parse_quantifier_expression("ANY"),
Token::Count => self.parse_keyword_as_function("COUNT"),
Token::Left => self.parse_keyword_as_function_no_window(
"LEFT",
"Unexpected token in expression: Left",
),
Token::Right => self.parse_keyword_as_function_no_window(
"RIGHT",
"Unexpected token in expression: Right",
),
Token::Like => self.parse_keyword_as_function_no_window(
"LIKE",
"Unexpected token in expression: Like",
),
Token::Replace => self.parse_keyword_as_function_no_window(
"REPLACE",
"Unexpected token in expression: Replace",
),
Token::Join => self.parse_keyword_as_function_no_window(
"JOIN",
"Unexpected token in expression: Join",
),
Token::Filter => self.parse_keyword_as_function_no_window(
"FILTER",
"Unexpected token in expression: Filter",
),
Token::Integer(n) => self.parse_integer(*n),
Token::Float(f) => self.parse_float(*f),
Token::String(s) => self.parse_string(s.clone()),
Token::True => self.parse_boolean(true),
Token::False => self.parse_boolean(false),
Token::Null => self.parse_null(),
Token::BindVar(name) => self.parse_bind_variable(name.clone()),
Token::LeftBrace => self.parse_object_expression(),
Token::LeftBracket => self.parse_array_expression(),
Token::LeftParen => self.parse_parenthesized_expression(),
Token::For | Token::Let => self.parse_unparenthesized_subquery(),
Token::Case => self.parse_case_expression(),
Token::TemplateString(parts) => {
let parts = parts.clone();
self.advance();
self.parse_template_string(parts)
}
_ => Err(DbError::ParseError(format!(
"Unexpected token in expression: {:?}",
self.current_token()
))),
}
}
fn is_none_quantifier(&self) -> bool {
if matches!(self.peek_token(1), Token::Identifier(_))
&& matches!(self.peek_token(2), Token::In)
{
return true;
}
matches!(self.peek_token(1), Token::LeftParen)
&& matches!(self.peek_token(2), Token::Identifier(_))
&& matches!(self.peek_token(3), Token::In)
}
fn parse_identifier_expression(&mut self, name: String) -> DbResult<Expression> {
if matches!(self.peek_token(1), Token::Arrow) {
return self.parse_lambda_expression();
}
self.advance();
if matches!(self.current_token(), Token::LeftParen) {
self.advance(); let args = self.parse_function_call_args()?;
if matches!(self.current_token(), Token::Over) {
return self.parse_window_function(name, args);
}
Ok(Expression::FunctionCall { name, args })
} else {
Ok(Expression::Variable(name))
}
}
fn parse_integer(&mut self, n: i64) -> DbResult<Expression> {
self.advance();
Ok(Expression::Literal(Value::Number(
serde_json::Number::from(n),
)))
}
fn parse_float(&mut self, f: f64) -> DbResult<Expression> {
self.advance();
Ok(Expression::Literal(Value::Number(
serde_json::Number::from_f64(f).unwrap(),
)))
}
fn parse_string(&mut self, s: String) -> DbResult<Expression> {
self.advance();
Ok(Expression::Literal(Value::String(s)))
}
fn parse_boolean(&mut self, value: bool) -> DbResult<Expression> {
self.advance();
Ok(Expression::Literal(Value::Bool(value)))
}
fn parse_null(&mut self) -> DbResult<Expression> {
self.advance();
Ok(Expression::Literal(Value::Null))
}
fn parse_bind_variable(&mut self, name: String) -> DbResult<Expression> {
self.advance();
Ok(Expression::BindVariable(name))
}
fn parse_parenthesized_expression(&mut self) -> DbResult<Expression> {
if self.is_lambda_params() {
return self.parse_lambda_expression();
}
self.advance();
if matches!(self.current_token(), Token::For | Token::Let) {
let subquery = self.parse_query(false)?;
self.expect(Token::RightParen)?;
Ok(Expression::Subquery(Box::new(subquery)))
} else {
let expr = self.parse_expression()?;
self.expect(Token::RightParen)?;
Ok(expr)
}
}
fn parse_unparenthesized_subquery(&mut self) -> DbResult<Expression> {
let subquery = self.parse_query(false)?;
Ok(Expression::Subquery(Box::new(subquery)))
}
}