Skip to main content

sqlite3_parser/parser/
mod.rs

1//! SQLite parser
2use bumpalo::{collections::Vec, Bump};
3
4pub mod ast;
5pub mod parse {
6    #![expect(unused_braces)]
7    #![expect(clippy::absurd_extreme_comparisons)] // FIXME
8    #![expect(clippy::needless_return)]
9    #![expect(clippy::upper_case_acronyms)]
10    #![expect(clippy::manual_range_patterns)]
11
12    include!(concat!(env!("OUT_DIR"), "/parse.rs"));
13}
14mod stack;
15
16use crate::dialect::Token;
17use ast::{Cmd, ExplainKind, Name, Stmt};
18
19/// Parser error
20#[derive(Debug, PartialEq)]
21pub enum ParserError {
22    /// Syntax error
23    SyntaxError(String),
24    /// Unexpected EOF
25    UnexpectedEof,
26    /// Custom error
27    Custom(String),
28}
29
30impl std::fmt::Display for ParserError {
31    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
32        match self {
33            Self::SyntaxError(s) => {
34                write!(f, "near \"{s}\": syntax error")
35            }
36            Self::UnexpectedEof => f.write_str("unexpected end of input"),
37            Self::Custom(s) => f.write_str(s),
38        }
39    }
40}
41
42impl std::error::Error for ParserError {}
43
44/// Custom error constructor
45#[macro_export]
46macro_rules! custom_err {
47    ($msg:literal $(,)?) => {
48        $crate::parser::ParserError::Custom($msg.to_owned())
49    };
50    ($err:expr $(,)?) => {
51        $crate::parser::ParserError::Custom(format!($err))
52    };
53    ($fmt:expr, $($arg:tt)*) => {
54        $crate::parser::ParserError::Custom(format!($fmt, $($arg)*))
55    };
56}
57
58/// Parser context
59pub struct Context<'input> {
60    bump: &'input Bump,
61    input: &'input [u8],
62    explain: Option<ExplainKind>,
63    stmt: Option<Stmt<'input>>,
64    constraint_name: Option<Name<'input>>,         // transient
65    module_arg: Option<(usize, usize)>,            // Complete text of a module argument
66    module_args: Option<Vec<'input, &'input str>>, // CREATE VIRTUAL TABLE args
67    done: bool,
68    error: Option<ParserError>,
69}
70
71impl<'input> Context<'input> {
72    pub fn new(bump: &'input Bump, input: &'input [u8]) -> Self {
73        Context {
74            bump,
75            input,
76            explain: None,
77            stmt: None,
78            constraint_name: None,
79            module_arg: None,
80            module_args: None,
81            done: false,
82            error: None,
83        }
84    }
85
86    pub fn new_vec<T>(&mut self, e: T) -> Vec<'input, T> {
87        let mut vec = Vec::new_in(self.bump);
88        vec.push(e);
89        vec
90    }
91
92    /// Consume parsed command
93    pub fn cmd(&mut self) -> Option<Cmd<'input>> {
94        if let Some(stmt) = self.stmt.take() {
95            match self.explain.take() {
96                Some(ExplainKind::Explain) => Some(Cmd::Explain(stmt)),
97                Some(ExplainKind::QueryPlan) => Some(Cmd::ExplainQueryPlan(stmt)),
98                None => Some(Cmd::Stmt(stmt)),
99            }
100        } else {
101            None
102        }
103    }
104
105    fn constraint_name(&mut self) -> Option<Name<'input>> {
106        self.constraint_name.take()
107    }
108    fn no_constraint_name(&self) -> bool {
109        self.constraint_name.is_none()
110    }
111
112    fn vtab_arg_init(&mut self) {
113        self.add_module_arg();
114        self.module_arg = None;
115    }
116    fn vtab_arg_extend(&mut self, any: Token) {
117        if let Some((_, ref mut n)) = self.module_arg {
118            *n = any.2;
119        } else {
120            self.module_arg = Some((any.0, any.2));
121        }
122    }
123    fn add_module_arg(&mut self) {
124        if let Some((start, end)) = self.module_arg.take() {
125            if let Ok(arg) = std::str::from_utf8(&self.input[start..end]) {
126                self.module_args
127                    .get_or_insert(Vec::new_in(self.bump))
128                    .push(self.bump.alloc_str(arg));
129            } // FIXME error handling
130        }
131    }
132    fn module_args(&mut self) -> Option<Vec<'input, &'input str>> {
133        self.add_module_arg();
134        self.module_args.take()
135    }
136
137    /// This routine is called after a single SQL statement has been parsed.
138    fn sqlite3_finish_coding(&mut self) {
139        self.done = true;
140    }
141
142    /// Return `true` if parser completes either successfully or with an error.
143    pub fn done(&self) -> bool {
144        self.done || self.error.is_some()
145    }
146
147    pub fn is_ok(&self) -> bool {
148        self.error.is_none()
149    }
150
151    /// Consume error generated by parser
152    pub fn error(&mut self) -> Option<ParserError> {
153        self.error.take()
154    }
155
156    pub fn reset(&mut self) {
157        self.explain = None;
158        self.stmt = None;
159        self.constraint_name = None;
160        self.module_arg = None;
161        self.module_args = None;
162        self.done = false;
163        self.error = None;
164    }
165}