1use 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 LParen,
160 RParen,
162 LBracket,
164 RBracket,
166 LBrace,
168 RBrace,
170
171 Fragment(FragmentKind),
173
174 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 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 _ => return Err(()),
264 }
265
266 )
267 }
268 }
269 };
270}
271
272token_description! {
273 #[derive(Clone, Copy, Debug, PartialEq)]
278 pub enum TokenDescription {
279 Terminal::Ident(_) => Ident,
281
282 Terminal::As => As,
285 Terminal::Async => Async,
287 Terminal::Await => Await,
289 Terminal::Break => Break,
291 Terminal::Const => Const,
293 Terminal::Continue => Continue,
295 Terminal::Crate => Crate,
297 Terminal::Dyn => Dyn,
299 Terminal::Else => Else,
301 Terminal::Enum => Enum,
303 Terminal::Extern => Extern,
305 Terminal::False => False,
307 Terminal::Fn => Fn,
309 Terminal::For => For,
311 Terminal::If => If,
313 Terminal::Impl => Impl,
315 Terminal::In => In,
317 Terminal::Let => Let,
319 Terminal::Loop => Loop,
321 Terminal::Match => Match,
323 Terminal::Mod => Mod,
325 Terminal::Move => Move,
327 Terminal::Mut => Mut,
329 Terminal::Pub => Pub,
331 Terminal::Ref => Ref,
333 Terminal::Return => Return,
335 Terminal::Self_ => Self_,
337 Terminal::SelfUpper => SelfUpper,
339 Terminal::Static => Static,
341 Terminal::Struct => Struct,
343 Terminal::Super => Super,
345 Terminal::Trait => Trait,
347 Terminal::True => True,
349 Terminal::Type => Type,
351 Terminal::Union => Union,
353 Terminal::Unsafe => Unsafe,
355 Terminal::Use => Use,
357 Terminal::Where => Where,
359 Terminal::While => While,
361 Terminal::Yield => Yield,
363
364 Terminal::Abstract => Abstract,
366 Terminal::Become => Become,
368 Terminal::Box => Box,
370 Terminal::Do => Do,
372 Terminal::Final => Final,
374 Terminal::Macro => Macro,
376 Terminal::Override => Override,
378 Terminal::Priv => Priv,
380 Terminal::Try => Try,
382 Terminal::Typeof => Typeof,
384 Terminal::Unsized => Unsized,
386 Terminal::Virtual => Virtual,
388
389 Terminal::Literal(_) => Literal,
392
393 Terminal::Plus => Plus,
396 Terminal::Minus => Minus,
398 Terminal::Star => Star,
400 Terminal::Slash => Slash,
402 Terminal::Percent => Percent,
404 Terminal::Caret => Caret,
406 Terminal::Not => Not,
408 Terminal::And => And,
410 Terminal::Or => Or,
412 Terminal::AndAnd => AndAnd,
414 Terminal::OrOr => OrOr,
416 Terminal::Shl => Shl,
418 Terminal::Shr => Shr,
420 Terminal::PlusEquals => PlusEquals,
422 Terminal::MinusEquals => MinusEquals,
424 Terminal::StarEquals => StarEquals,
426 Terminal::SlashEquals => SlashEquals,
428 Terminal::PercentEquals => PercentEquals,
430 Terminal::CaretEquals => CaretEquals,
432 Terminal::AndEquals => AndEquals,
434 Terminal::OrEquals => OrEquals,
436 Terminal::ShlEquals => ShlEquals,
438 Terminal::ShrEquals => ShrEquals,
440 Terminal::Equals => Equals,
442 Terminal::EqualsEquals => EqualsEquals,
444 Terminal::NotEquals => NotEquals,
446 Terminal::GreaterThan => GreaterThan,
448 Terminal::LessThan => LessThan,
450 Terminal::GreaterThanEquals => GreaterThanEquals,
452 Terminal::LessThanEquals => LessThanEquals,
454 Terminal::At => At,
456 Terminal::Underscore => Underscore,
458 Terminal::Dot => Dot,
460 Terminal::DotDot => DotDot,
462 Terminal::DotDotDot => DotDotDot,
464 Terminal::DotDotEquals => DotDotEquals,
466 Terminal::Comma => Comma,
468 Terminal::Semicolon => Semicolon,
470 Terminal::Colon => Colon,
472 Terminal::ColonColon => ColonColon,
474 Terminal::RightArrow => RightArrow,
476 Terminal::FatArrow => FatArrow,
478 Terminal::Pound => Pound,
480 Terminal::Dollar => Dollar,
482 Terminal::QuestionMark => QuestionMark,
484 }
485}