nom_rule/
lib.rs

1//! A procedural macro crate for writing nom parsers using a grammar-like syntax.
2//!
3//! The `nom-rule` crate provides the `rule!` macro, which allows you to define parsers in a DSL
4//! similar to grammar rules. This improves readability and maintainability.
5//!
6//! # Syntax
7//!
8//! The macro follows these rules:
9//!
10//! | **Syntax**            | **Description**                                                                  | **Expanded to**                         | **Operator Precedence**  |
11//! |-----------------------|----------------------------------------------------------------------------------|-----------------------------------------|--------------------------|
12//! | `TOKEN`               | Matches a token by kind.                                                         | `match_token(TOKEN)`                    | -                        |
13//! | `"@"`                 | Matches a token by its text.                                                     | `match_text("@")`                       | -                        |
14//! | `#fn_name`            | Calls an external nom parser function `fn_name`.                                 | `fn_name`                               | -                        |
15//! | `#fn_name(a, b, c)`   | Calls an external nom parser function `fn_name` with arguments.                  | `fn_name(a, b, c)`                      | -                        |
16//! | `a ~ b ~ c`           | Sequences parsers `a`, `b`, and `c`.                                             | `((a, b, c))`                           | 3 (Left Associative)     |
17//! | `a+`                  | One or more repetitions.                                                         | `nom::multi::many1(a)`                  | 4 (Postfix)              |
18//! | `a*`                  | Zero or more repetitions.                                                        | `nom::multi::many0(a)`                  | 4 (Postfix)              |
19//! | `a?`                  | Optional parser.                                                                 | `nom::combinator::opt(a)`               | 4 (Postfix)              |
20//! | `a \| b \| c`         | Choice between parsers `a`, `b`, and `c`.                                        | `nom::branch::alt((a, b, c))`           | 1 (Left Associative)     |
21//! | `&a`                  | Peeks at parser `a` without consuming input.                                     | `nom::combinator::peek(a)`              | 5 (Prefix)               |
22//! | `!a`                  | Negative lookahead for parser `a`.                                               | `nom::combinator::not(a)`               | 5 (Prefix)               |
23//! | `^a`                  | Cuts the parser `a`.                                                             | `nom::combinator::cut(a)`               | 5 (Prefix)               |
24//! | `... : "description"` | Adds a context description for error reporting.                                  | `nom::error::context("description", a)` | 2 (Postfix)              |
25//! # Example
26//!
27//! ```rust-example
28//! use nom_rule::rule;
29//! use nom::IResult;
30//!
31//! // Define your match functions
32//! fn match_text<'a>(text: &'a str) -> impl FnMut(Input<'a>) -> IResult<Input<'a>, &'a Token<'a>> {
33//!     // Implementation
34//! }
35//!
36//! fn match_token<'a>(kind: TokenKind) -> impl FnMut(Input<'a>) -> IResult<Input<'a>, &'a Token<'a>> {
37//!     // Implementation
38//! }
39//!
40//! fn ident<'a>(input: Input<'a>) -> IResult<Input<'a>, &str> {
41//!     // Implementation
42//! }
43//!
44//! // Use the `rule!` macro
45//! let mut parser = rule!(
46//!     CREATE ~ TABLE ~ #ident ~ ^"(" ~ (#ident ~ #ident ~ ","?)* ~ ")" ~ ";"
47//!     : "CREATE TABLE statement"
48//! );
49//! ```
50
51use nom::branch::alt;
52use nom::combinator::map;
53use nom::combinator::opt;
54use nom::error::make_error;
55use nom::error::ErrorKind;
56use nom::multi::many0;
57use nom::Parser;
58use nom::{IResult, Needed};
59use pratt::Affix;
60use pratt::Associativity;
61use pratt::PrattError;
62use pratt::PrattParser;
63use pratt::Precedence;
64use proc_macro2::Group;
65use proc_macro2::Ident;
66use proc_macro2::Literal;
67use proc_macro2::Punct;
68use proc_macro2::Spacing;
69use proc_macro2::Span;
70use proc_macro2::TokenStream;
71use proc_macro2::TokenTree;
72use proc_macro_error2::abort;
73use proc_macro_error2::abort_call_site;
74use proc_macro_error2::proc_macro_error;
75use quote::quote;
76use quote::ToTokens;
77use quote::TokenStreamExt;
78use std::iter::{Cloned, Enumerate};
79use std::ops::Deref;
80use std::slice::Iter;
81use syn::punctuated::Punctuated;
82use syn::Token;
83
84/// A procedural macro for writing nom parsers using a grammar-like syntax.
85///
86/// See the [crate level documentation](index.html) for more information.
87#[proc_macro]
88#[proc_macro_error]
89pub fn rule(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
90    let tokens: TokenStream = tokens.into();
91    let i: Vec<TokenTree> = tokens.into_iter().collect();
92
93    // Attempt to parse the paths for match_text and match_token
94    let (i, terminals) = if let Ok((rest, (match_text, _, match_token, _))) =
95        (path, match_punct(','), path, match_punct(',')).parse(Input(&i))
96    {
97        (
98            rest,
99            Some(CustomTerminal {
100                match_text: match_text.1,
101                match_token: match_token.1,
102            }),
103        )
104    } else {
105        (Input(i.as_slice()), None)
106    };
107
108    let terminal = terminals.unwrap_or_else(|| CustomTerminal {
109        match_text: Path {
110            segments: vec![Ident::new("match_text", Span::call_site())],
111        },
112        match_token: Path {
113            segments: vec![Ident::new("match_token", Span::call_site())],
114        },
115    });
116
117    let rule = parse_rule(i.iter().cloned().collect());
118    rule.check_return_type();
119    rule.to_token_stream(&terminal).into()
120}
121
122#[derive(Debug, Clone)]
123struct Path {
124    segments: Vec<Ident>,
125}
126
127#[derive(Debug, Clone)]
128enum Rule {
129    MatchText(Span, Literal),
130    MatchToken(Span, Path),
131    ExternalFunction(Span, Path, Option<Group>),
132    Context(Span, Literal, Box<Rule>),
133    Peek(Span, Box<Rule>),
134    Not(Span, Box<Rule>),
135    Optional(Span, Box<Rule>),
136    Cut(Span, Box<Rule>),
137    Many0(Span, Box<Rule>),
138    Many1(Span, Box<Rule>),
139    Sequence(Span, Vec<Rule>),
140    Choice(Span, Vec<Rule>),
141}
142
143#[derive(Debug, Clone)]
144enum RuleElement {
145    MatchText(Literal),
146    MatchToken(Path),
147    ExternalFunction(Path, Option<Group>),
148    Context(Literal),
149    Peek,
150    Not,
151    Optional,
152    Cut,
153    Many0,
154    Many1,
155    Sequence,
156    Choice,
157    SubRule(Rule),
158}
159
160#[derive(Debug, Clone)]
161struct WithSpan {
162    elem: RuleElement,
163    span: Span,
164}
165
166#[derive(Debug, Clone)]
167enum ReturnType {
168    Option(Box<ReturnType>),
169    Vec(Box<ReturnType>),
170    Unit,
171    Unknown,
172}
173
174struct CustomTerminal {
175    match_text: Path,
176    match_token: Path,
177}
178
179#[derive(Debug, Clone)]
180struct Input<'a>(&'a [TokenTree]);
181
182impl Deref for Input<'_> {
183    type Target = [TokenTree];
184
185    fn deref(&self) -> &Self::Target {
186        self.0
187    }
188}
189
190impl<'a> nom::Input for Input<'a> {
191    type Item = TokenTree;
192    type Iter = Cloned<Iter<'a, TokenTree>>;
193    type IterIndices = Enumerate<Self::Iter>;
194
195    fn input_len(&self) -> usize {
196        self.0.len()
197    }
198
199    fn take(&self, index: usize) -> Self {
200        Input(&self.0[0..index])
201    }
202
203    fn take_from(&self, index: usize) -> Self {
204        Input(&self.0[index..])
205    }
206
207    fn take_split(&self, index: usize) -> (Self, Self) {
208        let (prefix, suffix) = self.0.split_at(index);
209        (Input(suffix), Input(prefix))
210    }
211
212    fn position<P>(&self, predicate: P) -> Option<usize>
213    where
214        P: Fn(Self::Item) -> bool,
215    {
216        self.iter().position(|b| predicate(b.clone()))
217    }
218
219    fn iter_elements(&self) -> Self::Iter {
220        self.0.iter().cloned()
221    }
222
223    fn iter_indices(&self) -> Self::IterIndices {
224        self.iter_elements().enumerate()
225    }
226
227    fn slice_index(&self, count: usize) -> Result<usize, Needed> {
228        if self.len() >= count {
229            Ok(count)
230        } else {
231            Err(Needed::new(count - self.len()))
232        }
233    }
234}
235
236fn match_punct<'a>(punct: char) -> impl FnMut(Input<'a>) -> IResult<Input<'a>, TokenTree> {
237    move |i| match i.first().and_then(|token| match token {
238        TokenTree::Punct(p) if p.as_char() == punct => Some(token.clone()),
239        _ => None,
240    }) {
241        Some(token) => Ok((Input(&i.0[1..]), token)),
242        _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
243    }
244}
245
246fn group(i: Input) -> IResult<Input, Group> {
247    match i.first().and_then(|token| match token {
248        TokenTree::Group(group) => Some(group.clone()),
249        _ => None,
250    }) {
251        Some(group) => Ok((Input(&i.0[1..]), group)),
252        _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
253    }
254}
255
256fn literal(i: Input) -> IResult<Input, Literal> {
257    match i.first().and_then(|token| match token {
258        TokenTree::Literal(lit) => Some(lit.clone()),
259        _ => None,
260    }) {
261        Some(lit) => Ok((Input(&i.0[1..]), lit)),
262        _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
263    }
264}
265
266fn ident(i: Input) -> IResult<Input, Ident> {
267    match i.first().and_then(|token| match token {
268        TokenTree::Ident(ident) => Some(ident.clone()),
269        _ => None,
270    }) {
271        Some(ident) => Ok((Input(&i.0[1..]), ident)),
272        _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
273    }
274}
275
276fn path(i: Input) -> IResult<Input, (Span, Path)> {
277    map(
278        (ident, many0((match_punct(':'), match_punct(':'), ident))),
279        |(head, tail)| {
280            let mut segments = vec![head.clone()];
281            segments.extend(tail.into_iter().map(|(_, _, segment)| segment));
282            let span = segments
283                .iter()
284                .try_fold(head.span(), |span, seg| span.join(seg.span()))
285                .unwrap_or(Span::call_site());
286            (span, Path { segments })
287        },
288    )
289    .parse(i)
290}
291
292fn parse_rule(tokens: TokenStream) -> Rule {
293    let i: Vec<TokenTree> = tokens.into_iter().collect();
294
295    let (i, elems) = many0(parse_rule_element).parse(Input(&i)).unwrap();
296    if !i.is_empty() {
297        let rest: TokenStream = i.iter().cloned().collect();
298        abort!(rest, "unable to parse the following rules: {}", rest);
299    }
300
301    let mut iter = elems.into_iter().peekable();
302    let rule = unwrap_pratt(RuleParser.parse(&mut iter));
303    if iter.peek().is_some() {
304        let rest: Vec<_> = iter.collect();
305        abort!(
306            rest[0].span,
307            "unable to parse the following rules: {:?}",
308            rest
309        );
310    }
311
312    rule
313}
314
315fn parse_rule_element(i: Input) -> IResult<Input, WithSpan> {
316    let function_call = |i| {
317        let (i, hashtag) = match_punct('#')(i)?;
318        let (i, (path_span, fn_path)) = path(i)?;
319        let (i, args) = opt(group).parse(i)?;
320        let span = hashtag.span().join(path_span).unwrap_or(Span::call_site());
321        let span = args
322            .as_ref()
323            .and_then(|args| args.span().join(span))
324            .unwrap_or(span);
325
326        Ok((
327            i,
328            WithSpan {
329                elem: RuleElement::ExternalFunction(fn_path, args),
330                span,
331            },
332        ))
333    };
334    let context = map((match_punct(':'), literal), |(colon, msg)| {
335        let span = colon.span().join(msg.span()).unwrap_or(Span::call_site());
336        WithSpan {
337            elem: RuleElement::Context(msg),
338            span,
339        }
340    });
341    alt((
342        map(match_punct('|'), |token| WithSpan {
343            span: token.span(),
344            elem: RuleElement::Choice,
345        }),
346        map(match_punct('*'), |token| WithSpan {
347            span: token.span(),
348            elem: RuleElement::Many0,
349        }),
350        map(match_punct('+'), |token| WithSpan {
351            span: token.span(),
352            elem: RuleElement::Many1,
353        }),
354        map(match_punct('?'), |token| WithSpan {
355            span: token.span(),
356            elem: RuleElement::Optional,
357        }),
358        map(match_punct('^'), |token| WithSpan {
359            span: token.span(),
360            elem: RuleElement::Cut,
361        }),
362        map(match_punct('&'), |token| WithSpan {
363            span: token.span(),
364            elem: RuleElement::Peek,
365        }),
366        map(match_punct('!'), |token| WithSpan {
367            span: token.span(),
368            elem: RuleElement::Not,
369        }),
370        map(match_punct('~'), |token| WithSpan {
371            span: token.span(),
372            elem: RuleElement::Sequence,
373        }),
374        map(literal, |lit| WithSpan {
375            span: lit.span(),
376            elem: RuleElement::MatchText(lit),
377        }),
378        map(path, |(span, p)| WithSpan {
379            span,
380            elem: RuleElement::MatchToken(p),
381        }),
382        map(group, |group| WithSpan {
383            span: group.span(),
384            elem: RuleElement::SubRule(parse_rule(group.stream())),
385        }),
386        function_call,
387        context,
388    ))
389    .parse(i)
390}
391
392fn unwrap_pratt(res: Result<Rule, PrattError<WithSpan, pratt::NoError>>) -> Rule {
393    match res {
394        Ok(res) => res,
395        Err(PrattError::EmptyInput) => abort_call_site!("expected more tokens for rule"),
396        Err(PrattError::UnexpectedNilfix(input)) => {
397            abort!(input.span, "unable to parse the value")
398        }
399        Err(PrattError::UnexpectedPrefix(input)) => {
400            abort!(input.span, "unable to parse the prefix operator")
401        }
402        Err(PrattError::UnexpectedInfix(input)) => {
403            abort!(input.span, "unable to parse the binary operator")
404        }
405        Err(PrattError::UnexpectedPostfix(input)) => {
406            abort!(input.span, "unable to parse the postfix operator")
407        }
408        Err(PrattError::UserError(_)) => unreachable!(),
409    }
410}
411
412struct RuleParser;
413
414impl<I: Iterator<Item = WithSpan>> PrattParser<I> for RuleParser {
415    type Error = pratt::NoError;
416    type Input = WithSpan;
417    type Output = Rule;
418
419    fn query(&mut self, elem: &WithSpan) -> pratt::Result<Affix> {
420        let affix = match elem.elem {
421            RuleElement::Choice => Affix::Infix(Precedence(1), Associativity::Left),
422            RuleElement::Context(_) => Affix::Postfix(Precedence(2)),
423            RuleElement::Sequence => Affix::Infix(Precedence(3), Associativity::Left),
424            RuleElement::Optional => Affix::Postfix(Precedence(4)),
425            RuleElement::Many1 => Affix::Postfix(Precedence(4)),
426            RuleElement::Many0 => Affix::Postfix(Precedence(4)),
427            RuleElement::Cut => Affix::Prefix(Precedence(5)),
428            RuleElement::Peek => Affix::Prefix(Precedence(5)),
429            RuleElement::Not => Affix::Prefix(Precedence(5)),
430            _ => Affix::Nilfix,
431        };
432        Ok(affix)
433    }
434
435    fn primary(&mut self, elem: WithSpan) -> pratt::Result<Rule> {
436        let rule = match elem.elem {
437            RuleElement::SubRule(rule) => rule,
438            RuleElement::MatchText(text) => Rule::MatchText(elem.span, text),
439            RuleElement::MatchToken(token) => Rule::MatchToken(elem.span, token),
440            RuleElement::ExternalFunction(func, args) => {
441                Rule::ExternalFunction(elem.span, func, args)
442            }
443            _ => unreachable!(),
444        };
445        Ok(rule)
446    }
447
448    fn infix(&mut self, lhs: Rule, elem: WithSpan, rhs: Rule) -> pratt::Result<Rule> {
449        let rule = match elem.elem {
450            RuleElement::Sequence => match lhs {
451                Rule::Sequence(span, mut seq) => {
452                    let span = span
453                        .join(elem.span)
454                        .unwrap_or(Span::call_site())
455                        .join(rhs.span())
456                        .unwrap_or(Span::call_site());
457                    seq.push(rhs);
458                    Rule::Sequence(span, seq)
459                }
460                lhs => {
461                    let span = lhs.span().join(rhs.span()).unwrap_or(Span::call_site());
462                    Rule::Sequence(span, vec![lhs, rhs])
463                }
464            },
465            RuleElement::Choice => match lhs {
466                Rule::Choice(span, mut choices) => {
467                    let span = span
468                        .join(elem.span)
469                        .unwrap_or(Span::call_site())
470                        .join(rhs.span())
471                        .unwrap_or(Span::call_site());
472                    choices.push(rhs);
473                    Rule::Choice(span, choices)
474                }
475                lhs => {
476                    let span = lhs.span().join(rhs.span()).unwrap_or(Span::call_site());
477                    Rule::Choice(span, vec![lhs, rhs])
478                }
479            },
480            _ => unreachable!(),
481        };
482        Ok(rule)
483    }
484
485    fn prefix(&mut self, elem: WithSpan, rhs: Rule) -> pratt::Result<Rule> {
486        let rule = match elem.elem {
487            RuleElement::Cut => {
488                let span = elem.span.join(rhs.span()).unwrap_or(Span::call_site());
489                Rule::Cut(span, Box::new(rhs))
490            }
491            RuleElement::Peek => {
492                let span = elem.span.join(rhs.span()).unwrap_or(Span::call_site());
493                Rule::Peek(span, Box::new(rhs))
494            }
495            RuleElement::Not => {
496                let span = elem.span.join(rhs.span()).unwrap_or(Span::call_site());
497                Rule::Not(span, Box::new(rhs))
498            }
499            _ => unreachable!(),
500        };
501        Ok(rule)
502    }
503
504    fn postfix(&mut self, lhs: Rule, elem: WithSpan) -> pratt::Result<Rule> {
505        let rule = match elem.elem {
506            RuleElement::Optional => {
507                let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
508                Rule::Optional(span, Box::new(lhs))
509            }
510            RuleElement::Many0 => {
511                let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
512                Rule::Many0(span, Box::new(lhs))
513            }
514            RuleElement::Many1 => {
515                let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
516                Rule::Many1(span, Box::new(lhs))
517            }
518            RuleElement::Context(msg) => {
519                let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
520                Rule::Context(span, msg, Box::new(lhs))
521            }
522            _ => unreachable!(),
523        };
524        Ok(rule)
525    }
526}
527
528impl std::fmt::Display for ReturnType {
529    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
530        match self {
531            ReturnType::Option(ty) => write!(f, "Option<{}>", ty),
532            ReturnType::Vec(ty) => write!(f, "Vec<{}>", ty),
533            ReturnType::Unit => write!(f, "()"),
534            ReturnType::Unknown => write!(f, "_"),
535        }
536    }
537}
538
539impl PartialEq for ReturnType {
540    fn eq(&self, other: &ReturnType) -> bool {
541        match (self, other) {
542            (ReturnType::Option(lhs), ReturnType::Option(rhs)) => lhs == rhs,
543            (ReturnType::Vec(lhs), ReturnType::Vec(rhs)) => lhs == rhs,
544            (ReturnType::Unit, ReturnType::Unit) => true,
545            (ReturnType::Unknown, _) => true,
546            (_, ReturnType::Unknown) => true,
547            _ => false,
548        }
549    }
550}
551
552impl Rule {
553    fn check_return_type(&self) -> ReturnType {
554        match self {
555            Rule::MatchText(_, _) | Rule::MatchToken(_, _) | Rule::ExternalFunction(_, _, _) => {
556                ReturnType::Unknown
557            }
558            Rule::Context(_, _, rule) | Rule::Peek(_, rule) => rule.check_return_type(),
559            Rule::Not(_, _) => ReturnType::Unit,
560            Rule::Optional(_, rule) => ReturnType::Option(Box::new(rule.check_return_type())),
561            Rule::Cut(_, rule) => rule.check_return_type(),
562            Rule::Many0(_, rule) | Rule::Many1(_, rule) => {
563                ReturnType::Vec(Box::new(rule.check_return_type()))
564            }
565            Rule::Sequence(_, rules) => {
566                rules.iter().for_each(|rule| {
567                    rule.check_return_type();
568                });
569                ReturnType::Vec(Box::new(ReturnType::Unknown))
570            }
571            Rule::Choice(_, rules) => {
572                for slice in rules.windows(2) {
573                    match (slice[0].check_return_type(), slice[1].check_return_type()) {
574                        (ReturnType::Option(_), _) => {
575                            abort!(
576                                slice[0].span(),
577                                "optional shouldn't be in a choice because it will shortcut the following branches",
578                            )
579                        }
580                        (a, b) if a != b => abort!(
581                            slice[0]
582                                .span()
583                                .join(slice[1].span())
584                                .unwrap_or(Span::call_site()),
585                            "type mismatched between {:} and {:}",
586                            a,
587                            b,
588                        ),
589                        _ => (),
590                    }
591                }
592                ReturnType::Vec(Box::new(rules[0].check_return_type()))
593            }
594        }
595    }
596
597    fn span(&self) -> Span {
598        match self {
599            Rule::MatchText(span, _)
600            | Rule::MatchToken(span, _)
601            | Rule::ExternalFunction(span, _, _)
602            | Rule::Context(span, _, _)
603            | Rule::Peek(span, _)
604            | Rule::Not(span, _)
605            | Rule::Optional(span, _)
606            | Rule::Cut(span, _)
607            | Rule::Many0(span, _)
608            | Rule::Many1(span, _)
609            | Rule::Sequence(span, _)
610            | Rule::Choice(span, _) => *span,
611        }
612    }
613
614    fn to_tokens(&self, terminal: &CustomTerminal, tokens: &mut TokenStream) {
615        let token = match self {
616            Rule::MatchText(_, text) => {
617                let match_text = &terminal.match_text;
618                quote! { #match_text (#text) }
619            }
620            Rule::MatchToken(_, token) => {
621                let match_token = &terminal.match_token;
622                quote! { #match_token (#token) }
623            }
624            Rule::ExternalFunction(_, name, arg) => {
625                quote! { #name #arg }
626            }
627            Rule::Context(_, msg, rule) => {
628                let rule = rule.to_token_stream(terminal);
629                quote! { nom::error::context(#msg, #rule) }
630            }
631            Rule::Peek(_, rule) => {
632                let rule = rule.to_token_stream(terminal);
633                quote! { nom::combinator::peek(#rule) }
634            }
635            Rule::Not(_, rule) => {
636                let rule = rule.to_token_stream(terminal);
637                quote! { nom::combinator::not(#rule) }
638            }
639            Rule::Optional(_, rule) => {
640                let rule = rule.to_token_stream(terminal);
641                quote! { nom::combinator::opt(#rule) }
642            }
643            Rule::Cut(_, rule) => {
644                let rule = rule.to_token_stream(terminal);
645                quote! { nom::combinator::cut(#rule) }
646            }
647            Rule::Many0(_, rule) => {
648                let rule = rule.to_token_stream(terminal);
649                quote! { nom::multi::many0(#rule) }
650            }
651            Rule::Many1(_, rule) => {
652                let rule = rule.to_token_stream(terminal);
653                quote! { nom::multi::many1(#rule) }
654            }
655            Rule::Sequence(_, rules) => {
656                let list: Punctuated<TokenStream, Token![,]> = rules
657                    .iter()
658                    .map(|rule| rule.to_token_stream(terminal))
659                    .collect();
660                quote! { (#list) }
661            }
662            Rule::Choice(_, rules) => {
663                let list: Punctuated<TokenStream, Token![,]> = rules
664                    .iter()
665                    .map(|rule| rule.to_token_stream(terminal))
666                    .collect();
667                quote! { nom::branch::alt((#list)) }
668            }
669        };
670
671        tokens.extend(token);
672    }
673
674    fn to_token_stream(&self, terminal: &CustomTerminal) -> TokenStream {
675        let mut tokens = TokenStream::new();
676        self.to_tokens(terminal, &mut tokens);
677        tokens
678    }
679}
680
681impl ToTokens for Path {
682    fn to_tokens(&self, tokens: &mut TokenStream) {
683        for (i, segment) in self.segments.iter().enumerate() {
684            if i > 0 {
685                // Double colon `::`
686                tokens.append(Punct::new(':', Spacing::Joint));
687                tokens.append(Punct::new(':', Spacing::Alone));
688            }
689            segment.to_tokens(tokens);
690        }
691    }
692}