expandable_impl/
grammar.rs

1// Architectural invariant: this module contains basic types that allow to parse
2// the Rust language.
3
4use std::{cmp::Ordering, ptr};
5
6use rust_grammar_dpdfa::Interpreter;
7pub(crate) use rust_grammar_dpdfa::Transition;
8
9use crate::{FragmentKind, Terminal};
10
11#[derive(Clone, Debug)]
12pub(crate) struct DynamicState<Span>
13where
14    Span: 'static + Copy,
15{
16    pub(crate) state: Interpreter<'static, Span>,
17    pub(crate) eaten: Vec<(TokenDescription, Span)>,
18}
19
20impl<Span> PartialEq for DynamicState<Span>
21where
22    Span: 'static + Copy,
23{
24    fn eq(&self, other: &Self) -> bool {
25        ptr::eq(self, other) || self.state == other.state
26    }
27}
28
29impl<Span: 'static + Copy> Eq for DynamicState<Span> {}
30
31impl<Span> PartialOrd for DynamicState<Span>
32where
33    Span: Copy,
34{
35    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
36        Some(self.cmp(other))
37    }
38}
39
40impl<Span> Ord for DynamicState<Span>
41where
42    Span: Copy,
43{
44    fn cmp(&self, other: &Self) -> Ordering {
45        self.eaten
46            .len()
47            .cmp(&other.eaten.len())
48            .then_with(|| self.state.cmp(&other.state))
49    }
50}
51
52#[derive(Clone, Debug, PartialEq)]
53pub(crate) struct ParsingError<Span> {
54    pub(crate) err_span: Span,
55    pub(crate) expected: Vec<TokenDescription>,
56    pub(crate) cex: Vec<(TokenDescription, Span)>,
57}
58
59impl<Span> DynamicState<Span>
60where
61    Span: Copy + 'static,
62{
63    pub(crate) fn item() -> DynamicState<Span> {
64        DynamicState {
65            state: rust_grammar_dpdfa::new_item(),
66            eaten: Vec::new(),
67        }
68    }
69
70    pub(crate) fn expr() -> DynamicState<Span> {
71        DynamicState {
72            state: rust_grammar_dpdfa::new_expr(),
73            eaten: Vec::new(),
74        }
75    }
76
77    pub(crate) fn pat() -> DynamicState<Span> {
78        DynamicState {
79            state: rust_grammar_dpdfa::new_pat(),
80            eaten: Vec::new(),
81        }
82    }
83
84    pub(crate) fn stmt() -> DynamicState<Span> {
85        DynamicState {
86            state: rust_grammar_dpdfa::new_stmt(),
87            eaten: Vec::new(),
88        }
89    }
90
91    pub(crate) fn ty() -> DynamicState<Span> {
92        DynamicState {
93            state: rust_grammar_dpdfa::new_ty(),
94            eaten: Vec::new(),
95        }
96    }
97
98    pub(crate) fn accept_fragment(
99        self,
100        fragment: FragmentKind,
101        span: Span,
102    ) -> Result<(DynamicState<Span>, Transition), ParsingError<Span>> {
103        self.accept(TokenDescription::Fragment(fragment), span)
104    }
105
106    pub(crate) fn accept(
107        mut self,
108        descr: TokenDescription,
109        span: Span,
110    ) -> Result<(DynamicState<Span>, Transition), ParsingError<Span>> {
111        self.eaten.push((descr, span));
112        let descr = rust_grammar_dpdfa::TokenDescription::from(descr);
113        let trans = self.state.step(descr, span).map_err(|(e, err_span)| {
114            let expected = e.into_iter().flat_map(TokenDescription::try_from).collect();
115            let cex = self.eaten.clone();
116
117            ParsingError {
118                err_span,
119                expected,
120                cex,
121            }
122        })?;
123
124        Ok((self, trans))
125    }
126
127    pub(crate) fn is_accepting(&mut self, span: Span) -> Result<(), ParsingError<Span>> {
128        self.state.finish(span).map(drop).map_err(|(e, err_span)| {
129            let expected = e.into_iter().flat_map(TokenDescription::try_from).collect();
130            let cex = self.eaten.clone();
131
132            ParsingError {
133                err_span,
134                expected,
135                cex,
136            }
137        })
138    }
139
140    pub(crate) fn initial_transition(&self) -> Transition {
141        self.state.initial_transition()
142    }
143}
144
145macro_rules! token_description {
146    (
147        $( #[$meta:meta] )*
148        $vis:vis enum $name:ident {
149            $(
150                $( #[$meta_:meta] )*
151                $pattern:pat => $variant:ident
152            ),* $(,)?
153        }
154    ) => {
155        $( #[$meta] )*
156        #[non_exhaustive]
157        $vis enum $name {
158            /// An opening parenthesis.
159            LParen,
160            /// A closing parenthesis.
161            RParen,
162            /// An opening bracket.
163            LBracket,
164            /// A closing bracket.
165            RBracket,
166            /// An opening brace.
167            LBrace,
168            /// A closing brace.
169            RBrace,
170
171            /// A fragment.
172            Fragment(FragmentKind),
173
174            /// An invalid token.
175            Invalid,
176
177            $(
178                $( #[$meta_] )*
179                $variant
180            ),*
181        }
182
183        impl From<&Terminal> for $name {
184            fn from(value: &Terminal) -> $name {
185                match value {
186                    $( $pattern => $name::$variant, )*
187                }
188            }
189        }
190
191        impl From<$name> for rust_grammar_dpdfa::TokenDescription {
192            fn from(descr: $name) -> rust_grammar_dpdfa::TokenDescription {
193                match descr {
194                    $(
195                        $name::$variant => rust_grammar_dpdfa::TokenDescription::$variant,
196                    )*
197
198                    $name::LParen => rust_grammar_dpdfa::TokenDescription::LParen,
199                    $name::RParen => rust_grammar_dpdfa::TokenDescription::RParen,
200                    $name::LBracket => rust_grammar_dpdfa::TokenDescription::LBracket,
201                    $name::RBracket => rust_grammar_dpdfa::TokenDescription::RBracket,
202                    $name::LBrace => rust_grammar_dpdfa::TokenDescription::LBrace,
203                    $name::RBrace => rust_grammar_dpdfa::TokenDescription::RBrace,
204
205                    $name::Fragment(FragmentKind::Block) => rust_grammar_dpdfa::TokenDescription::FragmentBlock,
206                    $name::Fragment(FragmentKind::Expr) => rust_grammar_dpdfa::TokenDescription::FragmentExpr,
207                    $name::Fragment(FragmentKind::Ident) => rust_grammar_dpdfa::TokenDescription::FragmentIdent,
208                    $name::Fragment(FragmentKind::Item) => rust_grammar_dpdfa::TokenDescription::FragmentItem,
209                    $name::Fragment(FragmentKind::Lifetime) => rust_grammar_dpdfa::TokenDescription::FragmentLifetime,
210                    $name::Fragment(FragmentKind::Meta) => rust_grammar_dpdfa::TokenDescription::FragmentMeta,
211                    $name::Fragment(FragmentKind::Pat) => rust_grammar_dpdfa::TokenDescription::FragmentPat,
212                    $name::Fragment(FragmentKind::Path) => rust_grammar_dpdfa::TokenDescription::FragmentPath,
213                    $name::Fragment(FragmentKind::PatParam) => rust_grammar_dpdfa::TokenDescription::FragmentPatParam,
214                    $name::Fragment(FragmentKind::Stmt) => rust_grammar_dpdfa::TokenDescription::FragmentStmt,
215                    $name::Fragment(FragmentKind::Tt) => rust_grammar_dpdfa::TokenDescription::FragmentTt,
216                    $name::Fragment(FragmentKind::Ty) => rust_grammar_dpdfa::TokenDescription::FragmentTy,
217                    $name::Fragment(FragmentKind::Vis) => rust_grammar_dpdfa::TokenDescription::FragmentVis,
218
219                    $name::Invalid => unreachable!(),
220                }
221            }
222        }
223
224        impl TryFrom<rust_grammar_dpdfa::TokenDescription> for $name {
225            type Error = ();
226
227            fn try_from(descr: rust_grammar_dpdfa::TokenDescription) -> Result<$name, ()> {
228                Ok(
229                    match descr {
230                        $(
231                            rust_grammar_dpdfa::TokenDescription::$variant => $name::$variant,
232                        )*
233
234                        rust_grammar_dpdfa::TokenDescription::LParen => TokenDescription::LParen,
235                        rust_grammar_dpdfa::TokenDescription::RParen => TokenDescription::RParen,
236                        rust_grammar_dpdfa::TokenDescription::LBracket => TokenDescription::LBracket,
237                        rust_grammar_dpdfa::TokenDescription::RBracket => TokenDescription::RBracket,
238                        rust_grammar_dpdfa::TokenDescription::LBrace => TokenDescription::LBrace,
239                        rust_grammar_dpdfa::TokenDescription::RBrace => TokenDescription::RBrace,
240
241                        // TODO: support block
242                        // rust_grammar_dpdfa::TokenDescription::FragmentBlock => TokenDescription::Fragment(FragmentKind::Block),
243                        rust_grammar_dpdfa::TokenDescription::FragmentExpr => TokenDescription::Fragment(FragmentKind::Expr),
244                        rust_grammar_dpdfa::TokenDescription::FragmentIdent => TokenDescription::Fragment(FragmentKind::Ident),
245                        rust_grammar_dpdfa::TokenDescription::FragmentItem => TokenDescription::Fragment(FragmentKind::Item),
246                        rust_grammar_dpdfa::TokenDescription::FragmentPat => TokenDescription::Fragment(FragmentKind::Pat),
247                        // TODO: support lifetime
248                        // rust_grammar_dpdfa::TokenDescription::FragmentLifetime => TokenDescription::Fragment(FragmentKind::Lifetime),
249                        // TODO: support literal
250                        // rust_grammar_dpdfa::TokenDescription::FragmentLiteral => TokenDescription::Fragment(FragmentKind::Literal),
251                        // TODO: support meta
252                        // rust_grammar_dpdfa::TokenDescription::FragmentMeta => TokenDescription::Fragment(FragmentKind::Meta),
253                        // TODO: support stmt
254                        // rust_grammar_dpdfa::TokenDescription::FragmentStmt => TokenDescription::Fragment(FragmentKind::Stmt),
255                        // TODO: support TT
256                        // rust_grammar_dpdfa::TokenDescription::FragmentTT => TokenDescription::Fragment(FragmentKind::TT),
257                        // TODO: support ty
258                        // rust_grammar_dpdfa::TokenDescription::FragmentTy => TokenDescription::Fragment(FragmentKind::Ty),
259                        // TODO: support vis
260                        // rust_grammar_dpdfa::TokenDescription::FragmentVis => TokenDescription::Fragment(FragmentKind::Vis),
261
262
263                        _ => return Err(()),
264                    }
265
266                )
267            }
268        }
269    };
270}
271
272token_description! {
273    /// Describes a [`Terminal`].
274    ///
275    /// This allows library user to accurately report what kind of token is
276    /// expected.
277    #[derive(Clone, Copy, Debug, PartialEq)]
278    pub enum TokenDescription {
279        /// An identifier. Does not include keywords.
280        Terminal::Ident(_) => Ident,
281
282        // Keywords
283        /// The `as` keyword.
284        Terminal::As => As,
285        /// The `async` keyword.
286        Terminal::Async => Async,
287        /// The `await` keyword.
288        Terminal::Await => Await,
289        /// The `break` keyword.
290        Terminal::Break => Break,
291        /// The `const` keyword.
292        Terminal::Const => Const,
293        /// The `continue` keyword.
294        Terminal::Continue => Continue,
295        /// The `crate` keyword.
296        Terminal::Crate => Crate,
297        /// The `dyn` keyword.
298        Terminal::Dyn => Dyn,
299        /// The `else` keyword.
300        Terminal::Else => Else,
301        /// The `enum` keyword.
302        Terminal::Enum => Enum,
303        /// The `extern` keyword.
304        Terminal::Extern => Extern,
305        /// The `false` keyword.
306        Terminal::False => False,
307        /// The `fn` keyword.
308        Terminal::Fn => Fn,
309        /// The `for` keyword.
310        Terminal::For => For,
311        /// The `if` keyword.
312        Terminal::If => If,
313        /// The `impl` keyword.
314        Terminal::Impl => Impl,
315        /// The `in` keyword.
316        Terminal::In => In,
317        /// The `let` keyword.
318        Terminal::Let => Let,
319        /// The `loop` keyword.
320        Terminal::Loop => Loop,
321        /// The `match` keyword.
322        Terminal::Match => Match,
323        /// The `mod` keyword.
324        Terminal::Mod => Mod,
325        /// The `move` keyword.
326        Terminal::Move => Move,
327        /// The `mut` keyword.
328        Terminal::Mut => Mut,
329        /// The `pub` keyword.
330        Terminal::Pub => Pub,
331        /// The `ref` keyword.
332        Terminal::Ref => Ref,
333        /// The `return` keyword.
334        Terminal::Return => Return,
335        /// The `self` keyword.
336        Terminal::Self_ => Self_,
337        /// The `Self` keyword.
338        Terminal::SelfUpper => SelfUpper,
339        /// The `static` keyword.
340        Terminal::Static => Static,
341        /// The `struct` keyword.
342        Terminal::Struct => Struct,
343        /// The `super` keyword.
344        Terminal::Super => Super,
345        /// The `trait` keyword.
346        Terminal::Trait => Trait,
347        /// The `true` keyword.
348        Terminal::True => True,
349        /// The `type` keyword.
350        Terminal::Type => Type,
351        /// The `union` keyword.
352        Terminal::Union => Union,
353        /// The `unsafe` keyword.
354        Terminal::Unsafe => Unsafe,
355        /// The `use` keyword.
356        Terminal::Use => Use,
357        /// The `where` keyword.
358        Terminal::Where => Where,
359        /// The `while` keyword.
360        Terminal::While => While,
361        /// The `async` keyword.
362        Terminal::Yield => Yield,
363
364        /// The `abstract` keyword.
365        Terminal::Abstract => Abstract,
366        /// The `become` keyword.
367        Terminal::Become => Become,
368        /// The `box` keyword.
369        Terminal::Box => Box,
370        /// The `do` keyword.
371        Terminal::Do => Do,
372        /// The `final` keyword.
373        Terminal::Final => Final,
374        /// The `macro` keyword.
375        Terminal::Macro => Macro,
376        /// The `override` keyword.
377        Terminal::Override => Override,
378        /// The `priv` keyword.
379        Terminal::Priv => Priv,
380        /// The `try` keyword.
381        Terminal::Try => Try,
382        /// The `typeof` keyword.
383        Terminal::Typeof => Typeof,
384        /// The `unsized` keyword.
385        Terminal::Unsized => Unsized,
386        /// The `virtual` keyword.
387        Terminal::Virtual => Virtual,
388
389        // Literals
390        /// A literal
391        Terminal::Literal(_) => Literal,
392
393        // Punctuates
394        /// A plus (`+`).
395        Terminal::Plus => Plus,
396        /// A minus (`-`).
397        Terminal::Minus => Minus,
398        /// A star (`*`).
399        Terminal::Star => Star,
400        /// A slash (`/`).
401        Terminal::Slash => Slash,
402        /// A percent sign (`%`).
403        Terminal::Percent => Percent,
404        /// A caret (`^`).
405        Terminal::Caret => Caret,
406        /// A not (`!`).
407        Terminal::Not => Not,
408        /// An ampersand (`&`).
409        Terminal::And => And,
410        /// An or (`|`).
411        Terminal::Or => Or,
412        /// A lazy boolean and (`&&`).
413        Terminal::AndAnd => AndAnd,
414        /// A lazy boolean or (`||`).
415        Terminal::OrOr => OrOr,
416        /// A shift left (`<<`).
417        Terminal::Shl => Shl,
418        /// A shift right (`>>`).
419        Terminal::Shr => Shr,
420        /// A plus-equals (`+=`).
421        Terminal::PlusEquals => PlusEquals,
422        /// A minus-equals (`-=`).
423        Terminal::MinusEquals => MinusEquals,
424        /// A star-equals (`*=`).
425        Terminal::StarEquals => StarEquals,
426        /// A slash-equals (`/=`).
427        Terminal::SlashEquals => SlashEquals,
428        /// A percent-equals (`%=`).
429        Terminal::PercentEquals => PercentEquals,
430        /// A caret-equals (`^=`).
431        Terminal::CaretEquals => CaretEquals,
432        /// An and-equals (`&=`).
433        Terminal::AndEquals => AndEquals,
434        /// An or-equals (`|=`).
435        Terminal::OrEquals => OrEquals,
436        /// A shift-left-equals (`<<=`).
437        Terminal::ShlEquals => ShlEquals,
438        /// A shift-right-equals (`>>=`).
439        Terminal::ShrEquals => ShrEquals,
440        /// An equals (`=`).
441        Terminal::Equals => Equals,
442        /// An equals equals (`==`).
443        Terminal::EqualsEquals => EqualsEquals,
444        /// A not equals (`!=`).
445        Terminal::NotEquals => NotEquals,
446        /// A greater than (`>`).
447        Terminal::GreaterThan => GreaterThan,
448        /// A left chevron (`<`).
449        Terminal::LessThan => LessThan,
450        /// A greater than equals (`>=`).
451        Terminal::GreaterThanEquals => GreaterThanEquals,
452        /// A less than equals (`<=`).
453        Terminal::LessThanEquals => LessThanEquals,
454        /// An at (`@`).
455        Terminal::At => At,
456        /// An underscore (`_`).
457        Terminal::Underscore => Underscore,
458        /// A dot (`.`).
459        Terminal::Dot => Dot,
460        /// A dot dot (`..`).
461        Terminal::DotDot => DotDot,
462        /// A dot dot dot (`...`).
463        Terminal::DotDotDot => DotDotDot,
464        /// A dot dot equals (`..=`).
465        Terminal::DotDotEquals => DotDotEquals,
466        /// A comma (`,`).
467        Terminal::Comma => Comma,
468        /// A semicolon (`;`).
469        Terminal::Semicolon => Semicolon,
470        /// A colon (`:`).
471        Terminal::Colon => Colon,
472        /// A colon colon (`::`).
473        Terminal::ColonColon => ColonColon,
474        /// An arrow (`->`).
475        Terminal::RightArrow => RightArrow,
476        /// A fat arrow (`=>`).
477        Terminal::FatArrow => FatArrow,
478        /// The pound sign (`#`).
479        Terminal::Pound => Pound,
480        /// The dollar sign (`$`).
481        Terminal::Dollar => Dollar,
482        /// A question mark (`?`).
483        Terminal::QuestionMark => QuestionMark,
484    }
485}