mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-27 04:54:21 +01:00
155 lines
4.2 KiB
Rust
155 lines
4.2 KiB
Rust
//! SQLite parser
|
|
|
|
pub mod ast;
|
|
pub mod parse {
|
|
#![expect(unused_braces)]
|
|
#![expect(clippy::if_same_then_else)]
|
|
#![expect(clippy::absurd_extreme_comparisons)] // FIXME
|
|
#![expect(clippy::needless_return)]
|
|
#![expect(clippy::upper_case_acronyms)]
|
|
#![expect(clippy::manual_range_patterns)]
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/parse.rs"));
|
|
}
|
|
|
|
use crate::dialect::Token;
|
|
use ast::{Cmd, ExplainKind, Name, Stmt};
|
|
|
|
/// Parser error
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum ParserError {
|
|
/// Syntax error
|
|
SyntaxError(String),
|
|
/// Unexpected EOF
|
|
UnexpectedEof,
|
|
/// Custom error
|
|
Custom(String),
|
|
}
|
|
|
|
impl std::fmt::Display for ParserError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
match self {
|
|
Self::SyntaxError(s) => {
|
|
write!(f, "near \"{s}\": syntax error")
|
|
}
|
|
Self::UnexpectedEof => f.write_str("unexpected end of input"),
|
|
Self::Custom(s) => f.write_str(s),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for ParserError {}
|
|
|
|
/// Custom error constructor
|
|
#[macro_export]
|
|
macro_rules! custom_err {
|
|
($msg:literal $(,)?) => {
|
|
$crate::parser::ParserError::Custom($msg.to_owned())
|
|
};
|
|
($err:expr $(,)?) => {
|
|
$crate::parser::ParserError::Custom(format!($err))
|
|
};
|
|
($fmt:expr, $($arg:tt)*) => {
|
|
$crate::parser::ParserError::Custom(format!($fmt, $($arg)*))
|
|
};
|
|
}
|
|
|
|
/// Parser context
|
|
pub struct Context<'input> {
|
|
input: &'input [u8],
|
|
explain: Option<ExplainKind>,
|
|
stmt: Option<Stmt>,
|
|
constraint_name: Option<Name>, // transient
|
|
module_arg: Option<(usize, usize)>, // Complete text of a module argument
|
|
module_args: Option<Vec<String>>, // CREATE VIRTUAL TABLE args
|
|
done: bool,
|
|
error: Option<ParserError>,
|
|
}
|
|
|
|
impl<'input> Context<'input> {
|
|
pub fn new(input: &'input [u8]) -> Self {
|
|
Context {
|
|
input,
|
|
explain: None,
|
|
stmt: None,
|
|
constraint_name: None,
|
|
module_arg: None,
|
|
module_args: None,
|
|
done: false,
|
|
error: None,
|
|
}
|
|
}
|
|
|
|
/// Consume parsed command
|
|
pub fn cmd(&mut self) -> Option<Cmd> {
|
|
if let Some(stmt) = self.stmt.take() {
|
|
match self.explain.take() {
|
|
Some(ExplainKind::Explain) => Some(Cmd::Explain(stmt)),
|
|
Some(ExplainKind::QueryPlan) => Some(Cmd::ExplainQueryPlan(stmt)),
|
|
None => Some(Cmd::Stmt(stmt)),
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn constraint_name(&mut self) -> Option<Name> {
|
|
self.constraint_name.take()
|
|
}
|
|
fn no_constraint_name(&self) -> bool {
|
|
self.constraint_name.is_none()
|
|
}
|
|
|
|
fn vtab_arg_init(&mut self) {
|
|
self.add_module_arg();
|
|
self.module_arg = None;
|
|
}
|
|
fn vtab_arg_extend(&mut self, any: Token) {
|
|
if let Some((_, ref mut n)) = self.module_arg {
|
|
*n = any.2
|
|
} else {
|
|
self.module_arg = Some((any.0, any.2))
|
|
}
|
|
}
|
|
fn add_module_arg(&mut self) {
|
|
if let Some((start, end)) = self.module_arg.take() {
|
|
if let Ok(arg) = std::str::from_utf8(&self.input[start..end]) {
|
|
self.module_args.get_or_insert(vec![]).push(arg.to_owned());
|
|
} // FIXME error handling
|
|
}
|
|
}
|
|
fn module_args(&mut self) -> Option<Vec<String>> {
|
|
self.add_module_arg();
|
|
self.module_args.take()
|
|
}
|
|
|
|
/// This routine is called after a single SQL statement has been parsed.
|
|
fn sqlite3_finish_coding(&mut self) {
|
|
self.done = true;
|
|
}
|
|
|
|
/// Return `true` if parser completes either successfully or with an error.
|
|
pub fn done(&self) -> bool {
|
|
self.done || self.error.is_some()
|
|
}
|
|
|
|
pub fn is_ok(&self) -> bool {
|
|
self.error.is_none()
|
|
}
|
|
|
|
/// Consume error generated by parser
|
|
pub fn error(&mut self) -> Option<ParserError> {
|
|
self.error.take()
|
|
}
|
|
|
|
pub fn reset(&mut self) {
|
|
self.explain = None;
|
|
self.stmt = None;
|
|
self.constraint_name = None;
|
|
self.module_arg = None;
|
|
self.module_args = None;
|
|
self.done = false;
|
|
self.error = None;
|
|
}
|
|
}
|