untwine_macros/
lib.rs

1use std::ops::RangeInclusive;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::quote;
6use recoverable::{recover_enum, recover_struct};
7use syn::{
8    braced, bracketed, parenthesized,
9    parse::{discouraged::Speculative, Parse, ParseStream},
10    parse_macro_input,
11    token::{Brace, Bracket, Paren},
12    Block, DeriveInput, Expr, Ident, LitBool, LitChar, LitStr, Path, Result, Stmt, Token, Type,
13    Visibility,
14};
15
16mod codegen;
17mod display;
18mod recoverable;
19
20mod kw {
21    use syn::custom_keyword;
22
23    custom_keyword!(error);
24    custom_keyword!(context);
25    custom_keyword!(data);
26    custom_keyword!(lookahead_optimization);
27    custom_keyword!(recover);
28}
29
30#[derive(Debug)]
31pub(crate) struct Header {
32    ctx_name: Ident,
33    error_type: Type,
34    data_type: Type,
35    lookahead_optimization: bool,
36    recover: bool,
37}
38
39#[derive(Debug)]
40pub(crate) enum HeaderParam {
41    ContextName(Ident),
42    ErrorType(Type),
43    DataType(Type),
44    LookaheadOptimization(LitBool),
45    Recover(LitBool),
46}
47
48impl Parse for HeaderParam {
49    fn parse(input: ParseStream) -> Result<Self> {
50        if input.parse::<kw::error>().is_ok() {
51            input.parse::<Token![=]>()?;
52            Ok(HeaderParam::ErrorType(input.parse()?))
53        } else if input.parse::<kw::context>().is_ok() {
54            input.parse::<Token![=]>()?;
55            Ok(HeaderParam::ContextName(input.parse()?))
56        } else if input.parse::<kw::data>().is_ok() {
57            input.parse::<Token![=]>()?;
58            Ok(HeaderParam::DataType(input.parse()?))
59        } else if input.parse::<kw::lookahead_optimization>().is_ok() {
60            input.parse::<Token![=]>()?;
61            Ok(HeaderParam::LookaheadOptimization(input.parse()?))
62        } else if input.parse::<kw::recover>().is_ok() {
63            input.parse::<Token![=]>()?;
64            Ok(HeaderParam::Recover(input.parse()?))
65        } else {
66            Err(input.error("expected one of 'error', 'context', 'data', 'lookahead_optimization', or 'recover'"))
67        }
68    }
69}
70
71impl Parse for Header {
72    fn parse(input: ParseStream) -> Result<Self> {
73        let mut ctx_name = Ident::new("__ctx", Span::call_site());
74        let mut error_type = syn::parse(quote! {untwine::ParserError}.into())?;
75        let mut data_type = syn::parse(quote! {()}.into())?;
76        let mut lookahead_optimization = true;
77        let mut recover = false;
78
79        if input.peek(Bracket) {
80            let content;
81            bracketed!(content in input);
82            while !content.is_empty() {
83                let param: HeaderParam = content.parse()?;
84                match param {
85                    HeaderParam::ContextName(name) => ctx_name = name,
86                    HeaderParam::ErrorType(typ) => error_type = typ,
87                    HeaderParam::DataType(typ) => data_type = typ,
88                    HeaderParam::LookaheadOptimization(enable) => {
89                        lookahead_optimization = enable.value();
90                    }
91                    HeaderParam::Recover(enable) => recover = enable.value(),
92                }
93                if !content.is_empty() {
94                    content.parse::<Token![,]>()?;
95                }
96            }
97        }
98        Ok(Header {
99            ctx_name,
100            error_type,
101            data_type,
102            lookahead_optimization,
103            recover,
104        })
105    }
106}
107
108#[derive(Debug)]
109pub(crate) struct ParserBlock<Stage> {
110    header: Header,
111    parsers: Vec<Stage>,
112}
113
114impl ParserBlock<ParserDef> {
115    fn into_functions(self) -> ParserBlock<ParserFunction> {
116        let functions = self
117            .parsers
118            .into_iter()
119            .flat_map(ParserDef::into_functions)
120            .collect();
121
122        ParserBlock {
123            header: self.header,
124            parsers: functions,
125        }
126    }
127}
128
129impl Parse for ParserBlock<ParserDef> {
130    fn parse(input: ParseStream) -> Result<Self> {
131        let block = ParserBlock {
132            header: input.parse()?,
133            parsers: list(input, false, |i| i.is_empty())?,
134        };
135        Ok(block)
136    }
137}
138
139#[derive(Debug)]
140pub(crate) struct ParserDef {
141    vis: Visibility,
142    name: Ident,
143    patterns: ParserType,
144    return_type: Type,
145}
146
147impl ParserDef {
148    fn into_functions(self) -> Vec<ParserFunction> {
149        match self.patterns {
150            ParserType::Regular(top_level_patterns, block) => vec![ParserFunction {
151                vis: self.vis,
152                error_name: self.name.to_string(),
153                name: self.name,
154                patterns: top_level_patterns,
155                return_type: self.return_type,
156                block,
157            }],
158            ParserType::Match(parser_match) => {
159                parser_match.into_functions(&self.vis, &self.name, &self.return_type)
160            }
161        }
162    }
163}
164
165#[derive(Debug)]
166pub(crate) enum ParserType {
167    Regular(TopLevelPatterns, Block),
168    Match(ParserMatch),
169}
170
171#[derive(Debug)]
172pub(crate) struct ParserMatchArm {
173    patterns: TopLevelPatterns,
174    expr: Expr,
175}
176
177impl Parse for ParserMatchArm {
178    fn parse(input: ParseStream) -> Result<Self> {
179        let patterns = input.parse()?;
180        let _ = input.parse::<Token![=>]>()?;
181        let expr = input.parse()?;
182        Ok(ParserMatchArm { patterns, expr })
183    }
184}
185
186#[derive(Debug)]
187pub(crate) struct ParserMatch {
188    arms: Vec<ParserMatchArm>,
189}
190
191pub(crate) struct ParserFunction {
192    vis: Visibility,
193    name: Ident,
194    error_name: String,
195    patterns: TopLevelPatterns,
196    return_type: Type,
197    block: Block,
198}
199
200impl ParserMatch {
201    fn into_functions(
202        self,
203        vis: &Visibility,
204        parser_name: &Ident,
205        return_type: &Type,
206    ) -> Vec<ParserFunction> {
207        let mut parsers = vec![];
208        let mut names: Vec<Ident> = vec![];
209
210        for (i, arm) in self.arms.into_iter().enumerate() {
211            let name = Ident::new(&format!("__{parser_name}_match_arm_{i}"), Span::call_site());
212            names.push(name.clone());
213
214            let parser = ParserFunction {
215                vis: Visibility::Inherited,
216                error_name: parser_name.to_string(),
217                name,
218                patterns: arm.patterns,
219                return_type: return_type.clone(),
220                block: Block {
221                    brace_token: Brace::default(),
222                    stmts: vec![Stmt::Expr(arm.expr, None)],
223                },
224            };
225            parsers.push(parser);
226        }
227
228        let choices = names
229            .into_iter()
230            .map(|name| {
231                vec![Pattern {
232                    modifier: None,
233                    fragment: PatternFragment::ParserRef(name.clone()),
234                }]
235            })
236            .collect();
237
238        let named_rule = ParserFunction {
239            vis: vis.clone(),
240            error_name: parser_name.to_string(),
241            name: parser_name.clone(),
242            patterns: TopLevelPatterns {
243                patterns: vec![LabeledPattern {
244                    label: Some(parser_name.clone()),
245                    pattern: Pattern {
246                        fragment: PatternFragment::Nested(PatternList::Choices(choices)),
247                        modifier: None,
248                    },
249                }],
250            },
251            return_type: return_type.clone(),
252            block: syn::parse(quote! { { #parser_name } }.into()).unwrap(),
253        };
254        parsers.push(named_rule);
255
256        parsers
257    }
258}
259
260impl Parse for ParserMatch {
261    fn parse(input: ParseStream) -> Result<Self> {
262        input.parse::<Token![match]>()?;
263
264        let block;
265        braced!(block in input);
266
267        let mut arms = vec![];
268
269        if block.is_empty() {
270            return Ok(ParserMatch {
271                arms: vec![syn::parse(
272                    quote! { "" => Err(::untwine::error::ParserError::UnexpectedToken.into())? }
273                        .into(),
274                )?],
275            });
276        }
277
278        arms.push(block.parse()?);
279        while block.peek(Token![,]) {
280            block.parse::<Token![,]>()?;
281            if !block.is_empty() {
282                arms.push(block.parse()?);
283            }
284        }
285        Ok(ParserMatch { arms })
286    }
287}
288
289fn parse_return_type(input: &ParseStream) -> Result<Type> {
290    if input.parse::<Token![->]>().is_ok() {
291        input.parse()
292    } else {
293        syn::parse::<Type>(quote! {()}.into())
294    }
295}
296
297impl Parse for ParserDef {
298    fn parse(input: ParseStream) -> Result<Self> {
299        let vis = input.parse()?;
300        let name: Ident = input.parse()?;
301        let colon = input
302            .parse::<Token![:]>()
303            .map(|_| true)
304            .or_else(|_| input.parse::<Token![=]>().map(|_| false))?;
305
306        if !colon && input.peek(Token![match]) {
307            let match_stmt: ParserMatch = input.parse()?;
308            let return_type = parse_return_type(&input)?;
309            input.parse::<Token![;]>()?;
310
311            return Ok(ParserDef {
312                vis,
313                name,
314                patterns: ParserType::Match(match_stmt),
315                return_type,
316            });
317        }
318
319        let mut patterns: TopLevelPatterns = input.parse()?;
320        let return_type = parse_return_type(&input)?;
321
322        let block = if colon {
323            input.parse()?
324        } else {
325            input.parse::<Token![;]>()?;
326            if let Some(label) = patterns.patterns.iter().flat_map(|p| p.label.iter()).next() {
327                return Err(syn::Error::new(
328                    label.span(),
329                    "Cannot use explicit labels here (implicitly captured by = at beginning)",
330                ));
331            }
332
333            let pattern = Pattern {
334                fragment: PatternFragment::Nested(PatternList::List(
335                    patterns.patterns.into_iter().map(|p| p.pattern).collect(),
336                )),
337                modifier: None,
338            };
339
340            patterns = TopLevelPatterns {
341                patterns: vec![LabeledPattern {
342                    label: Some(name.clone()),
343                    pattern,
344                }],
345            };
346
347            syn::parse(quote! {{#name}}.into())?
348        };
349        Ok(ParserDef {
350            vis,
351            name,
352            patterns: ParserType::Regular(patterns, block),
353            return_type,
354        })
355    }
356}
357
358#[derive(Debug, Clone)]
359pub(crate) struct TopLevelPatterns {
360    patterns: Vec<LabeledPattern>,
361}
362
363impl Parse for TopLevelPatterns {
364    fn parse(input: ParseStream) -> Result<Self> {
365        let mut patterns = vec![];
366        while !input.peek(Token![->]) && !input.peek(Token![;]) && !input.peek(Token![=>]) {
367            patterns.push(input.parse()?);
368        }
369        Ok(TopLevelPatterns { patterns })
370    }
371}
372
373#[derive(Debug, Clone)]
374pub(crate) enum PatternFragment {
375    Literal(LitStr),
376    LiteralChar(LitChar),
377    CharRange(CharRange),
378    CharGroup(CharGroup),
379    CharFilter(CharFilter),
380    ParserRef(Ident),
381    Ignore(Box<IgnoredPattern>),
382    Span(PatternList),
383    Nested(PatternList),
384    Annotated(PatternAttribute),
385    AnyChar,
386}
387
388impl Parse for PatternFragment {
389    fn parse(input: ParseStream) -> Result<Self> {
390        if (input.peek(LitChar) && input.peek2(Token![-]) && !input.peek2(Token![->]))
391            || input.peek(Token![^])
392        {
393            input.parse().map(PatternFragment::CharRange)
394        } else if input.peek(LitChar) {
395            input.parse().map(PatternFragment::LiteralChar)
396        } else if input.peek(Bracket) {
397            input.parse().map(PatternFragment::CharGroup)
398        } else if input.peek(Brace) {
399            input.parse().map(PatternFragment::CharFilter)
400        } else if input.peek(LitStr) {
401            input.parse().map(PatternFragment::Literal)
402        } else if input.peek(Paren) {
403            let content;
404            parenthesized!(content in input);
405            content.parse().map(PatternFragment::Nested)
406        } else if input.peek(Token![.]) {
407            input.parse::<Token![.]>()?;
408            Ok(PatternFragment::AnyChar)
409        } else if input.peek(Token![#]) && input.peek2(Bracket) {
410            let fork = input.fork();
411            fork.parse::<Token![#]>()?;
412            let content;
413            bracketed!(content in fork);
414
415            if content.peek(Ident) {
416                Ok(PatternFragment::Annotated(input.parse()?))
417            } else {
418                Ok(PatternFragment::Ignore(Box::new(input.parse()?)))
419            }
420        } else if input.peek(Token![#]) {
421            let ignored: IgnoredPattern = input.parse()?;
422            Ok(PatternFragment::Ignore(Box::new(ignored)))
423        } else if input.peek(Token![<]) {
424            input.parse::<Token![<]>()?;
425            let patterns = input.parse()?;
426            input.parse::<Token![>]>()?;
427            Ok(PatternFragment::Span(patterns))
428        } else if input.peek(Ident) {
429            input.parse().map(PatternFragment::ParserRef)
430        } else {
431            Err(input.error("expected pattern fragment"))
432        }
433    }
434}
435
436#[derive(Debug, Clone)]
437pub(crate) struct Pattern {
438    fragment: PatternFragment,
439    modifier: Option<Modifier>,
440}
441
442impl Parse for Pattern {
443    fn parse(input: ParseStream) -> Result<Self> {
444        Ok(Pattern {
445            fragment: input.parse()?,
446            modifier: optional(input),
447        })
448    }
449}
450
451#[derive(Debug, Clone)]
452pub(crate) struct PatternAttribute {
453    name: Path,
454    args: Vec<Expr>,
455    pattern: Box<Pattern>,
456}
457
458impl Parse for PatternAttribute {
459    fn parse(input: ParseStream) -> Result<Self> {
460        input.parse::<Token![#]>()?;
461        let brackets;
462        bracketed!(brackets in input);
463        let name = brackets.parse()?;
464        let mut args = vec![];
465        if brackets.peek(Paren) {
466            let parens;
467            parenthesized!(parens in brackets);
468            while !parens.is_empty() {
469                args.push(parens.parse()?);
470                if !parens.is_empty() {
471                    parens.parse::<Token![,]>()?;
472                }
473            }
474        }
475
476        let pattern = Box::new(input.parse()?);
477
478        Ok(PatternAttribute {
479            name,
480            args,
481            pattern,
482        })
483    }
484}
485
486#[derive(Debug, Clone)]
487pub(crate) struct CharRange {
488    inverted: bool,
489    range: RangeInclusive<char>,
490}
491
492impl Parse for CharRange {
493    fn parse(input: ParseStream) -> Result<Self> {
494        let inverted: Option<Token![^]> = input.parse()?;
495        let begin: LitChar = input.parse()?;
496        input.parse::<Token![-]>()?;
497        let end: LitChar = input.parse()?;
498        Ok(CharRange {
499            inverted: inverted.is_some(),
500            range: begin.value()..=end.value(),
501        })
502    }
503}
504
505#[derive(Debug, Clone)]
506pub(crate) struct CharGroup {
507    inverted: bool,
508    chars: Vec<char>,
509}
510
511impl Parse for CharGroup {
512    fn parse(input: ParseStream) -> Result<Self> {
513        let content;
514        bracketed!(content in input);
515        let inverted: Option<Token![^]> = content.parse()?;
516        let str: LitStr = content.parse()?;
517        if str.value().is_empty() {
518            return Err(syn::Error::new_spanned(
519                str,
520                "Character groups must have at least one character",
521            ));
522        }
523        Ok(CharGroup {
524            inverted: inverted.is_some(),
525            chars: str.value().chars().collect(),
526        })
527    }
528}
529
530#[derive(Debug, Clone)]
531pub(crate) struct CharFilter {
532    expr: Expr,
533}
534
535impl Parse for CharFilter {
536    fn parse(input: ParseStream) -> Result<Self> {
537        let content;
538        braced!(content in input);
539        Ok(CharFilter {
540            expr: content.parse()?,
541        })
542    }
543}
544
545#[derive(Debug, Clone)]
546pub(crate) struct IgnoredPattern {
547    pattern: Pattern,
548}
549
550impl Parse for IgnoredPattern {
551    fn parse(input: ParseStream) -> Result<Self> {
552        input.parse::<Token![#]>()?;
553        let pattern = input.parse()?;
554        Ok(IgnoredPattern { pattern })
555    }
556}
557
558#[derive(Debug, Clone)]
559pub(crate) struct LabeledPattern {
560    label: Option<Ident>,
561    pattern: Pattern,
562}
563
564impl Parse for LabeledPattern {
565    fn parse(input: ParseStream) -> Result<Self> {
566        let mut label = None;
567        if input.peek2(Token![=]) && !input.peek2(Token![=>]) {
568            label = Some(input.parse()?);
569            input.parse::<Token![=]>()?;
570        }
571        let pattern: Pattern = input.parse()?;
572        Ok(LabeledPattern { label, pattern })
573    }
574}
575
576#[derive(Debug, Clone)]
577pub(crate) enum PatternList {
578    List(Vec<Pattern>),
579    Choices(Vec<Vec<Pattern>>),
580}
581
582fn list_terminator(input: ParseStream) -> bool {
583    input.peek(Token![|]) || input.peek(Token![->]) || input.peek(Token![>])
584}
585
586impl Parse for PatternList {
587    fn parse(input: ParseStream) -> Result<Self> {
588        let patterns: Vec<Pattern> = list(input, true, list_terminator)?;
589        if !input.peek(Token![|]) {
590            return Ok(PatternList::List(patterns));
591        }
592        let mut choices: Vec<Vec<Pattern>> = vec![patterns];
593        while input.peek(Token![|]) {
594            input.parse::<Token![|]>()?;
595            choices.push(list(input, true, list_terminator)?);
596        }
597        Ok(PatternList::Choices(choices))
598    }
599}
600
601#[derive(Debug, Clone)]
602pub(crate) enum Modifier {
603    Optional,
604    Repeating,
605    OptionalRepeating,
606    Delimited(PatternFragment),
607    OptionalDelimited(PatternFragment),
608}
609
610impl Parse for Modifier {
611    fn parse(input: ParseStream) -> Result<Self> {
612        if input.parse::<Option<Token![+]>>()?.is_some() {
613            Ok(Modifier::Repeating)
614        } else if input.parse::<Option<Token![?]>>()?.is_some() {
615            Ok(Modifier::Optional)
616        } else if input.parse::<Option<Token![*]>>()?.is_some() {
617            Ok(Modifier::OptionalRepeating)
618        } else if input.parse::<Option<Token![$]>>()?.is_some() {
619            let fragment = input.parse()?;
620            if input.peek(Token![+]) {
621                input.parse::<Token![+]>()?;
622                Ok(Modifier::Delimited(fragment))
623            } else {
624                input.parse::<Token![*]>()?;
625                Ok(Modifier::OptionalDelimited(fragment))
626            }
627        } else {
628            Err(input.error("expected modifier"))
629        }
630    }
631}
632
633fn list<T: Parse>(
634    input: ParseStream,
635    require: bool,
636    terminator: fn(ParseStream) -> bool,
637) -> Result<Vec<T>> {
638    let mut vec = vec![];
639    while (require && vec.is_empty()) || (!input.is_empty() && !terminator(input)) {
640        vec.push(input.parse()?);
641    }
642    Ok(vec)
643}
644
645fn optional<T: Parse>(input: ParseStream) -> Option<T> {
646    let fork = input.fork();
647    match fork.parse() {
648        Ok(val) => {
649            input.advance_to(&fork);
650            Some(val)
651        }
652        Err(_) => None,
653    }
654}
655
656/// Generate parsers using a series of declarative patterns and blocks evaluating their values.
657///
658/// Parsers, or "rules", are structured similarly to regular rust functions, and will be converted into
659/// them by this macro. Each rule consists of an optional visiblity modifier, a name, a series of patterns,
660/// and a block to evaluate the output of the parser.
661///
662/// ## Example of a simple parser
663/// ```ignore
664/// parser! {
665///    num: digits=<'0'-'9'+> -> u32 { digits.parse().unwrap() }
666///    pub num_list: nums=num$","+ -> Vec<u32> { nums }
667/// }
668/// ```
669/// Here, `num` is defined as a parser which parses the pattern `<'0'-'9'+>`, whose output is captured to the
670/// variable `digits`, and it evaluates to a `u32` (the result is implicit, and the error type can be configured).
671/// It generates its output by calling `.parse().unwrap()` on `digits`, which is captured as a [&str].
672///
673/// ## Summary of pattern syntax
674/// - `"literal"` - Parses a string literal, and evaluates to `()` (since string literals are assumed to be structural and not desired in output).
675/// - `'c'` - Parses a character literal, and evaluates to `()`
676/// - `'a'-'z'` - Parses characters within a range, equivalent to `'a'..='z'` in regular Rust. Evaluates to [char].
677/// - `^'a'-'z'` - Similar to the above, but parses a character not contained in the range.
678/// - `["abcd"]` - Match any character contained within the string literal. Evaluates to [char].
679/// - `[^"abcd"]` - Similar to the above, but parses a character not contained in the group.
680/// - `.` - Match any single character. Evaluates to [char].
681/// - `{char::is_whitespace}` - Matches any character passing the predicate inside `{}`. Any function with the signature `fn(&char) -> bool` can be used, including a custom lambda.
682/// - `<inner pattern>` - Captures the span of the parsed value as a [&str], rather than the value itself.
683/// - `ident` - Uses a parser defined in this parser block by name.
684/// - `var=pattern` - Captures the output of a parser to a variable which can be used in the parser's function body.
685/// - `(pattern_a | pattern_b)` - Can chain as many patterns as desired together. The resulting parser will try parsing using each of them, in the order specified. Each pattern used must have the same type.
686/// - `pattern_a pattern_b` - Parse two patterns in sequence. The output type will be `(A, B)` for the corresponding types `A` and `B` for the patterns. Units will not be included in this output.
687/// - Modifiers
688///   - `pattern+` - Modifies a pattern to make it repeat as many times as possible, at least once. Returns a [Vec](std::collections::Vec) of the modified pattern's type.
689///   - `pattern*` - Similar to the above, but allows zero matches.
690///   - `pattern?` - Parses the pattern optionally. Returns an [Option](std::option::Option) of the modified pattern's type.
691///   - `pattern$delimiter+` - Parses a list of `pattern` delimited by `delimiter`, requiring at least one value. Returns a [Vec](std::collections::Vec) of `pattern`'s output type. The delimiter's output is ignored.
692///   - `pattern$delimiter*` - Similar to the above, but allows zero matches.
693///   - `#pattern` - Ignores the output of the modified pattern, making it return `()`.
694///   - `#[dbg] pattern` - Print the debug output of the pattern after parsing.
695///     - The above syntax is not a special case, `untwine::attr::dbg` is its implementation. Any similar function can be used as an attribute.
696///     - Additional parameters can be passed like `#[myattr(1, "hello")]`.
697///
698/// ## Using a parser
699/// Every parser specified is rewritten into a regular Rust function, which will parse all of the patterns specified and evaluate your block at the end.
700/// Those which have a visibility modifier like `pub` or `pub(crate)` will be accessible outside of the parser block.
701///
702/// To use one of these parsers, you can either construct a `ParserContext` and call it as normal, or use `untwine::parse` / `untwine::parse_pretty` to get
703/// a regular `Result` instead of untwine's `ParserResult` type.
704
705/// ## Special syntax for parsers
706/// There is an alternate syntax for parsers whose output needs no modification.
707/// The example parser `num_list` above could also be written like this:
708/// ```ignore
709/// parser! {
710///    num: digits=<'0'-'9'+> -> u32 { digits.parse().unwrap() }
711///    pub num_list = nums=num$","+ -> Vec<u32>;
712/// }
713/// ```
714/// If the parser simply returns the output of all of its patterns unchanged, it may use an `=` instead of `:` and
715/// use a semicolon instead of a function body. If the output type is `()`, the `-> ReturnType` can also be omitted,
716/// allowing structural rules like whitespace to be defined simply, like `sep = {char::is_whitespace}*;`.
717///
718/// ### Match parsers
719/// Another special syntax allowed by parsers is a match statement, which can only be used as a top-level rule:
720/// ```ignore
721/// parser! {
722///     boolean = match {
723///         "true" => true,
724///         "false" => false,
725///     } -> bool;
726/// }
727/// ```
728/// These parsers will return the expression corresponding to the first pattern which succeeded.
729/// Since each arm is treated as a top-level pattern, you may use captures (name=) within them to
730/// extract values for the expressions.
731///
732/// ## Configuring a parser block
733/// There are some values that can be adjusted to change the behavior of a parser.
734/// These arguments are specified inside `[]` prior to defining any parsers:
735/// ```ignore
736/// parser! {
737///     [error = MyErrorType]
738///     ...
739/// }
740/// ```
741/// Here are the available options:
742/// - `error = MyErrorType` - Use `MyErrorType` instead of `ParserError` as the error type for all parsers. `MyErrorType` must implement `From<ParserError>`.
743/// - `context = ctx_name` - Expose the `ParserContext` to the parser function bodies using the name specified.
744/// - `data_type = MyCustomContext` - Specify a custom context type which will be passed to all parser functions. It can be accessed using `.data()` or `.data_mut()` on the context argument.
745/// - `lookahead_optimization = false` - Disable the lookahead optimization, which is on by default. This optimization can improve parser performance by as much as double, but also inflates the size of the generated code, which may cause slower clean builds.
746/// - `recovery = true` - Enable automatic error recovery, which allows the parser to continue parsing after an operation fails, following specific rules. Read more below.
747///
748/// ## Error recovery
749/// Automatic error recovery is one of the most powerful features of Untwine, but it is relatively basic and follows a few simple rules.
750/// Being aware of these rules can help you improve the quality of error messages you get, and you can also specify certain recovery rules
751/// manually using attributes.
752///
753/// In order for error recovery to work, you will need to implement the `Recoverable` trait on types which can be recovered from.
754/// This is like `Default`, but can take a range where the error occurred, and is used to generate a value which should be returned
755/// in case of an error which was recovered from.
756///
757/// You can use `#[derive(Recoverable)]` to automatically derive the `Recoverable` trait on your types. If using a struct, all fields
758/// must implement `Recoverable`. If using an enum, the variant to return must have the `#[recover]` attribute, and all constituent
759/// fields must implement `Recoverable`. Note that `Range<usize>` implements this trait, and will return itself, meaning it will auto-populate
760/// to the span of the error that was recovered from.
761///
762/// Here are the rules for error recovery:
763/// - If `recover = true` is set:
764///   - If a named parser begins and ends with unconditional string literals, recovery will happen automatically
765///     - Recovery is attempted by trying to jump ahead to the closing delimiter
766///     - This jump is limited to 1000 non-whitespace characters to prevent excessive lookaheads
767///     - The balance of delimiters will be respected, so `[[]` will not consider the first closing delimiter a match because it is still unbalanced
768///   - If a parser is delimited, when any element fails to parse, attempt to recover to the next delimiter
769///     - This jump respects parent delimiters, so the lookahead will never look past a closing delimiter which ends the scope
770///     - This jump is limited to 150 non-whitespace characters to prevent excessive lookaheads
771///   - If a parser is annotated with `#[recover_to("literal")]`, the annotated parser will recover using the same strategy as above
772///   - There is also a `#[recover_to_any(["a", "b"])]` attribute which allows recovering to one of multiple literals
773#[proc_macro]
774pub fn parser(input: TokenStream) -> TokenStream {
775    let block: ParserBlock<ParserDef> = parse_macro_input!(input as ParserBlock<ParserDef>);
776
777    match codegen::generate_parser_block(block) {
778        Ok(stream) => stream.into(),
779        Err(err) => err.to_compile_error().into(),
780    }
781}
782
783#[proc_macro_derive(Recoverable, attributes(recover))]
784pub fn recovery(input: TokenStream) -> TokenStream {
785    let derive_input = parse_macro_input!(input as DeriveInput);
786    match derive_input.data {
787        syn::Data::Struct(data) => {
788            recover_struct(&data, &derive_input.ident, &derive_input.generics)
789        }
790        syn::Data::Enum(data) => recover_enum(&data, &derive_input.ident, &derive_input.generics)
791            .unwrap_or_else(|e| e.to_compile_error()),
792        syn::Data::Union(_) => panic!("Cannot derive Recoverable on unions"),
793    }
794    .into()
795}