syntaqlite_syntax/parser/types.rs
1// Copyright 2025 The syntaqlite Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0.
3
4use crate::grammar::TypedGrammar;
5
6/// Tri-state parse result for statement-oriented parser APIs.
7///
8/// Mirrors C parser return codes:
9/// - [`ParseOutcome::Done`] -> `SYNTAQLITE_PARSE_DONE`
10/// - [`ParseOutcome::Ok`] -> `SYNTAQLITE_PARSE_OK`
11/// - [`ParseOutcome::Err`] -> `SYNTAQLITE_PARSE_ERROR`
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ParseOutcome<T, E> {
14 /// No more statements/results are available.
15 Done,
16 /// A statement parsed successfully.
17 Ok(T),
18 /// A statement parsed with an error.
19 Err(E),
20}
21
22impl<T, E> ParseOutcome<T, E> {
23 /// Convert into `Result<Option<T>, E>` for `?`-friendly control flow.
24 ///
25 /// # Errors
26 ///
27 /// Returns `Err(e)` when the outcome is [`ParseOutcome::Err`].
28 pub fn transpose(self) -> Result<Option<T>, E> {
29 match self {
30 ParseOutcome::Done => Ok(None),
31 ParseOutcome::Ok(v) => Ok(Some(v)),
32 ParseOutcome::Err(e) => Err(e),
33 }
34 }
35
36 /// Map the `Ok(T)` payload.
37 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ParseOutcome<U, E> {
38 match self {
39 ParseOutcome::Done => ParseOutcome::Done,
40 ParseOutcome::Ok(v) => ParseOutcome::Ok(f(v)),
41 ParseOutcome::Err(e) => ParseOutcome::Err(e),
42 }
43 }
44
45 /// Map the `Err(E)` payload.
46 pub fn map_err<F>(self, f: impl FnOnce(E) -> F) -> ParseOutcome<T, F> {
47 match self {
48 ParseOutcome::Done => ParseOutcome::Done,
49 ParseOutcome::Ok(v) => ParseOutcome::Ok(v),
50 ParseOutcome::Err(e) => ParseOutcome::Err(f(e)),
51 }
52 }
53}
54
55/// SQL comment style.
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum CommentKind {
58 /// A line comment starting with `--`.
59 Line,
60 /// A block comment delimited by `/* ... */`.
61 Block,
62}
63
64/// Comment captured from source during parsing.
65///
66/// Returned by [`super::TypedParsedStatement::comments`]. Requires
67/// `collect_tokens: true` in [`super::ParserConfig`].
68#[derive(Debug, Clone, Copy)]
69pub struct Comment<'a> {
70 text: &'a str,
71 kind: CommentKind,
72 offset: u32,
73 length: u32,
74}
75
76impl<'a> Comment<'a> {
77 pub(super) fn new(text: &'a str, kind: CommentKind, offset: u32, length: u32) -> Self {
78 Comment {
79 text,
80 kind,
81 offset,
82 length,
83 }
84 }
85
86 /// The full comment text, including delimiters.
87 pub fn text(&self) -> &'a str {
88 self.text
89 }
90
91 /// Whether this is a line (`--`) or block (`/* */`) comment.
92 pub fn kind(&self) -> CommentKind {
93 self.kind
94 }
95
96 /// Byte offset of the comment start within the statement source.
97 pub fn offset(&self) -> u32 {
98 self.offset
99 }
100
101 /// Byte length of the comment text.
102 pub fn length(&self) -> u32 {
103 self.length
104 }
105}
106
107/// Lightweight comment descriptor without a source text borrow.
108///
109/// Returned by [`super::AnyParsedStatement::comment_spans`].
110/// Use this when you only need position and kind, not the text.
111#[derive(Debug, Clone, Copy)]
112pub struct CommentSpan {
113 offset: u32,
114 length: u32,
115 kind: CommentKind,
116}
117
118impl CommentSpan {
119 /// Byte offset of the comment start within the statement source.
120 pub fn offset(&self) -> u32 {
121 self.offset
122 }
123
124 /// Byte length of the comment text.
125 pub fn length(&self) -> u32 {
126 self.length
127 }
128
129 /// Whether this is a line (`--`) or block (`/* */`) comment.
130 pub fn kind(&self) -> CommentKind {
131 self.kind
132 }
133
134 pub(super) fn new(offset: u32, length: u32, kind: CommentKind) -> Self {
135 CommentSpan {
136 offset,
137 length,
138 kind,
139 }
140 }
141}
142
143pub use crate::grammar::ParserTokenFlags;
144
145/// Token captured from a parsed statement, typed by grammar `G`.
146///
147/// Returned by [`super::TypedParsedStatement::tokens`]. Requires
148/// `collect_tokens: true` in [`super::ParserConfig`].
149#[derive(Debug, Clone, Copy)]
150pub struct TypedParserToken<'a, G: TypedGrammar> {
151 text: &'a str,
152 token_type: G::Token,
153 flags: ParserTokenFlags,
154 offset: u32,
155 length: u32,
156}
157
158impl<'a, G: TypedGrammar> TypedParserToken<'a, G> {
159 pub(super) fn new(
160 text: &'a str,
161 token_type: G::Token,
162 flags: ParserTokenFlags,
163 offset: u32,
164 length: u32,
165 ) -> Self {
166 TypedParserToken {
167 text,
168 token_type,
169 flags,
170 offset,
171 length,
172 }
173 }
174
175 /// The source text slice covered by this token.
176 pub fn text(&self) -> &'a str {
177 self.text
178 }
179
180 /// Grammar-typed token variant.
181 pub fn token_type(&self) -> G::Token {
182 self.token_type
183 }
184
185 /// Semantic usage flags inferred by the parser.
186 pub fn flags(&self) -> ParserTokenFlags {
187 self.flags
188 }
189
190 /// Byte offset of the token start within the statement source.
191 pub fn offset(&self) -> u32 {
192 self.offset
193 }
194
195 /// Byte length of the token text.
196 pub fn length(&self) -> u32 {
197 self.length
198 }
199}
200
201/// Parser-token alias for grammar-independent pipelines.
202pub type AnyParserToken<'a> = TypedParserToken<'a, crate::grammar::AnyGrammar>;
203
204/// Byte range of a macro call that contributed to this parse.
205///
206/// Returned by [`super::AnyParsedStatement::macro_regions`].
207#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub struct MacroRegion {
209 /// Byte offset of the macro call in the original source.
210 pub(crate) call_offset: u32,
211 /// Byte length of the entire macro call.
212 pub(crate) call_length: u32,
213}
214
215impl MacroRegion {
216 /// Byte offset of the macro call in the original source.
217 pub fn call_offset(&self) -> u32 {
218 self.call_offset
219 }
220 /// Byte length of the entire macro call.
221 pub fn call_length(&self) -> u32 {
222 self.call_length
223 }
224}
225
226/// Parser's best guess about what kind of token fits next.
227///
228/// Returned by incremental parse sessions for completion engines.
229#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
230#[repr(u32)]
231pub enum CompletionContext {
232 /// Could not determine context.
233 #[default]
234 Unknown = 0,
235 /// Parser expects an expression.
236 Expression = 1,
237 /// Parser expects a table reference.
238 TableRef = 2,
239}
240
241impl CompletionContext {
242 /// Convert from a numeric completion-context code.
243 ///
244 /// Mostly useful for FFI and serialization boundaries.
245 pub fn from_raw(v: u32) -> Self {
246 match v {
247 1 => Self::Expression,
248 2 => Self::TableRef,
249 _ => Self::Unknown,
250 }
251 }
252
253 /// Return the numeric completion-context code.
254 ///
255 /// Mostly useful for FFI and serialization boundaries.
256 pub fn raw(self) -> u32 {
257 self as u32
258 }
259}
260
261impl From<CompletionContext> for u32 {
262 fn from(v: CompletionContext) -> u32 {
263 v.raw()
264 }
265}