scan_rules/
macros.rs

1/*
2Copyright ⓒ 2016 Daniel Keep.
3
4Licensed under the MIT license (see LICENSE or <http://opensource.org
5/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
6<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
7files in the project carrying such notice may not be copied, modified,
8or distributed except according to those terms.
9*/
10/*!
11This module contains the public and crate-wide macros.
12*/
13
14/**
15Reads a line of text from standard input, then scans it using the provided rules.  The result of the `readln!` invocation is the type of the rule bodies; just as with `match`, all bodies must agree on their result type.
16
17Note that this macro automatically flushes standard output.  As a result, if you use this macro *while* you are holding a lock on standard output, your program will deadlock.
18
19If you wish to read from standard input whilst manually locking standard output, you should use `scan!` directly.
20
21This macro *cannot* be used to capture slices of the input; all captured values must be owned.
22
23See also: [Pattern Syntax](index.html#pattern-syntax), [`try_readln!`](macro.try_readln!.html).
24
25# Panics
26
27Panics if an error is encountered while reading from standard input, or if all rules fail to match.
28*/
29#[macro_export]
30macro_rules! readln {
31    ($($rules:tt)*) => {
32        match ::std::io::Write::flush(&mut ::std::io::stdout()) {
33            Err(err) => panic!("{:?}", err),
34            Ok(()) => {
35                let mut line = ::std::string::String::new();
36                match ::std::io::Stdin::read_line(&::std::io::stdin(), &mut line) {
37                    Err(err) => panic!("{:?}", err),
38                    Ok(_) => {
39                        let line = $crate::internal::strip_line_term(&line);
40                        match scan!(line; $($rules)*) {
41                            Err(err) => panic!("{:?}", err),
42                            Ok(v) => v,
43                        }
44                    },
45                }
46            },
47        }
48    };
49}
50
51/**
52Reads a line of text from standard input, then scans it using the provided rules.  The result of the `try_readln!` invocation is a `Result<T, ScanError>`, where `T` is the type of the rule bodies; just as with `match`, all bodies must agree on their result type.
53
54See also: [Pattern Syntax](index.html#pattern-syntax), [`readln!`](macro.readln!.html).
55*/
56#[macro_export]
57macro_rules! try_readln {
58    ($($rules:tt)*) => {
59        match ::std::io::Write::flush(&mut ::std::io::stdout()) {
60            Err(err) => Err($crate::ScanError::io(err)),
61            Ok(()) => {
62                let mut line = ::std::string::String::new();
63                match ::std::io::Stdin::read_line(&::std::io::stdin(), &mut line) {
64                    Err(err) => Err($crate::ScanError::io(err)),
65                    Ok(_) => {
66                        let line = $crate::internal::strip_line_term(&line);
67                        scan!(line; $($rules)*)
68                    },
69                }
70            },
71        }
72    };
73}
74
75/**
76Scans the provided input, using the specified pattern.  All values are bound directly to local variables.
77
78Note that this macro only supports a *single* pattern.
79
80See also: [Pattern Syntax](index.html#pattern-syntax), [`scan!`](macro.scan!.html).
81
82## Examples
83
84```rust
85# #[macro_use] extern crate scan_rules;
86# use scan_rules::scanner::Word;
87# fn main() {
88let input = "10¥, うまい棒";
89let_scan!(input; (let cost: u32, "¥,", let product: Word));
90println!("One {} costs {}¥.", product, cost);
91# }
92```
93
94## Panics
95
96Panics if the pattern fails to match.
97*/
98#[macro_export]
99macro_rules! let_scan {
100    ($input:expr; ($($pattern:tt)*)) => {
101        scan_rules_impl!(@with_bindings ($($pattern)*),
102            then: scan_rules_impl!(@let_bindings.panic $input, ($($pattern)*),);)
103    };
104}
105
106/**
107Reads a line of text from standard input, then scans it using the specified pattern.  All values are bound directly to local variables.
108
109Note that this macro only supports a *single* pattern.
110
111See also: [Pattern Syntax](index.html#pattern-syntax), [`scan!`](macro.scan!.html).
112
113## Examples
114
115```ignore
116# #[macro_use] extern crate scan_rules;
117# use scan_rules::scanner::Word;
118# fn main() {
119let_readln!((let cost: u32, "¥,", let product: Word));
120println!("One {} costs {}¥.", product, cost);
121# }
122```
123
124# Panics
125
126Panics if an error is encountered while reading from standard input, or if the pattern fails to match.
127*/
128#[cfg(macro_inter_stmt_binding_visibility)]
129#[macro_export]
130macro_rules! let_readln {
131    ($($pattern:tt)*) => {
132        let mut line = ::std::string::String::new();
133        let line = match ::std::io::Write::flush(&mut ::std::io::stdout()) {
134            Err(err) => Err($crate::ScanError::io(err)),
135            Ok(()) => {
136                match ::std::io::Stdin::read_line(&::std::io::stdin(), &mut line) {
137                    Err(err) => Err($crate::ScanError::io(err)),
138                    Ok(_) => Ok($crate::internal::strip_line_term(&line)),
139                }
140            },
141        };
142        let line = line.unwrap();
143        scan_rules_impl!(@with_bindings ($($pattern)*),
144            then: scan_rules_impl!(@let_bindings.panic line, ($($pattern)*),);)
145    };
146}
147
148/**
149Scans the provided input, using the specified rules.  The result is a `Result<T, ScanError>` where `T` is the type of the rule bodies; just as with `match`, all bodies must agree on their result type.
150
151The input may be any value which implements `IntoScanCursor`, which includes `&str`, `String`, and `Cow<str>`.
152
153See also: [Pattern Syntax](index.html#pattern-syntax).
154*/
155#[macro_export]
156macro_rules! scan {
157    ($input:expr;
158        $(($($patterns:tt)*) => $bodies:expr),+
159    ) => {
160        scan!($input; $(($($patterns)*) => $bodies,)+)
161    };
162
163    ($input:expr;
164        ($($head_pattern:tt)*) => $head_body:expr
165        , $(($($tail_patterns:tt)*) => $tail_bodies:expr,)*
166    ) => {
167        {
168            let cur = $crate::input::IntoScanCursor::into_scan_cursor($input);
169
170            let result = scan_rules_impl!(@scan (cur.clone()); ($($head_pattern)*,) => $head_body);
171
172            $(
173                let result = match result {
174                    Ok(v) => Ok(v),
175                    Err(last_err) => match scan_rules_impl!(@scan (cur.clone()); ($($tail_patterns)*,) => $tail_bodies) {
176                        Ok(v) => Ok(v),
177                        Err(new_err) => Err(last_err.furthest_along(new_err))
178                    }
179                };
180            )*
181
182            result
183        }
184    };
185}
186
187#[doc(hidden)]
188#[macro_export]
189macro_rules! scan_rules_impl {
190    /*
191
192    # `@scan` - parse scan pattern.
193
194    */
195
196    /*
197    ## Termination rule.
198    */
199    (@scan ($cur:expr); () => $body:expr) => {
200        {
201            match $crate::input::ScanCursor::try_end($cur) {
202                Ok(()) => Ok($body),
203                Err((err, _)) => Err(err)
204            }
205        }
206    };
207
208    /*
209    ## Tail capture.
210    */
211    (@scan ($cur:expr); (.._,) => $body:expr) => {
212        {
213            match $crate::input::ScanCursor::try_scan_raw(
214                $cur,
215                |s| {
216                    let s = $crate::input::ScanInput::as_str(&s);
217                    Ok::<_, $crate::ScanError>((s, s.len()))
218                }
219            ) {
220                Ok((_, new_cur)) => scan_rules_impl!(@scan (new_cur); () => $body),
221                Err((err, _)) => Err(err)
222            }
223        }
224    };
225
226    (@scan ($cur:expr); (..$name:ident,) => $body:expr) => {
227        {
228            match $crate::input::ScanCursor::try_scan_raw(
229                $cur,
230                |s| {
231                    let s = $crate::input::ScanInput::as_str(&s);
232                    Ok::<_, $crate::ScanError>((s, s.len()))
233                }
234            ) {
235                Ok(($name, new_cur)) => scan_rules_impl!(@scan (new_cur); () => $body),
236                Err((err, _)) => Err(err)
237            }
238        }
239    };
240
241    /*
242    ## Anchor capture.
243    */
244    (@scan ($cur:expr); (^..$name:ident,) => $body:expr) => {
245        {
246            let $name = $cur;
247            Ok($body)
248        }
249    };
250
251    /*
252    ## Value capture.
253    */
254    (@scan ($cur:expr); (let _: $t:ty, $($tail:tt)*) => $body:expr) => {
255        {
256            match $crate::internal::try_scan_static::<_, $t>($cur) {
257                Ok((_, new_cur)) => scan_rules_impl!(@scan (new_cur); ($($tail)*) => $body),
258                Err((err, _)) => Err(err)
259            }
260        }
261    };
262
263    (@scan ($cur:expr); (let _ <| $s:expr, $($tail:tt)*) => $body:expr) => {
264        {
265            match $crate::internal::try_scan_runtime($cur, &mut $s) {
266                Ok((_, new_cur)) => scan_rules_impl!(@scan (new_cur); ($($tail)*) => $body),
267                Err((err, _)) => Err(err)
268            }
269        }
270    };
271
272    (@scan ($cur:expr); (let $name:ident, $($tail:tt)*) => $body:expr) => {
273        {
274            match $crate::internal::try_scan_static_self($cur) {
275                Ok(($name, new_cur)) => scan_rules_impl!(@scan (new_cur); ($($tail)*) => $body),
276                Err((err, _)) => Err(err)
277            }
278        }
279    };
280
281    (@scan ($cur:expr); (let $name:ident: $t:ty, $($tail:tt)*) => $body:expr) => {
282        {
283            match $crate::internal::try_scan_static::<_, $t>($cur) {
284                Ok(($name, new_cur)) => scan_rules_impl!(@scan (new_cur); ($($tail)*) => $body),
285                Err((err, _)) => Err(err)
286            }
287        }
288    };
289
290    (@scan ($cur:expr); (let $name:ident <| $s:expr, $($tail:tt)*) => $body:expr) => {
291        {
292            match $crate::internal::try_scan_runtime($cur, &mut $s) {
293                Ok(($name, new_cur)) => scan_rules_impl!(@scan (new_cur); ($($tail)*) => $body),
294                Err((err, _)) => Err(err)
295            }
296        }
297    };
298
299    /*
300    ## Repeating entry.
301
302    This is a *tremendous* discomfort in the posterior.  Without alternation, the only way to get the desired syntax is to exhaustively *list* the various combinations, recursing into another invocation to normalise everything.
303
304    It's a small miracle that the ascription syntax works, though I daresay any user who accidentally types `[...]*: T: U` is going to be *very* confused.
305
306    The next few sections are divided first by separator, then by repetition count control.
307    */
308    /*
309    ### No separator.
310    */
311    (@scan ($cur:expr); ([$($pat:tt)*]? $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
312        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {0, Some(1)}, ($($col_ty)*); ($($tail)*) => $body)
313    };
314
315    (@scan ($cur:expr); ([$($pat:tt)*]* $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
316        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {0, None}, ($($col_ty)*); ($($tail)*) => $body)
317    };
318
319    (@scan ($cur:expr); ([$($pat:tt)*]+ $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
320        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {1, None}, ($($col_ty)*); ($($tail)*) => $body)
321    };
322
323    (@scan ($cur:expr); ([$($pat:tt)*]{,$max:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
324        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {0, Some($max)}, ($($col_ty)*); ($($tail)*) => $body)
325    };
326
327    (@scan ($cur:expr); ([$($pat:tt)*]{$n:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
328        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {$n, Some($n)}, ($($col_ty)*); ($($tail)*) => $body)
329    };
330
331    (@scan ($cur:expr); ([$($pat:tt)*]{$min:expr,} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
332        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {$min, None}, ($($col_ty)*); ($($tail)*) => $body)
333    };
334
335    (@scan ($cur:expr); ([$($pat:tt)*]{$min:expr, $max:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
336        scan_rules_impl!(@repeat ($cur), [$($pat)*], (), {$min, Some($max)}, ($($col_ty)*); ($($tail)*) => $body)
337    };
338
339    /*
340    ### Comma separator.
341    */
342    (@scan ($cur:expr); ([$($pat:tt)*],? $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
343        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {0, Some(1)}, ($($col_ty)*); ($($tail)*) => $body)
344    };
345
346    (@scan ($cur:expr); ([$($pat:tt)*],* $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
347        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {0, None}, ($($col_ty)*); ($($tail)*) => $body)
348    };
349
350    (@scan ($cur:expr); ([$($pat:tt)*],+ $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
351        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {1, None}, ($($col_ty)*); ($($tail)*) => $body)
352    };
353
354    (@scan ($cur:expr); ([$($pat:tt)*],{,$max:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
355        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {0, Some($max)}, ($($col_ty)*); ($($tail)*) => $body)
356    };
357
358    (@scan ($cur:expr); ([$($pat:tt)*],{$n:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
359        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {$n, Some($n)}, ($($col_ty)*); ($($tail)*) => $body)
360    };
361
362    (@scan ($cur:expr); ([$($pat:tt)*],{$min:expr,} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
363        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {$min, None}, ($($col_ty)*); ($($tail)*) => $body)
364    };
365
366    (@scan ($cur:expr); ([$($pat:tt)*],{$min:expr, $max:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
367        scan_rules_impl!(@repeat ($cur), [$($pat)*], (","), {$min, Some($max)}, ($($col_ty)*); ($($tail)*) => $body)
368    };
369
370    /*
371    ### Sub-pattern separator.
372    */
373    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*)? $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
374        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {0, Some(1)}, ($($col_ty)*); ($($tail)*) => $body)
375    };
376
377    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*)* $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
378        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {0, None}, ($($col_ty)*); ($($tail)*) => $body)
379    };
380
381    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*)+ $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
382        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {1, None}, ($($col_ty)*); ($($tail)*) => $body)
383    };
384
385    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*){,$max:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
386        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {0, Some($max)}, ($($col_ty)*); ($($tail)*) => $body)
387    };
388
389    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*){$n:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
390        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {$n, Some($n)}, ($($col_ty)*); ($($tail)*) => $body)
391    };
392
393    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*){$min:expr,} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
394        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {$min, None}, ($($col_ty)*); ($($tail)*) => $body)
395    };
396
397    (@scan ($cur:expr); ([$($pat:tt)*]($($sep:tt)*){$min:expr, $max:expr} $(: $col_ty:ty)*, $($tail:tt)*) => $body:expr) => {
398        scan_rules_impl!(@repeat ($cur), [$($pat)*], ($($sep)*), {$min, Some($max)}, ($($col_ty)*); ($($tail)*) => $body)
399    };
400
401    /*
402    ## Literal match.
403    */
404    (@scan ($cur:expr); ($lit:expr, $($tail:tt)*) => $body:expr) => {
405        match $crate::input::ScanCursor::try_match_literal($cur, $lit) {
406            Ok(new_cur) => scan_rules_impl!(@scan (new_cur); ($($tail)*) => $body),
407            Err((err, _)) => Err(err)
408        }
409    };
410
411    /*
412
413    # `@repeat` - Repetition expansion.
414
415    The first step here is to handle a missing `$col_ty` by replacing it with `Vec<_>`.  We delegate to `.with_col_ty` to handle the rest.
416
417    */
418    (@repeat ($cur:expr),
419        [$($pat:tt)*], ($($sep:tt)*), {$min:expr, $max:expr}, ();
420        $($tail:tt)*
421    ) => {
422        scan_rules_impl!(@repeat.with_col_ty ($cur), [$($pat)*], ($($sep)*), {$min, $max}, Vec<_>; $($tail)*)
423    };
424
425    (@repeat ($cur:expr),
426        [$($pat:tt)*], ($($sep:tt)*), {$min:expr, $max:expr}, ($col_ty:ty);
427        $($tail:tt)*
428    ) => {
429        scan_rules_impl!(@repeat.with_col_ty ($cur), [$($pat)*], ($($sep)*), {$min, $max}, $col_ty; $($tail)*)
430    };
431
432    /*
433    ## `.with_col_ty`
434
435    This handles the bulk of the repetition expansion.  The only somewhat obtuse part is how captures are handled: we have to define a collection to hold every value captured in both the repeating and separator sub-patterns.
436
437    This will go rather *poorly* if someone is silly enough to use the same name more than once... but then, that's a bad idea in general.
438    */
439    (@repeat.with_col_ty ($cur:expr),
440        [$($pat:tt)*], ($($sep:tt)*), {$min:expr, $max:expr}, $col_ty:ty;
441        $($tail:tt)*
442    ) => {
443        {
444            let mut cur = $cur;
445            let mut repeats: usize = 0;
446            let min: usize = $min;
447            let max: ::std::option::Option<usize> = $max;
448            scan_rules_impl!(@with_bindings ($($pat)*), then: scan_rules_impl!(@repeat.define_cols $col_ty,););
449            scan_rules_impl!(@with_bindings ($($sep)*), then: scan_rules_impl!(@repeat.define_cols $col_ty,););
450
451            match (min, max) {
452                (a, Some(b)) if a > b => panic!("assertion failed: `(min <= max)` (min: `{:?}`, max: `{:?}`)", a, b),
453                _ => ()
454            }
455
456            // If we broke out of the loop due to a scanning error, what was it?
457            let mut break_err: Option<$crate::ScanError> = None;
458
459            // Did we break due to a scanning error *after* having successfully scanned a separator?
460            let mut break_after_sep: bool;
461
462            loop {
463                // Doing this here prevents an "does not need to be mut" warning.
464                break_after_sep = false;
465
466                match max {
467                    ::std::option::Option::Some(max) if max == repeats => break,
468                    _ => ()
469                }
470
471                // Handle the separator pattern, if there is one.
472                scan_rules_impl!(@if_empty.expr ($($sep)*) {
473                    () // Do nothing.
474                } else {
475                    if repeats > 0 {
476                        match scan_rules_impl!(@scan (cur.clone());
477                            ($($sep)*, ^..after,) => {
478                                cur = after;
479                                scan_rules_impl!(@with_bindings ($($sep)*), then: scan_rules_impl!(@repeat.tuple))
480                            }
481                        ) {
482                            ::std::result::Result::Ok(elems) => {
483                                // See below about black-holing.
484                                let _ = elems.0;
485                                scan_rules_impl!(@with_bindings ($($sep)*), then: scan_rules_impl!(@repeat.push elems,););
486                            },
487                            ::std::result::Result::Err(err) => {
488                                break_err = Some(err);
489                                break;
490                            }
491                        }
492                    }
493                });
494
495                // Scan the repeating pattern.
496                match scan_rules_impl!(@scan (cur.clone());
497                    ($($pat)*, ^..after,) => {
498                        cur = after;
499                        scan_rules_impl!(@with_bindings ($($pat)*), then: scan_rules_impl!(@repeat.tuple))
500                    }
501                ) {
502                    ::std::result::Result::Ok(elems) => {
503                        // Black-hole the first element to stop Rust from complaining when there are no captures.
504                        let _ = elems.0;
505                        scan_rules_impl!(@with_bindings ($($pat)*), then: scan_rules_impl!(@repeat.push elems,););
506                        repeats += 1;
507                    },
508                    ::std::result::Result::Err(err) => {
509                        scan_rules_impl!(@if_empty.expr ($($sep)*) {
510                            () // Do nothing
511                        } else {
512                            break_after_sep = repeats > 0
513                        });
514                        break_err = Some(err);
515                        break;
516                    }
517                }
518            }
519
520            if repeats < min || break_after_sep {
521                // Evaluate to the last error because *either* we didn't get enough elements, *or* because we found a separator that wasn't followed by a match.
522                Err(break_err.unwrap())
523            } else {
524                scan_rules_impl!(@scan (cur); $($tail)*)
525            }
526        }
527    };
528
529    /*
530    ## `.define_cols`
531
532    Define the collections that repeating variables will be collected into.
533    */
534    (@repeat.define_cols $col_ty:ty, $(($names:ident, $_idxs:expr),)*) => {
535        $(
536            let mut $names: $col_ty = ::std::default::Default::default();
537        )*
538    };
539
540    /*
541    ## `.tuple`
542
543    Define a tuple expression that contains the names of the repeating variables.
544
545    The first element is *always* `()` so we can explicitly drop it to avoid unused variable warnings.
546    */
547    (@repeat.tuple $(($names:ident, $_idxs:expr),)*) => {
548        ((), $($names,)*)
549    };
550
551    /*
552    ## `.push`
553
554    Push captured values into their respective collections.
555    */
556    (@repeat.push $elems:expr, $(($names:ident, $idxs:tt),)*) => {
557        $(
558            ::std::iter::Extend::extend(
559                &mut $names,
560                ::std::iter::once(scan_rules_impl!(@as_expr $elems.$idxs))
561            );
562        )*
563    };
564
565    /*
566
567    # `@let_bindings`
568
569    This is a callback designed to continue from `@with_bindings`.  It takes the list of binding names, and defines local variables for them, and sets up the pattern body to return them.
570
571    */
572
573    (@let_bindings.panic $input:expr, $pattern:tt, $(($ns:ident, $_is:tt),)*) => {
574        scan_rules_impl!(
575            @as_stmt
576            let ($($ns,)*) = match $input {
577                input => match scan!(&input[..]; $pattern => ($($ns,)*)) {
578                    Ok(vs) => vs,
579                    Err(err) => panic!("error while scanning `{:?}`: {}", input, err)
580                }
581            }
582        );
583    };
584
585    /*
586
587    # `@with_bindings` - Extract all binding names from pattern.
588
589    The callback will be invoked with `(a, 1), (x, 2), (vvv, 3), ...,` appended to the argument.  This will be a list of every binding name in the pattern in lexical order, plus a matching ordinal.
590
591    **Note**: The first element of the tuple will be a `()` which we can explicitly drop to avoid unused variable warnings.  As such, the index counter starts at `1`, not `0`.
592
593    **Note**: tail and anchor captures aren't valid inside repeats, so they are *not* handled by this macro.
594
595    */
596    (@with_bindings ($($pat:tt)*), then: $cb_name:ident!$cb_arg:tt) => {
597        scan_rules_impl!(@with_bindings.step 1, (), ($cb_name $cb_arg); $($pat)*,)
598    };
599
600    (@with_bindings ($($pat:tt)*), then: $cb_name:ident!$cb_arg:tt;) => {
601        scan_rules_impl!(@with_bindings.step 1, (), ($cb_name $cb_arg;); $($pat)*,)
602    };
603
604    /*
605    ## `.step`
606
607    Step over the next part of the pattern.  If it has a binding, extract it and increment `$i`.
608
609    If there's nothing left in the input, invoke the callback.
610    */
611    (@with_bindings.step
612        $_i:expr,
613        ($($names:tt)*),
614        ($cb_name:ident ($($cb_args:tt)*)); $(,)*
615    ) => {
616        scan_rules_impl!(@as_expr $cb_name!($($cb_args)* $($names)*))
617    };
618
619    (@with_bindings.step
620        $_i:expr,
621        ($($names:tt)*),
622        ($cb_name:ident ($($cb_args:tt)*);); $(,)*
623    ) => {
624        scan_rules_impl!(@as_stmt $cb_name!($($cb_args)* $($names)*))
625    };
626
627    (@with_bindings.step $i:tt, $names:tt, $cb:tt; let _: $_ty:ty, $($tail:tt)*) => {
628        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($tail)*)
629    };
630
631    (@with_bindings.step $i:tt, $names:tt, $cb:tt; let _ <| $_s:expr, $($tail:tt)*) => {
632        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($tail)*)
633    };
634
635    (@with_bindings.step $i:tt, ($($names:tt)*), $cb:tt; let $name:ident, $($tail:tt)*) => {
636        scan_rules_impl!(@with_bindings.inc $i, ($($names)* ($name, $i),), $cb; $($tail)*)
637    };
638
639    (@with_bindings.step $i:tt, ($($names:tt)*), $cb:tt; let $name:ident: $_ty:ty, $($tail:tt)*) => {
640        scan_rules_impl!(@with_bindings.inc $i, ($($names)* ($name, $i),), $cb; $($tail)*)
641    };
642
643    (@with_bindings.step $i:tt, ($($names:tt)*), $cb:tt; let $name:ident <| $_s:expr, $($tail:tt)*) => {
644        scan_rules_impl!(@with_bindings.inc $i, ($($names)* ($name, $i),), $cb; $($tail)*)
645    };
646
647    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]? $(: $col_ty:ty)*, $($tail:tt)*) => {
648        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
649    };
650
651    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]* $(: $col_ty:ty)*, $($tail:tt)*) => {
652        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
653    };
654
655    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]+ $(: $col_ty:ty)*, $($tail:tt)*) => {
656        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
657    };
658
659    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]{$($_bounds:tt)*} $(: $col_ty:ty)*, $($tail:tt)*) => {
660        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
661    };
662
663    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*],? $(: $col_ty:ty)*, $($tail:tt)*) => {
664        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
665    };
666
667    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*],* $(: $col_ty:ty)*, $($tail:tt)*) => {
668        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
669    };
670
671    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*],+ $(: $col_ty:ty)*, $($tail:tt)*) => {
672        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
673    };
674
675    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*],{$($_bounds:tt)*} $(: $col_ty:ty)*, $($tail:tt)*) => {
676        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($tail)*)
677    };
678
679    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]($($sep:tt)*)? $(: $col_ty:ty)*, $($tail:tt)*) => {
680        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($sep)*, $($tail)*)
681    };
682
683    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]($($sep:tt)*)* $(: $col_ty:ty)*, $($tail:tt)*) => {
684        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($sep)*, $($tail)*)
685    };
686
687    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]($($sep:tt)*)+ $(: $col_ty:ty)*, $($tail:tt)*) => {
688        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($sep)*, $($tail)*)
689    };
690
691    (@with_bindings.step $i:tt, $names:tt, $cb:tt; [$($pat:tt)*]($($sep:tt)*){$($_bounds:tt)*} $(: $col_ty:ty)*, $($tail:tt)*) => {
692        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($pat)*, $($sep)*, $($tail)*)
693    };
694
695    (@with_bindings.step $i:tt, $names:tt, $cb:tt; $_lit:expr, $($tail:tt)*) => {
696        scan_rules_impl!(@with_bindings.step $i, $names, $cb; $($tail)*)
697    };
698
699    /*
700    ## `.inc`
701
702    Increment the index counter.  Because `macro_rules!` is stupid, this is *very* limited in how many identifiers can be transitively within a repeating pattern.
703    */
704    (@with_bindings.inc  1, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  2, $($tail)*) };
705    (@with_bindings.inc  2, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  3, $($tail)*) };
706    (@with_bindings.inc  3, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  4, $($tail)*) };
707    (@with_bindings.inc  4, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  5, $($tail)*) };
708    (@with_bindings.inc  5, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  6, $($tail)*) };
709    (@with_bindings.inc  6, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  7, $($tail)*) };
710    (@with_bindings.inc  7, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  8, $($tail)*) };
711    (@with_bindings.inc  8, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step  9, $($tail)*) };
712    (@with_bindings.inc  9, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 10, $($tail)*) };
713    (@with_bindings.inc 10, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 11, $($tail)*) };
714    (@with_bindings.inc 11, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 12, $($tail)*) };
715    (@with_bindings.inc 12, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 13, $($tail)*) };
716    (@with_bindings.inc 13, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 14, $($tail)*) };
717    (@with_bindings.inc 14, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 15, $($tail)*) };
718    (@with_bindings.inc 15, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 16, $($tail)*) };
719    (@with_bindings.inc 16, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 17, $($tail)*) };
720    (@with_bindings.inc 17, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 18, $($tail)*) };
721    (@with_bindings.inc 18, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 19, $($tail)*) };
722    (@with_bindings.inc 19, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 20, $($tail)*) };
723    (@with_bindings.inc 20, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 21, $($tail)*) };
724    (@with_bindings.inc 21, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 22, $($tail)*) };
725    (@with_bindings.inc 22, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 23, $($tail)*) };
726    (@with_bindings.inc 23, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 24, $($tail)*) };
727    (@with_bindings.inc 24, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 25, $($tail)*) };
728    (@with_bindings.inc 25, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 26, $($tail)*) };
729    (@with_bindings.inc 26, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 27, $($tail)*) };
730    (@with_bindings.inc 27, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 28, $($tail)*) };
731    (@with_bindings.inc 28, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 29, $($tail)*) };
732    (@with_bindings.inc 29, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 30, $($tail)*) };
733    (@with_bindings.inc 30, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 31, $($tail)*) };
734    (@with_bindings.inc 31, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 32, $($tail)*) };
735    (@with_bindings.inc 32, $($tail:tt)*) => { scan_rules_impl!(@with_bindings.step 33, $($tail)*) };
736
737    /*
738
739    # Miscellaneous
740
741    */
742    (@as_expr $e:expr) => {$e};
743    (@as_stmt $s:stmt) => {$s;};
744
745    (@if_empty.expr () {$($th:tt)*} else {$($_el:tt)*}) => {
746        scan_rules_impl!(@as_expr $($th)*)
747    };
748
749    (@if_empty.expr ($($_tts:tt)+) {$($_th:tt)*} else {$($el:tt)*}) => {
750        scan_rules_impl!(@as_expr $($el)*)
751    };
752}