tokit/
parser.rs

1//! Blazing fast parser combinators with deterministic parsing and zero-copy streaming.
2//!
3//! This module provides a unique parser combinator framework that combines:
4//!
5//! 1. **Parse-While-Lexing Architecture**: Zero-copy streaming - tokens consumed directly from
6//!    the lexer without buffering, eliminating allocation overhead
7//! 2. **Deterministic LALR-Style Parsing**: Explicit lookahead with compile-time buffer capacity, no hidden backtracking
8//! 3. **Flexible Error Handling**: Same parser adapts for fail-fast runtime ([`Fatal`](crate::emitter::Fatal))
9//!    or greedy compiler diagnostics (via custom [`Emitter`](crate::Emitter))
10//!
11//! # Architecture
12//!
13//! Unlike traditional parser combinators that buffer all tokens and rely on implicit backtracking:
14//!
15//! **Traditional (Two-Phase)**:
16//! ```text
17//! Source → Lexer → [Vec<Token>] → Parser
18//!                   ↑ Extra allocation!
19//! ```
20//!
21//! **Tokit (Streaming)**:
22//! ```text
23//! Source → Lexer ←→ Parser
24//!          ↑________↓
25//!     Zero-copy, on-demand
26//! ```
27//!
28//! Parsers pull tokens on-demand from the lexer. Only a small lookahead window (1-32 tokens)
29//! is buffered on the stack for deterministic decisions.
30//!
31//! # Core Concepts
32//!
33//! ## Parse-While-Lexing
34//!
35//! Tokens flow directly from lexer to parser without intermediate buffering:
36//! - **Zero extra allocations**: No `Vec<Token>` buffer
37//! - **Lower memory**: Only lookahead window buffered on stack
38//! - **Better cache locality**: Tokens processed immediately after lexing
39//!
40//! ## Deterministic Parsing (No Hidden Backtracking)
41//!
42//! Unlike traditional parser combinators with implicit backtracking, Tokit uses
43//! **explicit lookahead-based decisions**:
44//!
45//! ```ignore
46//! // Traditional: Hidden backtracking
47//! let parser = try_parser1.or(try_parser2).or(try_parser3);
48//!
49//! // Tokit: Explicit lookahead, deterministic
50//! let parser = any().peek_then::<_, typenum::U2>(|peeked, _| {
51//!     match peeked.front() {
52//!         Some(Token::If) => Ok(Action::Continue),  // Deterministic!
53//!         _ => Ok(Action::Stop),
54//!     }
55//! });
56//! ```
57//!
58//! The [`Window`] trait provides compile-time fixed lookahead capacity (`typenum::U1` to `typenum::U32`),
59//! enabling LALR-style deterministic table parsing.
60//!
61//! ## Flexible Error Handling via Emitter
62//!
63//! The [`Emitter`](crate::Emitter) trait decouples parsing logic from error handling strategy:
64//!
65//! ```ignore
66//! // Fail-fast for runtime/REPL (stop on first error)
67//! let parser = Parser::with_context(FatalContext::new());
68//! let result = parser.parse(source);  // Uses Fatal emitter
69//!
70//! // Custom greedy emitter for compiler diagnostics (collect all errors)
71//! struct DiagnosticEmitter { errors: Vec<Error> }
72//! impl Emitter for DiagnosticEmitter { /* collect errors */ }
73//! ```
74//!
75//! **Same parser code, different behavior** - just swap the `Emitter` type.
76//!
77//! # Quick Start
78//!
79//! ```ignore
80//! use tokit::{Any, Parse, Parser, parser::FatalContext};
81//!
82//! // 1. Parse any token
83//! let parser = Any::parser::<'_, MyLexer<'_>, ()>();
84//! let result = parser.parse(source);
85//!
86//! // 2. Chain combinators
87//! let parser = Any::parser::<'_, MyLexer<'_>, ()>()
88//!     .map(|tok| tok.kind())
89//!     .filter(|kind| matches!(kind, TokenKind::Number));
90//!
91//! // 3. Explicit lookahead (deterministic choice)
92//! let parser = Any::parser::<'_, MyLexer<'_>, ()>()
93//!     .peek_then::<_, typenum::U1>(|peeked, _| {
94//!         match peeked.get(0) {
95//!             Some(tok) if tok.is_keyword("if") => Ok(Action::Continue),
96//!             _ => Ok(Action::Stop),
97//!         }
98//!     });
99//! ```
100//!
101//! # Available Combinators
102//!
103//! ## Basic Parsers
104//!
105//! - [`any`] - Accept any single token
106//! - [`expect`] - Expect specific token, emit error if not found
107//! - [`empty`] - No-op parser
108//! - [`todo`] - Placeholder for incomplete implementations
109//!
110//! ## Sequencing
111//!
112//! - [`then`] - Sequential composition: parse `p1` then `p2`
113//! - [`then_ignore`] - Parse both, keep only first result
114//! - [`ignore_then`] - Parse both, keep only second result
115//!
116//! ## Repetition & Collections
117//!
118//! - [`repeated`] - Repeat until condition returns `Action::Stop`
119//! - [`separated_by`](SeparatedBy) - Parse elements separated by delimiter
120//! - [`delim`] - Parse delimited content (e.g., parentheses)
121//! - [`delim_seq`] - Parse delimited, separated sequences
122//!
123//! ## Lookahead & Conditional (Deterministic)
124//!
125//! - [`peek_then`](PeekThen) - Peek ahead with fixed window, make deterministic decision
126//! - [`peek_then_choice`](PeekThenChoice) - Choose between alternatives based on lookahead
127//! - [`or_not`](OrNot) - Optional parsing
128//!
129//! ## Transformation
130//!
131//! - [`map`](Map) - Transform output
132//! - [`filter`](Filter) - Filter with validation
133//! - [`filter_map`](FilterMap) - Filter and transform
134//! - [`validate`](Validate) - Validate with full location context
135//!
136//! ## Error Recovery
137//!
138//! - [`recover`](Recover) - Try parser, use recovery on error
139//! - [`padded`](Padded) - Skip trivia (whitespace/comments) before and after
140//!
141//! # Performance Characteristics
142//!
143//! - **Memory**: O(1) - only small lookahead window on stack, no token buffering
144//! - **Parsing**: O(n) - single-pass, deterministic, no backtracking
145//! - **Lookahead**: O(1) - fixed compile-time capacity (1-32 tokens)
146//!
147//! # Design Priorities
148//!
149//! 1. **Performance**: Parse-while-lexing (zero-copy), no hidden allocations
150//! 2. **Predictability**: No hidden backtracking, deterministic decisions
151//! 3. **Composability**: Small parsers combine into complex grammars
152//! 4. **Versatility**: Same parser for runtime (fail-fast) or compiler (greedy) via `Emitter`
153
154#![allow(clippy::type_complexity)]
155
156use core::{marker::PhantomData, mem::MaybeUninit};
157
158use crate::{
159  Check, Emitter, Lexed, Lexer, Source, Token,
160  emitter::{Fatal, FromEmitterError},
161  error::{UnexpectedEot, token::UnexpectedToken},
162  lexer::{Input, InputRef, Peeked, PunctuatorToken},
163  punct::Comma,
164  utils::{
165    Expected, Located, Sliced, Spanned,
166    marker::{PhantomLocated, PhantomSliced, PhantomSpan},
167  },
168};
169
170use derive_more::{IsVariant, TryUnwrap, Unwrap};
171use generic_arraydeque::{ArrayLength, GenericArrayDeque, array::GenericArray, typenum};
172
173pub use any::*;
174pub use choice::*;
175pub use collect::Collect;
176pub use ctx::{FatalContext, ParseContext, ParserContext};
177pub use delim::*;
178pub use delim_seq::*;
179pub use empty::*;
180pub use expect::*;
181pub use filter::*;
182pub use filter_map::*;
183pub use ignore::*;
184pub use map::*;
185pub use or_not::*;
186pub use padded::*;
187pub use peek_then::*;
188pub use peek_then_choice::*;
189pub use recover::*;
190pub use repeated::*;
191pub use sep::{SepFixSpec, SeparatedBy, SeparatedByOptions};
192pub use then::*;
193pub use todo::*;
194pub use validate::*;
195
196// #[cfg(any(feature = "std", feature = "alloc"))]
197// #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
198// pub use recursive::*;
199
200mod any;
201mod choice;
202mod collect;
203mod ctx;
204mod delim;
205mod delim_seq;
206mod empty;
207mod expect;
208mod filter;
209mod filter_map;
210mod ignore;
211mod map;
212mod or_not;
213mod padded;
214mod peek_then;
215mod peek_then_choice;
216mod recover;
217mod repeated;
218mod sep;
219mod then;
220mod todo;
221mod validate;
222
223#[cfg(any(feature = "std", feature = "alloc"))]
224mod recursive;
225
226mod sealed {
227  pub trait Sealed {}
228}
229
230/// A trait for parsers that specify the capacity of their peek buffer.
231pub trait Window: sealed::Sealed {
232  /// The capacity of the peek buffer.
233  type CAPACITY: ArrayLength;
234
235  /// Create an uninitialized array of the specified capacity.
236  #[cfg_attr(not(tarpaulin), inline(always))]
237  fn array<T>() -> GenericArray<MaybeUninit<T>, Self::CAPACITY> {
238    GenericArray::uninit()
239  }
240
241  /// Create a deque of the specified capacity.
242  #[cfg_attr(not(tarpaulin), inline(always))]
243  fn deque<T>() -> GenericArrayDeque<MaybeUninit<T>, Self::CAPACITY> {
244    GenericArrayDeque::new()
245  }
246}
247
248macro_rules! peek_buf_capacity_impl_for_typenum {
249  ($($size:literal), + $(,)?) => {
250    paste::paste! {
251      $(
252        impl sealed::Sealed for typenum::[< U $size >] {}
253
254        impl Window for typenum::[< U $size >] {
255          type CAPACITY = typenum::[< U $size >];
256        }
257      )*
258    }
259  };
260}
261
262seq_macro::seq!(N in 1..=32 {
263  peek_buf_capacity_impl_for_typenum! {
264    #(N,)*
265  }
266});
267
268/// Decision action for conditional parsing.
269pub trait Decision<'inp, L, E, W, Lang: ?Sized = ()> {
270  /// Decide the next action based on the peeked tokens.
271  fn decide(&mut self, toks: Peeked<'_, 'inp, L, W>, emitter: &mut E) -> Result<Action, E::Error>
272  where
273    L: Lexer<'inp>,
274    E: Emitter<'inp, L, Lang>,
275    W: Window;
276}
277
278impl<'inp, F, L, E, W, Lang: ?Sized> Decision<'inp, L, E, W, Lang> for F
279where
280  F: FnMut(Peeked<'_, 'inp, L, W>, &mut E) -> Result<Action, E::Error>,
281  L: Lexer<'inp>,
282  E: Emitter<'inp, L, Lang>,
283  W: Window,
284{
285  #[cfg_attr(not(tarpaulin), inline(always))]
286  fn decide(&mut self, toks: Peeked<'_, 'inp, L, W>, emitter: &mut E) -> Result<Action, E::Error>
287  where
288    W: Window,
289  {
290    (self)(toks, emitter)
291  }
292}
293
294/// Core trait implemented by every parser combinator.
295///
296/// This mirrors the ergonomics of libraries like `winnow`: a parser is
297/// simply something that can mutate an [`InputRef`] and either produce
298/// a value or a spanned error using the configured `Emitter`.
299pub trait ParseInput<'inp, L, O, Ctx, Lang: ?Sized = ()> {
300  /// Try to parse from the given input.
301  fn parse_input(
302    &mut self,
303    input: &mut InputRef<'inp, '_, L, Ctx, Lang>,
304  ) -> Result<O, <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error>
305  where
306    L: Lexer<'inp>,
307    Ctx: ParseContext<'inp, L, Lang>;
308
309  /// Wraps the output of this parser in a `Spanned` with the span of the parsed input.
310  #[cfg_attr(not(tarpaulin), inline(always))]
311  fn spanned(self) -> With<PhantomSpan, Self>
312  where
313    Self: Sized,
314  {
315    With::new(PhantomSpan::phantom(), self)
316  }
317
318  /// Wraps the output of this parser in a `Sliced` with the source slice of the parsed input.
319  #[cfg_attr(not(tarpaulin), inline(always))]
320  fn sourced(self) -> With<PhantomSliced, Self>
321  where
322    Self: Sized,
323  {
324    With::new(PhantomSliced::phantom(), self)
325  }
326
327  /// Wraps the output of this parser in a `Located` with the span and source slice of the parsed input.
328  #[cfg_attr(not(tarpaulin), inline(always))]
329  fn located(self) -> With<PhantomLocated, Self>
330  where
331    Self: Sized,
332  {
333    With::new(PhantomLocated::phantom(), self)
334  }
335
336  /// Ignores the output of this parser.
337  #[cfg_attr(not(tarpaulin), inline(always))]
338  fn ignored(self) -> Ignore<Self, O>
339  where
340    Self: Sized,
341  {
342    Ignore::new(self)
343  }
344
345  /// Creates a `Repeated` combinator that applies this parser repeatedly
346  /// until the condition handler `Condition` returns [`RepeatedAction::End`] or an fatal error.
347  #[cfg_attr(not(tarpaulin), inline(always))]
348  fn repeated<Condition, W>(self, condition: Condition) -> Repeated<Self, Condition, O, W>
349  where
350    Self: Sized,
351    L: Lexer<'inp>,
352    Ctx: ParseContext<'inp, L, Lang>,
353    Condition: Decision<'inp, L, Ctx::Emitter, W::CAPACITY>,
354    W: Window,
355  {
356    Repeated::new(self, condition)
357  }
358
359  /// Creates a `SeparatedBy` combinator that applies this parser repeatedly,
360  #[cfg_attr(not(tarpaulin), inline(always))]
361  fn separated_by<SepClassifier, Condition, W>(
362    self,
363    sep_classifier: SepClassifier,
364    condition: Condition,
365  ) -> SeparatedBy<Self, SepClassifier, Condition, O, W, L, Ctx>
366  where
367    Self: Sized,
368    L: Lexer<'inp>,
369    Ctx: ParseContext<'inp, L, Lang>,
370    Condition: Decision<'inp, L, Ctx::Emitter, W, Lang>,
371    SepClassifier: Check<L::Token>,
372    W: Window,
373  {
374    SeparatedBy::new(self, sep_classifier, condition)
375  }
376
377  /// Creates a `SeparatedBy` combinator that applies this parser repeatedly,
378  #[cfg_attr(not(tarpaulin), inline(always))]
379  fn separated_by_comma<Condition, W>(
380    self,
381    condition: Condition,
382  ) -> SeparatedBy<Self, Comma, Condition, O, W, L, Ctx>
383  where
384    Self: Sized,
385    L: Lexer<'inp>,
386    L::Token: PunctuatorToken<'inp>,
387    Ctx: ParseContext<'inp, L, Lang>,
388    Condition: Decision<'inp, L, Ctx::Emitter, W, Lang>,
389    W: Window,
390  {
391    SeparatedBy::new(self, Comma::PHANTOM, condition)
392  }
393
394  /// Creates a `PeekThen` combinator that peeks at most `N` tokens first from the input before parsing.
395  ///
396  /// If the condition handler `C` returns `Ok(())`, the inner parser is applied, otherwise,
397  /// parsing is stopped and return the error from the handler.
398  fn peek_then<C, W>(self, condition: C) -> PeekThen<Self, C, L::Token, W>
399  where
400    Self: Sized,
401    L: Lexer<'inp>,
402    Ctx: ParseContext<'inp, L, Lang>,
403    C: FnMut(
404      Peeked<'_, 'inp, L, W>,
405      &mut Ctx::Emitter,
406    ) -> Result<(), <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error>,
407    W: Window,
408    PeekThen<Self, C, L::Token, W>: ParseInput<'inp, L, O, Ctx, Lang>,
409  {
410    PeekThen::of(self, condition)
411  }
412
413  /// Creates a `PeekThen` combinator that peeks at most `N` tokens first from the input before parsing.
414  ///
415  /// If the condition handler `C` returns `Ok(Action::Continue)`, the inner parser is applied,
416  /// otherwise returns `None`.
417  #[doc(alias = "or_not")]
418  fn peek_then_or_not<C, W>(self, condition: C) -> OrNot<PeekThen<Self, C, L::Token, W>>
419  where
420    Self: Sized,
421    L: Lexer<'inp>,
422    Ctx: ParseContext<'inp, L, Lang>,
423    C: Decision<'inp, L, Ctx::Emitter, W, Lang>,
424    W: Window,
425    OrNot<PeekThen<Self, C, L::Token, W>>: ParseInput<'inp, L, Option<O>, Ctx, Lang>,
426  {
427    PeekThen::or_not_of(self, condition)
428  }
429
430  /// Map the output of this parser using the given function.
431  #[cfg_attr(not(tarpaulin), inline(always))]
432  fn map<U, F>(self, f: F) -> Map<Self, F, L, Ctx, O, U, Lang>
433  where
434    Self: Sized,
435    F: FnMut(O) -> U,
436  {
437    Map::new(self, f)
438  }
439
440  /// Filter the output of this parser using a validation function.
441  ///
442  /// The parser must produce a `Spanned<O>` value. The validator receives
443  /// the data and span, and returns `Ok(())` if valid or an error otherwise.
444  #[cfg_attr(not(tarpaulin), inline(always))]
445  fn filter<F>(self, validator: F) -> Filter<Self, F>
446  where
447    Self: Sized,
448    L: Lexer<'inp>,
449    F: FnMut(&O) -> Result<(), <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error>,
450    Ctx: ParseContext<'inp, L, Lang>,
451  {
452    Filter::of(self, validator)
453  }
454
455  /// Filter and map the output of this parser using a validation/transformation function.
456  ///
457  /// The parser must produce a `Spanned<O>` value. The mapper receives
458  /// the data and span, and returns `Ok(new_value)` or an error.
459  #[cfg_attr(not(tarpaulin), inline(always))]
460  fn filter_map<U, F>(self, mapper: F) -> FilterMap<Self, F, O>
461  where
462    Self: Sized,
463    L: Lexer<'inp>,
464    F: FnMut(O) -> Result<U, <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error>,
465    Ctx: ParseContext<'inp, L, Lang>,
466  {
467    FilterMap::of(self, mapper)
468  }
469
470  /// Validate the output of this parser with full location context.
471  ///
472  /// The parser must produce a `Located<O>` value. The validator receives
473  /// the data, span, and slice, and returns `Ok(())` if valid or an error otherwise.
474  #[cfg_attr(not(tarpaulin), inline(always))]
475  fn validate<F>(self, validator: F) -> Validate<Self, F>
476  where
477    Self: Sized,
478    L: Lexer<'inp>,
479    F: FnMut(&O) -> Result<(), <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error>,
480    Ctx: ParseContext<'inp, L, Lang>,
481  {
482    Validate::of(self, validator)
483  }
484
485  /// Sequence this parser with another, ignoring the output of the second.
486  #[cfg_attr(not(tarpaulin), inline(always))]
487  fn then_ignore<G, U>(self, second: G) -> ThenIgnore<Self, G, U>
488  where
489    Self: Sized,
490    G: ParseInput<'inp, L, U, Ctx, Lang>,
491    Ctx: ParseContext<'inp, L, Lang>,
492  {
493    ThenIgnore::new(self, second)
494  }
495
496  /// Sequence this parser with another, using the first result to determine the second parser.
497  #[cfg_attr(not(tarpaulin), inline(always))]
498  fn then<T, U>(self, then: T) -> Then<Self, T>
499  where
500    Self: Sized,
501    T: ParseInput<'inp, L, U, Ctx, Lang>,
502    Ctx: ParseContext<'inp, L, Lang>,
503  {
504    Then::new(self, then)
505  }
506
507  /// Sequence this parser with another, ignoring the output of the first.
508  #[cfg_attr(not(tarpaulin), inline(always))]
509  fn ignore_then<G, U>(self, second: G) -> IgnoreThen<Self, G, O>
510  where
511    Self: Sized,
512    G: ParseInput<'inp, L, U, Ctx, Lang>,
513  {
514    IgnoreThen::new(self, second)
515  }
516
517  /// Recover from errors produced by this parser using the given recovery parser.
518  #[cfg_attr(not(tarpaulin), inline(always))]
519  fn recover<R>(self, recovery: R) -> Recover<Self, R>
520  where
521    Self: Sized,
522    R: ParseInput<'inp, L, O, Ctx, Lang>,
523    Ctx: ParseContext<'inp, L, Lang>,
524  {
525    Recover::new(self, recovery)
526  }
527
528  /// Recover in-place from errors produced by this parser using the given recovery parser.
529  #[cfg_attr(not(tarpaulin), inline(always))]
530  fn inplace_recover<R>(self, recovery: R) -> InplaceRecover<Self, R>
531  where
532    Self: Sized,
533    R: ParseInput<'inp, L, O, Ctx, Lang>,
534    Ctx: ParseContext<'inp, L, Lang>,
535  {
536    InplaceRecover::new(self, recovery)
537  }
538
539  /// Creates a parser that accepts any token with optional padding.
540  #[cfg_attr(not(tarpaulin), inline(always))]
541  fn padded(self) -> Padded<Self>
542  where
543    Self: Sized,
544  {
545    Padded::new(self)
546  }
547}
548
549impl<'inp, F, L, O, Ctx, Lang: ?Sized> ParseInput<'inp, L, O, Ctx, Lang> for F
550where
551  F: FnMut(
552    &mut InputRef<'inp, '_, L, Ctx, Lang>,
553  ) -> Result<O, <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error>,
554  L: Lexer<'inp>,
555  Ctx: ParseContext<'inp, L, Lang>,
556{
557  #[cfg_attr(not(tarpaulin), inline(always))]
558  fn parse_input(
559    &mut self,
560    input: &mut InputRef<'inp, '_, L, Ctx, Lang>,
561  ) -> Result<O, <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error> {
562    (self)(input)
563  }
564}
565
566impl<'inp, L, O, Ctx, P, Lang: ?Sized> ParseInput<'inp, L, Spanned<O, L::Span>, Ctx, Lang>
567  for With<PhantomSpan, P>
568where
569  P: ParseInput<'inp, L, O, Ctx, Lang>,
570  L: Lexer<'inp>,
571  Ctx: ParseContext<'inp, L, Lang>,
572{
573  #[cfg_attr(not(tarpaulin), inline(always))]
574  fn parse_input(
575    &mut self,
576    inp: &mut InputRef<'inp, '_, L, Ctx, Lang>,
577  ) -> Result<Spanned<O, L::Span>, <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error> {
578    let cursor = inp.cursor().clone();
579    self
580      .secondary
581      .parse_input(inp)
582      .map(|output| Spanned::new(inp.span_since(&cursor), output))
583  }
584}
585
586impl<'inp, L, O, Ctx, P, Lang: ?Sized>
587  ParseInput<'inp, L, Sliced<O, <L::Source as Source<L::Offset>>::Slice<'inp>>, Ctx, Lang>
588  for With<PhantomSliced, P>
589where
590  P: ParseInput<'inp, L, O, Ctx, Lang>,
591  L: Lexer<'inp>,
592  Ctx: ParseContext<'inp, L, Lang>,
593{
594  #[cfg_attr(not(tarpaulin), inline(always))]
595  fn parse_input(
596    &mut self,
597    inp: &mut InputRef<'inp, '_, L, Ctx, Lang>,
598  ) -> Result<
599    Sliced<O, <L::Source as Source<L::Offset>>::Slice<'inp>>,
600    <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error,
601  > {
602    let cursor = inp.cursor().clone();
603    self.secondary.parse_input(inp).map(|output| {
604      Sliced::new(
605        inp
606          .slice_since(&cursor)
607          .expect("parser should guarantee slice"),
608        output,
609      )
610    })
611  }
612}
613
614impl<'inp, L, O, Ctx, P, Lang: ?Sized>
615  ParseInput<'inp, L, Located<O, L::Span, <L::Source as Source<L::Offset>>::Slice<'inp>>, Ctx, Lang>
616  for With<PhantomLocated, P>
617where
618  P: ParseInput<'inp, L, O, Ctx, Lang>,
619  L: Lexer<'inp>,
620  Ctx: ParseContext<'inp, L, Lang>,
621{
622  #[cfg_attr(not(tarpaulin), inline(always))]
623  fn parse_input(
624    &mut self,
625    inp: &mut InputRef<'inp, '_, L, Ctx, Lang>,
626  ) -> Result<
627    Located<O, L::Span, <L::Source as Source<L::Offset>>::Slice<'inp>>,
628    <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error,
629  > {
630    let cursor = inp.cursor().clone();
631    self.secondary.parse_input(inp).map(|output| {
632      Located::new(
633        inp
634          .slice_since(&cursor)
635          .expect("parser should guarantee slice"),
636        inp.span_since(&cursor),
637        output,
638      )
639    })
640  }
641}
642
643/// Wrapper for cache configuration in parsers.
644///
645/// Wraps a cache type `C` to distinguish it from bare `()` in type parameters,
646/// preventing trait overlap in Parse implementations.
647#[repr(transparent)]
648pub struct WithCache<'inp, L, C> {
649  cache: C,
650  _marker: PhantomData<&'inp L>,
651}
652
653/// Wrapper for emitter configuration in parsers.
654///
655/// Wraps an emitter type `E` to distinguish it from bare `()` in type parameters,
656/// preventing trait overlap in Parse implementations.
657#[repr(transparent)]
658pub struct WithEmitter<E: ?Sized>(E);
659
660/// A parser with configurable emitter and cache.
661///
662/// # Type Parameters
663///
664/// - `F`: The parsing function
665/// - `L`: The lexer type
666/// - `O`: The output type
667/// - `Error`: The error type
668/// - `Options`: Configuration for emitter and cache (defaults to `ParserOptions<L>`)
669///
670/// # Examples
671///
672/// ```ignore
673/// // Create parser with defaults
674/// let p = Parser::with(|inp| inp.next());
675///
676/// // Configure emitter
677/// let p = Parser::with(|inp| inp.next())
678///     .with_emitter(MyEmitter::new());
679/// ```
680pub struct Parser<F, L, O, Error, Context> {
681  f: F,
682  ctx: Context,
683  _marker: PhantomData<(L, O, Error)>,
684}
685
686impl<F, L, O, Error, Context> core::ops::Deref for Parser<F, L, O, Error, Context> {
687  type Target = F;
688
689  #[cfg_attr(not(tarpaulin), inline(always))]
690  fn deref(&self) -> &Self::Target {
691    &self.f
692  }
693}
694
695impl<F, L, O, Error, Context> core::ops::DerefMut for Parser<F, L, O, Error, Context> {
696  #[cfg_attr(not(tarpaulin), inline(always))]
697  fn deref_mut(&mut self) -> &mut Self::Target {
698    &mut self.f
699  }
700}
701
702impl<'inp, L, O, Error> Default for Parser<(), L, O, Error, FatalContext<'inp, L, Error>>
703where
704  L: Lexer<'inp>,
705  Error: FromEmitterError<'inp, L>,
706{
707  #[cfg_attr(not(tarpaulin), inline(always))]
708  fn default() -> Self {
709    Parser::new()
710  }
711}
712
713impl Parser<(), (), (), (), ()> {
714  /// A parser without any behavior.
715  #[cfg_attr(not(tarpaulin), inline(always))]
716  pub const fn new<'inp, L, O, Error>() -> Parser<(), L, O, Error, FatalContext<'inp, L, Error>>
717  where
718    L: Lexer<'inp>,
719    Error: FromEmitterError<'inp, L>,
720  {
721    Self::of()
722  }
723
724  /// Creates a parser with the given context.
725  #[cfg_attr(not(tarpaulin), inline(always))]
726  pub const fn with_context<'inp, L, O, Error, Ctx>(ctx: Ctx) -> Parser<(), L, O, Error, Ctx>
727  where
728    L: Lexer<'inp>,
729    Error: FromEmitterError<'inp, L>,
730    Ctx: ParseContext<'inp, L>,
731    Ctx::Emitter: Emitter<'inp, L, Error = Error>,
732  {
733    Self::with_context_of(ctx)
734  }
735
736  /// A parser without any behavior.
737  #[cfg_attr(not(tarpaulin), inline(always))]
738  pub const fn of<'inp, L, O, Error, Lang>()
739  -> Parser<(), L, O, Error, FatalContext<'inp, L, Error, Lang>>
740  where
741    L: Lexer<'inp>,
742    Error: FromEmitterError<'inp, L, Lang>,
743    Lang: ?Sized,
744  {
745    Self::with_context_of(FatalContext::of(Fatal::of()))
746  }
747
748  /// Creates a parser with the given context for a specific language.
749  #[cfg_attr(not(tarpaulin), inline(always))]
750  pub const fn with_context_of<'inp, L, O, Error, Ctx, Lang>(
751    ctx: Ctx,
752  ) -> Parser<(), L, O, Error, Ctx>
753  where
754    L: Lexer<'inp>,
755    Error: FromEmitterError<'inp, L, Lang>,
756    Ctx: ParseContext<'inp, L, Lang>,
757    Ctx::Emitter: Emitter<'inp, L, Lang, Error = Error>,
758    Lang: ?Sized,
759  {
760    Parser {
761      f: (),
762      ctx,
763      _marker: PhantomData,
764    }
765  }
766
767  /// Creates a parser with a parser function and the fatal context.
768  #[cfg_attr(not(tarpaulin), inline(always))]
769  pub const fn with_parser<'inp, L, O, Error, F>(
770    f: F,
771  ) -> Parser<F, L, O, Error, FatalContext<'inp, L, Error>>
772  where
773    L: Lexer<'inp>,
774    F: ParseInput<'inp, L, O, FatalContext<'inp, L, Error>>,
775    Error: FromEmitterError<'inp, L>,
776  {
777    Self::with_parser_of(f)
778  }
779
780  /// Creates a parser with a parser function and the fatal context for a specific language.
781  #[cfg_attr(not(tarpaulin), inline(always))]
782  pub const fn with_parser_of<'inp, L, O, Error, F, Lang>(
783    f: F,
784  ) -> Parser<F, L, O, Error, FatalContext<'inp, L, Error, Lang>>
785  where
786    L: Lexer<'inp>,
787    F: ParseInput<'inp, L, O, FatalContext<'inp, L, Error, Lang>>,
788    Error: FromEmitterError<'inp, L, Lang>,
789    Lang: ?Sized,
790  {
791    Self::with_parser_and_context_of(f, FatalContext::of(Fatal::of()))
792  }
793
794  /// Creates a parser with a parser function and the fatal context.
795  #[cfg_attr(not(tarpaulin), inline(always))]
796  pub const fn with_parser_and_context<'inp, L, O, Error, Ctx, F>(
797    f: F,
798    ctx: Ctx,
799  ) -> Parser<F, L, O, Error, Ctx>
800  where
801    L: Lexer<'inp>,
802    F: ParseInput<'inp, L, O, Ctx>,
803    Ctx: ParseContext<'inp, L>,
804    Error: FromEmitterError<'inp, L>,
805  {
806    Self::with_parser_and_context_of(f, ctx)
807  }
808
809  /// Creates a parser with a parser function and the fatal context for a specific language.
810  #[cfg_attr(not(tarpaulin), inline(always))]
811  pub const fn with_parser_and_context_of<'inp, L, O, Error, Ctx, F, Lang>(
812    f: F,
813    ctx: Ctx,
814  ) -> Parser<F, L, O, Error, Ctx>
815  where
816    L: Lexer<'inp>,
817    F: ParseInput<'inp, L, O, Ctx>,
818    Ctx: ParseContext<'inp, L, Lang>,
819    Error: FromEmitterError<'inp, L, Lang>,
820    Lang: ?Sized,
821  {
822    Parser {
823      f,
824      ctx,
825      _marker: PhantomData,
826    }
827  }
828}
829
830impl<'inp, L, O, Error, Ctx> Parser<(), L, O, Error, Ctx>
831where
832  L: Lexer<'inp>,
833{
834  /// Apply a new parsing function to the parser.
835  #[cfg_attr(not(tarpaulin), inline(always))]
836  pub fn apply<F>(self, f: F) -> Parser<F, L, O, Error, Ctx>
837  where
838    Ctx: ParseContext<'inp, L>,
839    F: ParseInput<'inp, L, O, Ctx>,
840  {
841    self.apply_of(f)
842  }
843
844  /// Apply a new parsing function to the parser for a specific language.
845  #[cfg_attr(not(tarpaulin), inline(always))]
846  pub fn apply_of<F, Lang>(self, f: F) -> Parser<F, L, O, Error, Ctx>
847  where
848    Ctx: ParseContext<'inp, L, Lang>,
849    F: ParseInput<'inp, L, O, Ctx>,
850  {
851    Parser {
852      f,
853      ctx: self.ctx,
854      _marker: PhantomData,
855    }
856  }
857}
858
859/// Entry-point trait: run a parser against a source.
860///
861/// This provides the ergonomic `.parse()` API similar to Chumsky and
862/// Winnow. Implementations wire up `Input`, `Emitter`, and `Cache`
863/// before delegating to [`ParseInput`].
864pub trait Parse<'inp, L, O, Error, Lang: ?Sized = ()>: Sized {
865  /// Parse using the lexer's default state.
866  #[cfg_attr(not(tarpaulin), inline(always))]
867  fn parse(self, src: &'inp L::Source) -> Result<O, Error>
868  where
869    L: Lexer<'inp>,
870    L::State: Default,
871  {
872    self.parse_with_state(src, L::State::default())
873  }
874
875  /// Parse using an explicit lexer state.
876  fn parse_with_state(self, src: &'inp L::Source, state: L::State) -> Result<O, Error>
877  where
878    L: Lexer<'inp>;
879}
880
881impl<'inp, F, L, O, Error, Ctx, Lang: ?Sized> Parse<'inp, L, O, Error, Lang>
882  for Parser<F, L, O, Error, Ctx>
883where
884  F: ParseInput<'inp, L, O, Ctx, Lang>,
885  L: Lexer<'inp>,
886  Ctx: ParseContext<'inp, L, Lang>,
887  Ctx::Emitter: Emitter<'inp, L, Lang, Error = Error>,
888{
889  #[cfg_attr(not(tarpaulin), inline(always))]
890  fn parse_with_state(self, src: &'inp L::Source, state: L::State) -> Result<O, Error> {
891    let Parser { mut f, ctx, .. } = self;
892
893    let (mut emitter, cache) = ctx.provide().into_components();
894    let mut input = Input::with_state_and_cache(src, state, cache);
895    let mut input_ref = input.as_ref(&mut emitter);
896    f.parse_input(&mut input_ref)
897  }
898}
899
900/// Type-level function for configuration transformations.
901///
902/// This trait enables progressive parser configuration by transforming
903/// one configuration type into another. For example:
904///
905/// - `()` → `WithEmitter<E>` (add emitter configuration)
906/// - `()` → `WithCache<C>` (add cache configuration)
907///
908/// Used internally by `.with_emitter()` and `.with_cache()` methods.
909pub trait Apply<State> {
910  /// The input required to perform the transformation
911  type Options;
912
913  /// Transform `self` into `State` using the provided `options`.
914  fn apply(self, options: Self::Options) -> State;
915}
916
917/// Combines two values in a type-safe way.
918///
919/// This type is used throughout the parser system for:
920///
921/// - Wrapping parser functions with base parsers: `With<F, Parser<()>>`
922/// - Building configuration structures: `With<E, C>` for emitter + cache
923/// - Nested configurations: `With<PhantomData<L>, With<E, C>>` for ParserOptions
924///
925/// # Type Parameters
926///
927/// - `P`: The primary value (typically a parser function or marker)
928/// - `S`: The secondary value (typically configuration or a base parser)
929#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
930pub struct With<P, S> {
931  primary: P,
932  secondary: S,
933}
934
935impl<P, S> With<P, S> {
936  /// Create a new `With` combinator.
937  #[cfg_attr(not(tarpaulin), inline(always))]
938  pub const fn new(primary: P, secondary: S) -> Self {
939    Self { primary, secondary }
940  }
941
942  /// Returns a reference to the primary.
943  #[cfg_attr(not(tarpaulin), inline(always))]
944  pub const fn primary(&self) -> &P {
945    &self.primary
946  }
947
948  /// Returns a reference to the secondary.
949  #[cfg_attr(not(tarpaulin), inline(always))]
950  pub const fn secondary(&self) -> &S {
951    &self.secondary
952  }
953
954  /// Returns a mutable reference to the primary.
955  #[cfg_attr(not(tarpaulin), inline(always))]
956  pub const fn primary_mut(&mut self) -> &mut P {
957    &mut self.primary
958  }
959
960  /// Returns a mutable reference to the secondary.
961  #[cfg_attr(not(tarpaulin), inline(always))]
962  pub const fn secondary_mut(&mut self) -> &mut S {
963    &mut self.secondary
964  }
965
966  /// Maps the primary value using the given function.
967  #[cfg_attr(not(tarpaulin), inline(always))]
968  pub fn map_primary<U, F>(self, f: F) -> With<U, S>
969  where
970    F: FnOnce(P) -> U,
971  {
972    With {
973      primary: f(self.primary),
974      secondary: self.secondary,
975    }
976  }
977
978  /// Maps the secondary value using the given function.
979  #[cfg_attr(not(tarpaulin), inline(always))]
980  pub fn map_secondary<U, F>(self, f: F) -> With<P, U>
981  where
982    F: FnOnce(S) -> U,
983  {
984    With {
985      primary: self.primary,
986      secondary: f(self.secondary),
987    }
988  }
989}
990
991/// A hint used during parsing.
992#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, Unwrap, TryUnwrap)]
993#[unwrap(ref, ref_mut)]
994#[try_unwrap(ref, ref_mut)]
995pub enum Action {
996  /// Indicates the token belongs to another syntactic element, hint to stop parsing.
997  #[unwrap(ignore)]
998  #[try_unwrap(ignore)]
999  Stop,
1000  /// Indicates a token belongs to an element was found, hint to continue parsing.
1001  #[unwrap(ignore)]
1002  #[try_unwrap(ignore)]
1003  Continue,
1004}
1005
1006impl Apply<Maximum> for () {
1007  type Options = usize;
1008
1009  #[cfg_attr(not(tarpaulin), inline(always))]
1010  fn apply(self, options: Self::Options) -> Maximum {
1011    Maximum(options)
1012  }
1013}
1014
1015impl Apply<Minimum> for () {
1016  type Options = usize;
1017
1018  #[cfg_attr(not(tarpaulin), inline(always))]
1019  fn apply(self, options: Self::Options) -> Minimum {
1020    Minimum(options)
1021  }
1022}
1023
1024impl Apply<Maximum> for Maximum {
1025  type Options = usize;
1026
1027  #[cfg_attr(not(tarpaulin), inline(always))]
1028  fn apply(self, options: Self::Options) -> Maximum {
1029    Maximum(options)
1030  }
1031}
1032
1033impl Apply<Minimum> for Minimum {
1034  type Options = usize;
1035
1036  #[cfg_attr(not(tarpaulin), inline(always))]
1037  fn apply(self, options: Self::Options) -> Minimum {
1038    Minimum(options)
1039  }
1040}
1041
1042/// A marker type representing the maximum number of elements allowed.
1043#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1044pub struct Maximum(pub usize);
1045
1046impl Maximum {
1047  /// The maximum possible value for `Maximum`.
1048  pub const MAX: Self = Self::new(usize::MAX);
1049
1050  /// Creates a new `Maximum`.
1051  #[cfg_attr(not(tarpaulin), inline(always))]
1052  pub const fn new(n: usize) -> Self {
1053    Self(n)
1054  }
1055
1056  /// Returns the maximum number of elements allowed.
1057  #[cfg_attr(not(tarpaulin), inline(always))]
1058  pub const fn get(&self) -> usize {
1059    self.0
1060  }
1061}
1062
1063/// A marker type representing the minimum number of elements required.
1064#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1065pub struct Minimum(usize);
1066
1067impl Minimum {
1068  /// The minimum possible value for `Minimum`.
1069  pub const MIN: Self = Self::new(0);
1070
1071  /// Creates a new `Minimum`.
1072  #[cfg_attr(not(tarpaulin), inline(always))]
1073  pub const fn new(n: usize) -> Self {
1074    Self(n)
1075  }
1076
1077  /// Returns the minimum number of elements required.
1078  #[cfg_attr(not(tarpaulin), inline(always))]
1079  pub const fn get(&self) -> usize {
1080    self.0
1081  }
1082}
1083
1084trait MinSpec {
1085  fn minimum(&self) -> usize;
1086}
1087
1088impl<T: MinSpec> MinSpec for &mut T {
1089  #[cfg_attr(not(tarpaulin), inline(always))]
1090  fn minimum(&self) -> usize {
1091    (**self).minimum()
1092  }
1093}
1094
1095impl MinSpec for Minimum {
1096  #[cfg_attr(not(tarpaulin), inline(always))]
1097  fn minimum(&self) -> usize {
1098    self.0
1099  }
1100}
1101
1102impl MinSpec for () {
1103  #[cfg_attr(not(tarpaulin), inline(always))]
1104  fn minimum(&self) -> usize {
1105    0
1106  }
1107}
1108
1109trait MaxSpec {
1110  fn maximum(&self) -> usize;
1111}
1112
1113impl<T: MaxSpec> MaxSpec for &mut T {
1114  #[cfg_attr(not(tarpaulin), inline(always))]
1115  fn maximum(&self) -> usize {
1116    (**self).maximum()
1117  }
1118}
1119
1120impl MaxSpec for Maximum {
1121  #[cfg_attr(not(tarpaulin), inline(always))]
1122  fn maximum(&self) -> usize {
1123    self.0
1124  }
1125}
1126
1127impl MaxSpec for () {
1128  #[cfg_attr(not(tarpaulin), inline(always))]
1129  fn maximum(&self) -> usize {
1130    usize::MAX
1131  }
1132}
1133
1134/// The result of a parsing attempt.
1135pub enum ParseResult<O, E> {
1136  /// No output, no error, no consumption; the input was rewound to its original state.
1137  Rewind,
1138  /// Successful parse with output `O` and no emitted errors.
1139  Ok(O),
1140  /// Fatal parse failure with error `E`; caller should stop or propagate.
1141  Err(E),
1142}