Skip to main content

parse_that/
combinators.rs

1use std::ops::RangeBounds;
2
3use crate::parse::Parser;
4use crate::state::ParserState;
5use crate::utils::extract_bounds;
6
7impl<'a, Output> Parser<'a, Output>
8where
9    Self: 'a,
10    Output: 'a,
11{
12    #[inline]
13    pub fn then<Output2>(self, next: Parser<'a, Output2>) -> Parser<'a, (Output, Output2)>
14    where
15        Output2: 'a,
16    {
17        let with = move |state: &mut ParserState<'a>| {
18            let value1 = self.call(state)?;
19            let value2 = next.call(state)?;
20            Some((value1, value2))
21        };
22        Parser::new(with)
23    }
24
25    /// Alternation with checkpoint-based backtracking (no Vec push/pop).
26    #[inline]
27    pub fn or(self, other: Parser<'a, Output>) -> Parser<'a, Output> {
28        let or = move |state: &mut ParserState<'a>| {
29            let checkpoint = state.offset;
30            if let Some(value) = self.call(state) {
31                return Some(value);
32            }
33            state.furthest_offset = state.furthest_offset.max(state.offset);
34            state.offset = checkpoint;
35
36            if let Some(value) = other.call(state) {
37                return Some(value);
38            }
39            state.furthest_offset = state.furthest_offset.max(state.offset);
40            state.offset = checkpoint;
41
42            None
43        };
44        Parser::new(or)
45    }
46
47    #[inline]
48    pub fn or_else(self, f: fn() -> Output) -> Parser<'a, Output> {
49        let or_else = move |state: &mut ParserState<'a>| match self.call(state) {
50            Some(value) => Some(value),
51            None => Some(f()),
52        };
53        Parser::new(or_else)
54    }
55
56    #[inline]
57    pub fn opt(self) -> Parser<'a, Option<Output>> {
58        let opt = move |state: &mut ParserState<'a>| {
59            if let Some(value) = self.call(state) {
60                return Some(Some(value));
61            }
62            Some(None)
63        };
64        Parser::new(opt)
65    }
66
67    /// Consuming negative lookahead: parse `self`, then check that `next` does
68    /// NOT match at the resulting position. If `next` matches, the overall
69    /// parse fails. Unlike `negate()` (zero-width), `not()` consumes the input
70    /// matched by `self` on success.
71    #[inline]
72    pub fn not<Output2>(self, next: Parser<'a, Output2>) -> Parser<'a, Output>
73    where
74        Output2: 'a,
75    {
76        let not = move |state: &mut ParserState<'a>| {
77            let value = self.call(state)?;
78            let checkpoint = state.offset;
79            let saved_furthest = state.furthest_offset;
80            if next.call(state).is_none() {
81                state.offset = checkpoint;
82                state.furthest_offset = saved_furthest;
83                return Some(value);
84            }
85            state.offset = checkpoint;
86            state.furthest_offset = saved_furthest;
87            None
88        };
89        Parser::new(not)
90    }
91
92    /// Set difference: match `self` only if `excluded` would NOT match at the
93    /// same starting position. Used for EBNF/BNF exception (`-`) semantics.
94    #[inline]
95    pub fn minus<Output2>(self, excluded: Parser<'a, Output2>) -> Parser<'a, Output>
96    where
97        Output2: 'a,
98    {
99        let minus = move |state: &mut ParserState<'a>| {
100            let checkpoint = state.offset;
101            let saved_furthest = state.furthest_offset;
102            if excluded.call(state).is_some() {
103                state.offset = checkpoint;
104                state.furthest_offset = saved_furthest;
105                return None;
106            }
107            state.offset = checkpoint;
108            state.furthest_offset = saved_furthest;
109            self.call(state)
110        };
111        Parser::new(minus)
112    }
113
114    /// Zero-width negative assertion: succeeds (returning `()`) when the inner
115    /// parser *fails*, and fails when the inner parser *succeeds*. Does not
116    /// consume any input in either case.
117    #[inline]
118    pub fn negate(self) -> Parser<'a, ()> {
119        let negate = move |state: &mut ParserState<'a>| {
120            let checkpoint = state.offset;
121            let saved_furthest = state.furthest_offset;
122            if self.call(state).is_none() {
123                state.offset = checkpoint;
124                state.furthest_offset = saved_furthest;
125                return Some(());
126            }
127            state.offset = checkpoint;
128            state.furthest_offset = saved_furthest;
129            None
130        };
131        Parser::new(negate)
132    }
133
134    #[inline]
135    pub fn map<Output2>(self, f: fn(Output) -> Output2) -> Parser<'a, Output2>
136    where
137        Output2: 'a,
138    {
139        let map = move |state: &mut ParserState<'a>| self.call(state).map(f);
140        Parser::new(map)
141    }
142
143    #[inline]
144    pub fn map_with_state<Output2>(
145        self,
146        f: fn(Output, usize, &mut ParserState<'a>) -> Output2,
147    ) -> Parser<'a, Output2>
148    where
149        Output2: 'a,
150    {
151        let map_with_state = move |state: &mut ParserState<'a>| {
152            let offset = state.offset;
153            let result = self.call(state)?;
154            Some(f(result, offset, state))
155        };
156        Parser::new(map_with_state)
157    }
158
159    #[inline]
160    pub fn skip<Output2>(self, next: Parser<'a, Output2>) -> Parser<'a, Output>
161    where
162        Output2: 'a,
163    {
164        let skip = move |state: &mut ParserState<'a>| {
165            let value = self.call(state)?;
166            next.call(state)?;
167            Some(value)
168        };
169        Parser::new(skip)
170    }
171
172    #[inline]
173    pub fn next<Output2>(self, next: Parser<'a, Output2>) -> Parser<'a, Output2>
174    where
175        Output2: 'a,
176    {
177        let next = move |state: &mut ParserState<'a>| {
178            self.call(state)?;
179            next.call(state)
180        };
181        Parser::new(next)
182    }
183
184    #[inline]
185    pub fn many(self, bounds: impl RangeBounds<usize> + 'a) -> Parser<'a, Vec<Output>> {
186        let (lower_bound, upper_bound) = extract_bounds(bounds);
187
188        let many = move |state: &mut ParserState<'a>| {
189            let est = if lower_bound > 0 { lower_bound.max(16) } else { 32 };
190            let mut values = Vec::with_capacity(est);
191
192            while values.len() < upper_bound {
193                if let Some(value) = self.call(state) {
194                    values.push(value);
195                } else {
196                    break;
197                }
198            }
199            if values.len() >= lower_bound {
200                Some(values)
201            } else {
202                None
203            }
204        };
205
206        Parser::new(many)
207    }
208
209    #[inline]
210    pub fn wrap<Output2, Output3>(
211        self,
212        left: Parser<'a, Output2>,
213        right: Parser<'a, Output3>,
214    ) -> Parser<'a, Output>
215    where
216        Output2: 'a,
217        Output3: 'a,
218    {
219        let wrap = move |state: &mut ParserState<'a>| {
220            #[cfg(feature = "diagnostics")]
221            let open_offset = state.offset;
222            left.call(state)?;
223            #[cfg(feature = "diagnostics")]
224            let open_end = state.offset;
225            let value = self.call(state)?;
226            if right.call(state).is_some() {
227                Some(value)
228            } else {
229                #[cfg(feature = "diagnostics")]
230                {
231                    let delimiter = state.src[open_offset..open_end].to_string();
232                    state.add_suggestion(|| crate::state::Suggestion {
233                        kind: crate::state::SuggestionKind::UnclosedDelimiter {
234                            delimiter: delimiter.clone(),
235                            open_offset,
236                        },
237                        message: format!(
238                            "close the delimiter with matching `{}`",
239                            match delimiter.as_str() {
240                                "{" => "}",
241                                "[" => "]",
242                                "(" => ")",
243                                d => d,
244                            }
245                        ),
246                    });
247                    state.add_secondary_span(
248                        open_offset,
249                        format!("unclosed `{}` opened here", delimiter),
250                    );
251                }
252                None
253            }
254        };
255        Parser::new(wrap)
256    }
257
258    #[inline]
259    pub fn trim<Output2>(self, trimmer: Parser<'a, Output2>) -> Parser<'a, Output>
260    where
261        Output2: 'a,
262    {
263        let trim = move |state: &mut ParserState<'a>| {
264            trimmer.call(state)?;
265            let value = self.call(state)?;
266            trimmer.call(state)?;
267            Some(value)
268        };
269        Parser::new(trim)
270    }
271
272    #[inline]
273    pub fn trim_keep<Output2>(
274        self,
275        trimmer: Parser<'a, Output2>,
276    ) -> Parser<'a, (Output2, Output, Output2)>
277    where
278        Output2: 'a,
279    {
280        let trim = move |state: &mut ParserState<'a>| {
281            let trim1 = trimmer.call(state)?;
282            let value = self.call(state)?;
283            let trim2 = trimmer.call(state)?;
284            Some((trim1, value, trim2))
285        };
286        Parser::new(trim)
287    }
288
289    /// Strictly interleaving: `elem (sep elem)*`. Never accepts a trailing
290    /// separator — trailing sep acceptance is a grammar concern.
291    #[inline]
292    pub fn sep_by<Output2>(
293        self,
294        sep: Parser<'a, Output2>,
295        bounds: impl RangeBounds<usize> + 'a,
296    ) -> Parser<'a, Vec<Output>>
297    where
298        Output2: 'a,
299    {
300        let (lower_bound, upper_bound) = extract_bounds(bounds);
301
302        let sep_by = move |state: &mut ParserState<'a>| {
303            let est = if lower_bound > 0 { lower_bound.max(16) } else { 32 };
304            let mut values = Vec::with_capacity(est);
305
306            // Parse first element
307            if let Some(value) = self.call(state) {
308                values.push(value);
309            } else if lower_bound == 0 {
310                return Some(values);
311            } else {
312                return None;
313            }
314
315            // Parse (sep elem)* — checkpoint before separator so trailing
316            // separators are rejected by restoring state.
317            while values.len() < upper_bound {
318                let cp = state.offset;
319                if sep.call(state).is_none() {
320                    state.offset = cp;
321                    break;
322                }
323                if let Some(value) = self.call(state) {
324                    values.push(value);
325                } else {
326                    // Element after separator failed — backtrack past the
327                    // separator to reject the trailing separator.
328                    state.offset = cp;
329                    break;
330                }
331            }
332
333            if values.len() >= lower_bound {
334                Some(values)
335            } else {
336                None
337            }
338        };
339
340        Parser::new(sep_by)
341    }
342
343    /// Error recovery combinator. On success, returns the result normally.
344    /// On failure, snapshots the current diagnostic into the collected
345    /// diagnostics list, then runs `sync` to skip past the bad content
346    /// and returns `sentinel`.
347    ///
348    /// This enables `many()` / `sep_by()` loops to keep going — each failed
349    /// element produces a diagnostic but doesn't halt the overall parse.
350    #[cfg(feature = "diagnostics")]
351    pub fn recover(self, sync: Parser<'a, ()>, sentinel: Output) -> Parser<'a, Output>
352    where
353        Output: Clone,
354    {
355        use crate::state::{push_diagnostic, pop_last_diagnostic};
356
357        let recover = move |state: &mut ParserState<'a>| {
358            let checkpoint = state.offset;
359            if let Some(value) = self.call(state) {
360                return Some(value);
361            }
362
363            // Snapshot diagnostic, then try to sync forward
364            let diag = state.snapshot_diagnostic(checkpoint);
365            push_diagnostic(diag);
366
367            state.offset = checkpoint;
368            if sync.call(state).is_some() {
369                // Sync succeeded — return sentinel
370                Some(sentinel.clone())
371            } else {
372                // Sync failed — pop the diagnostic and give up
373                pop_last_diagnostic();
374                state.offset = checkpoint;
375                None
376            }
377        };
378        Parser::new(recover)
379    }
380
381    /// No-op version without diagnostics feature — just runs the inner parser.
382    #[cfg(not(feature = "diagnostics"))]
383    pub fn recover(self, _sync: Parser<'a, ()>, _sentinel: Output) -> Parser<'a, Output>
384    where
385        Output: Clone,
386    {
387        self
388    }
389
390    #[inline]
391    pub fn look_ahead<Output2>(self, parser: Parser<'a, Output2>) -> Parser<'a, Output>
392    where
393        Output2: 'a,
394    {
395        let look_ahead = move |state: &mut ParserState<'a>| {
396            let value = self.call(state)?;
397            let offset_after_self = state.offset;
398            let lookahead_result = parser.call(state);
399            state.offset = offset_after_self;
400            lookahead_result?;
401            Some(value)
402        };
403        Parser::new(look_ahead)
404    }
405}
406
407impl<'a, Output2> std::ops::BitOr<Parser<'a, Output2>> for Parser<'a, Output2>
408where
409    Output2: 'a,
410{
411    type Output = Parser<'a, Output2>;
412
413    #[inline]
414    fn bitor(self, other: Parser<'a, Output2>) -> Self::Output {
415        self.or(other)
416    }
417}
418
419impl<'a, Output, Output2> std::ops::Add<Parser<'a, Output2>> for Parser<'a, Output>
420where
421    Output: 'a,
422    Output2: 'a,
423{
424    type Output = Parser<'a, (Output, Output2)>;
425
426    #[inline]
427    fn add(self, other: Parser<'a, Output2>) -> Self::Output {
428        self.then(other)
429    }
430}
431
432#[path = "span_trait.rs"]
433mod span_trait;
434pub use span_trait::*;
435
436// ── seq!: flat N-ary sequential combinator ────────────────────
437// Creates a single Box<dyn ParserFn> instead of N-1 intermediate boxes.
438// Usage: seq!(p1, p2) → Parser<(O1, O2)>, seq!(p1, p2, p3) → Parser<(O1, O2, O3)>, etc.
439
440#[macro_export]
441macro_rules! seq {
442    ($p1:expr, $p2:expr) => {
443        $crate::Parser::new(move |state| {
444            let v1 = $p1.call(state)?;
445            let v2 = $p2.call(state)?;
446            Some((v1, v2))
447        })
448    };
449    ($p1:expr, $p2:expr, $p3:expr) => {
450        $crate::Parser::new(move |state| {
451            let v1 = $p1.call(state)?;
452            let v2 = $p2.call(state)?;
453            let v3 = $p3.call(state)?;
454            Some((v1, v2, v3))
455        })
456    };
457    ($p1:expr, $p2:expr, $p3:expr, $p4:expr) => {
458        $crate::Parser::new(move |state| {
459            let v1 = $p1.call(state)?;
460            let v2 = $p2.call(state)?;
461            let v3 = $p3.call(state)?;
462            let v4 = $p4.call(state)?;
463            Some((v1, v2, v3, v4))
464        })
465    };
466    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr) => {
467        $crate::Parser::new(move |state| {
468            let v1 = $p1.call(state)?;
469            let v2 = $p2.call(state)?;
470            let v3 = $p3.call(state)?;
471            let v4 = $p4.call(state)?;
472            let v5 = $p5.call(state)?;
473            Some((v1, v2, v3, v4, v5))
474        })
475    };
476    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr, $p6:expr) => {
477        $crate::Parser::new(move |state| {
478            let v1 = $p1.call(state)?;
479            let v2 = $p2.call(state)?;
480            let v3 = $p3.call(state)?;
481            let v4 = $p4.call(state)?;
482            let v5 = $p5.call(state)?;
483            let v6 = $p6.call(state)?;
484            Some((v1, v2, v3, v4, v5, v6))
485        })
486    };
487    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr, $p6:expr, $p7:expr) => {
488        $crate::Parser::new(move |state| {
489            let v1 = $p1.call(state)?;
490            let v2 = $p2.call(state)?;
491            let v3 = $p3.call(state)?;
492            let v4 = $p4.call(state)?;
493            let v5 = $p5.call(state)?;
494            let v6 = $p6.call(state)?;
495            let v7 = $p7.call(state)?;
496            Some((v1, v2, v3, v4, v5, v6, v7))
497        })
498    };
499    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr, $p6:expr, $p7:expr, $p8:expr) => {
500        $crate::Parser::new(move |state| {
501            let v1 = $p1.call(state)?;
502            let v2 = $p2.call(state)?;
503            let v3 = $p3.call(state)?;
504            let v4 = $p4.call(state)?;
505            let v5 = $p5.call(state)?;
506            let v6 = $p6.call(state)?;
507            let v7 = $p7.call(state)?;
508            let v8 = $p8.call(state)?;
509            Some((v1, v2, v3, v4, v5, v6, v7, v8))
510        })
511    };
512}
513
514// ── alt!: flat N-ary alternation combinator ───────────────────
515// Creates a single Box<dyn ParserFn> instead of N-1 intermediate boxes.
516// Usage: alt!(p1, p2) → Parser<O>, alt!(p1, p2, p3) → Parser<O>, etc.
517
518#[macro_export]
519macro_rules! alt {
520    ($p1:expr, $p2:expr) => {
521        $crate::Parser::new(move |state| {
522            let cp = state.offset;
523            if let Some(v) = $p1.call(state) { return Some(v); }
524            state.furthest_offset = state.furthest_offset.max(state.offset);
525            state.offset = cp;
526            if let Some(v) = $p2.call(state) { return Some(v); }
527            state.furthest_offset = state.furthest_offset.max(state.offset);
528            state.offset = cp;
529            None
530        })
531    };
532    ($p1:expr, $p2:expr, $p3:expr) => {
533        $crate::Parser::new(move |state| {
534            let cp = state.offset;
535            if let Some(v) = $p1.call(state) { return Some(v); }
536            state.furthest_offset = state.furthest_offset.max(state.offset);
537            state.offset = cp;
538            if let Some(v) = $p2.call(state) { return Some(v); }
539            state.furthest_offset = state.furthest_offset.max(state.offset);
540            state.offset = cp;
541            if let Some(v) = $p3.call(state) { return Some(v); }
542            state.furthest_offset = state.furthest_offset.max(state.offset);
543            state.offset = cp;
544            None
545        })
546    };
547    ($p1:expr, $p2:expr, $p3:expr, $p4:expr) => {
548        $crate::Parser::new(move |state| {
549            let cp = state.offset;
550            if let Some(v) = $p1.call(state) { return Some(v); }
551            state.furthest_offset = state.furthest_offset.max(state.offset);
552            state.offset = cp;
553            if let Some(v) = $p2.call(state) { return Some(v); }
554            state.furthest_offset = state.furthest_offset.max(state.offset);
555            state.offset = cp;
556            if let Some(v) = $p3.call(state) { return Some(v); }
557            state.furthest_offset = state.furthest_offset.max(state.offset);
558            state.offset = cp;
559            if let Some(v) = $p4.call(state) { return Some(v); }
560            state.furthest_offset = state.furthest_offset.max(state.offset);
561            state.offset = cp;
562            None
563        })
564    };
565    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr) => {
566        $crate::Parser::new(move |state| {
567            let cp = state.offset;
568            if let Some(v) = $p1.call(state) { return Some(v); }
569            state.furthest_offset = state.furthest_offset.max(state.offset);
570            state.offset = cp;
571            if let Some(v) = $p2.call(state) { return Some(v); }
572            state.furthest_offset = state.furthest_offset.max(state.offset);
573            state.offset = cp;
574            if let Some(v) = $p3.call(state) { return Some(v); }
575            state.furthest_offset = state.furthest_offset.max(state.offset);
576            state.offset = cp;
577            if let Some(v) = $p4.call(state) { return Some(v); }
578            state.furthest_offset = state.furthest_offset.max(state.offset);
579            state.offset = cp;
580            if let Some(v) = $p5.call(state) { return Some(v); }
581            state.furthest_offset = state.furthest_offset.max(state.offset);
582            state.offset = cp;
583            None
584        })
585    };
586    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr, $p6:expr) => {
587        $crate::Parser::new(move |state| {
588            let cp = state.offset;
589            if let Some(v) = $p1.call(state) { return Some(v); }
590            state.furthest_offset = state.furthest_offset.max(state.offset);
591            state.offset = cp;
592            if let Some(v) = $p2.call(state) { return Some(v); }
593            state.furthest_offset = state.furthest_offset.max(state.offset);
594            state.offset = cp;
595            if let Some(v) = $p3.call(state) { return Some(v); }
596            state.furthest_offset = state.furthest_offset.max(state.offset);
597            state.offset = cp;
598            if let Some(v) = $p4.call(state) { return Some(v); }
599            state.furthest_offset = state.furthest_offset.max(state.offset);
600            state.offset = cp;
601            if let Some(v) = $p5.call(state) { return Some(v); }
602            state.furthest_offset = state.furthest_offset.max(state.offset);
603            state.offset = cp;
604            if let Some(v) = $p6.call(state) { return Some(v); }
605            state.furthest_offset = state.furthest_offset.max(state.offset);
606            state.offset = cp;
607            None
608        })
609    };
610    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr, $p6:expr, $p7:expr) => {
611        $crate::Parser::new(move |state| {
612            let cp = state.offset;
613            if let Some(v) = $p1.call(state) { return Some(v); }
614            state.furthest_offset = state.furthest_offset.max(state.offset);
615            state.offset = cp;
616            if let Some(v) = $p2.call(state) { return Some(v); }
617            state.furthest_offset = state.furthest_offset.max(state.offset);
618            state.offset = cp;
619            if let Some(v) = $p3.call(state) { return Some(v); }
620            state.furthest_offset = state.furthest_offset.max(state.offset);
621            state.offset = cp;
622            if let Some(v) = $p4.call(state) { return Some(v); }
623            state.furthest_offset = state.furthest_offset.max(state.offset);
624            state.offset = cp;
625            if let Some(v) = $p5.call(state) { return Some(v); }
626            state.furthest_offset = state.furthest_offset.max(state.offset);
627            state.offset = cp;
628            if let Some(v) = $p6.call(state) { return Some(v); }
629            state.furthest_offset = state.furthest_offset.max(state.offset);
630            state.offset = cp;
631            if let Some(v) = $p7.call(state) { return Some(v); }
632            state.furthest_offset = state.furthest_offset.max(state.offset);
633            state.offset = cp;
634            None
635        })
636    };
637    ($p1:expr, $p2:expr, $p3:expr, $p4:expr, $p5:expr, $p6:expr, $p7:expr, $p8:expr) => {
638        $crate::Parser::new(move |state| {
639            let cp = state.offset;
640            if let Some(v) = $p1.call(state) { return Some(v); }
641            state.furthest_offset = state.furthest_offset.max(state.offset);
642            state.offset = cp;
643            if let Some(v) = $p2.call(state) { return Some(v); }
644            state.furthest_offset = state.furthest_offset.max(state.offset);
645            state.offset = cp;
646            if let Some(v) = $p3.call(state) { return Some(v); }
647            state.furthest_offset = state.furthest_offset.max(state.offset);
648            state.offset = cp;
649            if let Some(v) = $p4.call(state) { return Some(v); }
650            state.furthest_offset = state.furthest_offset.max(state.offset);
651            state.offset = cp;
652            if let Some(v) = $p5.call(state) { return Some(v); }
653            state.furthest_offset = state.furthest_offset.max(state.offset);
654            state.offset = cp;
655            if let Some(v) = $p6.call(state) { return Some(v); }
656            state.furthest_offset = state.furthest_offset.max(state.offset);
657            state.offset = cp;
658            if let Some(v) = $p7.call(state) { return Some(v); }
659            state.furthest_offset = state.furthest_offset.max(state.offset);
660            state.offset = cp;
661            if let Some(v) = $p8.call(state) { return Some(v); }
662            state.furthest_offset = state.furthest_offset.max(state.offset);
663            state.offset = cp;
664            None
665        })
666    };
667}