mod auth_ddl;
mod config;
mod cte;
mod ddl;
mod dml;
mod error;
mod expr;
mod filter;
mod graph;
mod graph_commands;
mod hybrid;
mod index_ddl;
mod join;
mod kv;
pub mod limits;
mod migration;
mod path;
mod probabilistic_commands;
mod queue;
mod search_commands;
mod table;
mod timeseries;
mod tree;
mod vector;
#[cfg(test)]
mod json_literal_table;
#[cfg(test)]
mod property_tests;
#[cfg(test)]
mod tests;
pub use error::{ParseError, ParseErrorKind, SafeTokenDisplay};
pub use limits::ParserLimits;
use super::ast::{QueryExpr, QueryWithCte};
use super::lexer::{Lexer, Position, Spanned, Token};
use crate::storage::schema::Value;
use limits::DepthCounter;
pub struct Parser<'a> {
lexer: Lexer<'a>,
pub(crate) current: Spanned,
pub(crate) depth: DepthCounter,
pub(crate) placeholder_mode: PlaceholderMode,
pub(crate) question_count: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum PlaceholderMode {
None,
Dollar,
Question,
}
impl<'a> Parser<'a> {
pub fn new(input: &'a str) -> Result<Self, ParseError> {
Self::with_limits(input, ParserLimits::default())
}
pub fn with_limits(input: &'a str, limits: ParserLimits) -> Result<Self, ParseError> {
if input.len() > limits.max_input_bytes {
return Err(ParseError::input_too_large(
"max_input_bytes",
limits.max_input_bytes,
Position::new(1, 1, 0),
));
}
let mut lexer = Lexer::with_limits(input, limits);
let current = lexer.next_token()?;
Ok(Self {
lexer,
current,
depth: DepthCounter::new(limits.max_depth),
placeholder_mode: PlaceholderMode::None,
question_count: 0,
})
}
pub(crate) fn enter_depth(&mut self) -> Result<(), ParseError> {
self.depth.depth += 1;
if self.depth.depth > self.depth.max_depth {
return Err(ParseError::depth_limit(
"max_depth",
self.depth.max_depth,
self.position(),
));
}
Ok(())
}
pub(crate) fn exit_depth(&mut self) {
if self.depth.depth > 0 {
self.depth.depth -= 1;
}
}
pub fn position(&self) -> Position {
self.current.start
}
pub fn advance(&mut self) -> Result<Token, ParseError> {
let old = std::mem::replace(&mut self.current, self.lexer.next_token()?);
Ok(old.token)
}
pub fn peek(&self) -> &Token {
&self.current.token
}
pub fn peek_next(&mut self) -> Result<&Token, ParseError> {
Ok(&self.lexer.peek_token()?.token)
}
pub fn check(&self, expected: &Token) -> bool {
std::mem::discriminant(&self.current.token) == std::mem::discriminant(expected)
}
pub fn check_keyword(&self, keyword: &Token) -> bool {
self.check(keyword)
}
pub fn expect(&mut self, expected: Token) -> Result<Token, ParseError> {
if self.check(&expected) {
self.advance()
} else {
Err(ParseError::expected(
vec![&expected.to_string()],
&self.current.token,
self.position(),
))
}
}
pub fn expect_ident(&mut self) -> Result<String, ParseError> {
match &self.current.token {
Token::Ident(name) => {
let name = name.clone();
self.advance()?;
Ok(name)
}
other => Err(ParseError::expected(
vec!["identifier"],
other,
self.position(),
)),
}
}
pub fn expect_ident_or_keyword(&mut self) -> Result<String, ParseError> {
let name = match &self.current.token {
Token::Ident(name) => name.clone(),
Token::Contains => "CONTAINS".to_string(),
Token::Left => "LEFT".to_string(),
Token::Right => "RIGHT".to_string(),
Token::First => "FIRST".to_string(),
Token::Last => "LAST".to_string(),
Token::In => "IN".to_string(),
Token::By => "BY".to_string(),
other => other.to_string(),
};
match &self.current.token {
Token::Ident(_) => {
self.advance()?;
Ok(name)
}
Token::Contains
| Token::Left
| Token::Right
| Token::First
| Token::Last
| Token::In
| Token::By => {
self.advance()?;
Ok(name)
}
Token::Eof
| Token::LParen
| Token::RParen
| Token::LBracket
| Token::RBracket
| Token::Comma
| Token::Dot
| Token::Eq
| Token::Lt
| Token::Gt
| Token::Le
| Token::Ge
| Token::Arrow
| Token::ArrowLeft
| Token::Dash
| Token::Colon
| Token::Semi
| Token::Star
| Token::Plus
| Token::Slash => Err(ParseError::expected(
vec!["identifier or type name"],
&self.current.token,
self.position(),
)),
_ => {
self.advance()?;
Ok(name)
}
}
}
pub fn consume(&mut self, expected: &Token) -> Result<bool, ParseError> {
if self.check(expected) {
self.advance()?;
Ok(true)
} else {
Ok(false)
}
}
pub fn consume_ident_ci(&mut self, expected: &str) -> Result<bool, ParseError> {
match self.peek().clone() {
Token::Ident(name) if name.eq_ignore_ascii_case(expected) => {
self.advance()?;
Ok(true)
}
_ => Ok(false),
}
}
pub fn parse(&mut self) -> Result<QueryExpr, ParseError> {
let query = self.parse_frontend_statement()?.into_query_expr();
if !self.check(&Token::Eof) {
return Err(ParseError::new(
format!(
"Unexpected token after query: {}",
error::SafeTokenDisplay(&self.current.token)
),
self.position(),
));
}
Ok(query)
}
pub fn parse_query_expr(&mut self) -> Result<QueryExpr, ParseError> {
self.parse_frontend_statement()
.map(|statement| statement.into_query_expr())
}
pub fn parse_integer(&mut self) -> Result<i64, ParseError> {
match &self.current.token {
Token::Integer(n) => {
let n = *n;
self.advance()?;
Ok(n)
}
other => Err(ParseError::expected(
vec!["integer"],
other,
self.position(),
)),
}
}
pub fn parse_param_slot(&mut self, field: &'static str) -> Result<usize, ParseError> {
match self.peek().clone() {
Token::Dollar => {
self.advance()?;
let n = match *self.peek() {
Token::Integer(n) if n >= 1 => {
self.advance()?;
n as usize
}
_ => {
return Err(ParseError::new(
format!("expected `$N` (N >= 1) for {field} parameter"),
self.position(),
));
}
};
if self.placeholder_mode == PlaceholderMode::Question {
return Err(ParseError::new(
"cannot mix `?` and `$N` placeholders in one statement".to_string(),
self.position(),
));
}
self.placeholder_mode = PlaceholderMode::Dollar;
Ok(n - 1)
}
Token::Question => {
self.advance()?;
if self.placeholder_mode == PlaceholderMode::Dollar {
return Err(ParseError::new(
"cannot mix `?` and `$N` placeholders in one statement".to_string(),
self.position(),
));
}
self.placeholder_mode = PlaceholderMode::Question;
self.question_count += 1;
Ok(self.question_count - 1)
}
other => Err(ParseError::expected(
vec!["$N", "?"],
&other,
self.position(),
)),
}
}
pub fn parse_positive_integer(&mut self, field: &'static str) -> Result<i64, ParseError> {
let pos = self.position();
if matches!(self.current.token, Token::Minus | Token::Dash) {
return Err(ParseError::value_out_of_range(
field,
"must be a positive integer",
pos,
));
}
let raw = self.parse_integer()?;
if raw <= 0 {
return Err(ParseError::value_out_of_range(
field,
"must be a positive integer",
pos,
));
}
Ok(raw)
}
pub fn parse_float(&mut self) -> Result<f64, ParseError> {
let negate = if matches!(self.current.token, Token::Minus | Token::Dash) {
self.advance()?;
true
} else {
false
};
let value = match &self.current.token {
Token::Float(n) => {
let n = *n;
self.advance()?;
n
}
Token::Integer(n) => {
let n = *n as f64;
self.advance()?;
n
}
other => {
return Err(ParseError::expected(vec!["number"], other, self.position()));
}
};
Ok(if negate { -value } else { value })
}
pub fn parse_string(&mut self) -> Result<String, ParseError> {
match &self.current.token {
Token::String(s) => {
let s = s.clone();
self.advance()?;
Ok(s)
}
other => Err(ParseError::expected(vec!["string"], other, self.position())),
}
}
pub fn parse_value(&mut self) -> Result<Value, ParseError> {
self.parse_literal_value()
}
pub fn parse_value_list(&mut self) -> Result<Vec<Value>, ParseError> {
let mut values = Vec::new();
loop {
values.push(self.parse_value()?);
if !self.consume(&Token::Comma)? {
break;
}
}
Ok(values)
}
pub fn parse_expr_value(&mut self) -> Result<Value, ParseError> {
let expr = self.parse_expr()?;
super::sql_lowering::fold_expr_to_value(expr)
.map_err(|msg| ParseError::new(msg, self.position()))
}
}
pub fn parse(input: &str) -> Result<QueryWithCte, ParseError> {
let mut parser = Parser::new(input)?;
parser.parse_with_cte()
}