1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Wrap [chumsky](https://docs.rs/chumsky) parsers in increparse
//! [`Pass`](increparse::Pass)es.
//!
//! chumsky 0.10 reports spans as [`SimpleSpan`]s relative to the input slice
//! it parsed; increparse needs *absolute* spans carrying a source revision —
//! and the incremental tree only reuses regions whose spans match exactly.
//! This crate does the translation once, correctly, so your chumsky parsers
//! can stay in slice-relative coordinates.
//!
//! A pass is a function from the region's slice to a chumsky
//! [`ParseResult`] whose output is the parsed children: each child is a
//! **slice-relative** [`SimpleSpan`] plus a context value for the next
//! round. The wrapper converts the result to an
//! [`Outcome`](increparse::Outcome):
//!
//! * parse succeeded with children → `Outcome::Expand` with rebased
//! absolute spans,
//! * succeeded with no children → `Outcome::Done`,
//! * parse failed → `Outcome::Failed` (errors dropped; the region stays in
//! the tree as a leaf and later passes may retry it).
//!
//! Note: chumsky's `Parser::parse` implicitly requires the *whole* input to
//! be consumed. To claim children and ignore the rest of the region, end
//! your parser with `.then_ignore(any().repeated())`.
//!
//! Because parsers are typically built per-call (they are cheap), the
//! closure receives the slice and runs its parser itself:
//!
//! # Examples
//!
//! ```
//! use chumsky::prelude::*;
//! use increparse::{Outcome, Pass, Span};
//! use increparse_chumsky::{chumsky_pass, ChumChildren};
//!
//! // Parsers are built per call, tied to the input's lifetime.
//! fn split_at_hi(slice: &str) -> ParseResult<ChumChildren<()>, Rich<'_, char>> {
//! fn parser<'a>() -> impl Parser<'a, &'a str, ChumChildren<()>, extra::Err<Rich<'a, char>>> {
//! just("hi")
//! .map_with(|_out, e| vec![(e.span(), ())])
//! .then_ignore(any().repeated())
//! }
//! parser().parse(slice)
//! }
//!
//! let pass = chumsky_pass(split_at_hi);
//! let source = "hi there";
//! match pass.parse(source, Span::new(0, source.len(), 0), &()) {
//! Outcome::Expand(children) => {
//! // The child span is absolute, even though chumsky saw a slice.
//! assert_eq!(children[0].0.start, 0);
//! assert_eq!(children[0].0.end, 2);
//! }
//! _ => panic!("expected expansion"),
//! }
//! ```
//!
//! Spans you emit are validated by the engine like any other: they must be
//! contained in the region and (unless
//! [`EngineConfig::enforce_shrink`](increparse::EngineConfig::enforce_shrink)
//! is disabled) strictly smaller.
use Rich;
use SimpleSpan;
use ParseResult;
use ;
/// The children a chumsky parser produces: slice-relative spans plus the
/// context each child carries into the next round.
pub type ChumChildren<C> = ;
/// A [`Pass`] driven by a chumsky parser.
///
/// See the [crate docs](self) for the conversion rules. Build one with
/// [`chumsky_pass`].
/// Creates a pass from a closure that parses a slice into [`ChumChildren`].
///
/// chumsky 0.10's [`Parser`] trait is tied to the input lifetime, so parsers
/// are built per call (they are cheap) by a small factory function; the
/// closure builds one and runs it against the slice:
///
/// ```
/// use chumsky::prelude::*;
/// use increparse::{Outcome, Pass, Span};
/// use increparse_chumsky::{chumsky_pass, ChumChildren};
///
/// #[derive(Clone, Debug, PartialEq)]
/// enum Ctx {
/// Ident,
/// }
///
/// // The factory ties the parser to the input lifetime...
/// fn idents<'a>() -> impl Parser<'a, &'a str, ChumChildren<Ctx>, extra::Err<Rich<'a, char>>> {
/// text::ident()
/// .map_with(|_name, e| vec![(e.span(), Ctx::Ident)])
/// .then_ignore(any().repeated())
/// }
///
/// // ...and the closure is the pass body.
/// fn idents_pass(slice: &str) -> ParseResult<ChumChildren<Ctx>, Rich<'_, char>> {
/// idents().parse(slice)
/// }
///
/// let pass = chumsky_pass(idents_pass);
/// let source = "one two";
/// assert!(matches!(pass.parse(source, Span::new(0, source.len(), 0), &Ctx::Ident),
/// Outcome::Expand(_)));
/// ```