sqlite3_parser/parser/
mod.rs

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