parsy 0.16.3

An easy-to-use, efficient parser combinators library
Documentation
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
use std::{borrow::Cow, ops::Deref, sync::LazyLock};

use crate::{
    Container, FileId, NoAllocContainer, ParserInput, ParserResult, ParsingError, parsers::*,
};

/// A parser takes an input and tries to consume the upcoming character(s) and transform it
/// into a value.
///
/// Implement this trait will also perform auto-implementation for the [`ParserConstUtils`] and
/// [`ParserNonConstUtils`] traits.
pub trait Parser<T> {
    /// Inner parsing function, to implement
    fn parse_inner(&self, input: &mut ParserInput) -> ParserResult<T>;
}

/// Non-constant-function utilities for parsers
pub trait ParserNonConstUtils<T>: Parser<T> {
    /// Parse an input with the current parser
    ///
    /// The input position will advance if the parsing is successful,
    /// and will not advance if the parsing fails
    fn parse(&self, input: &mut ParserInput) -> ParserResult<T> {
        // "Clone" (copy) 'input'
        let mut input_copy = *input;

        let result = self.parse_inner(&mut input_copy);

        // Only apply changes to input (cursor advance) if the parsing was successful
        // Otherwise, keep the original intact (this is equivalent to rollbacking in case of error)
        result.inspect(|span| input.advance(span.at))
    }

    /// Parse a string
    ///
    /// Will use [`FileId::None`] as the source
    fn parse_str(&self, str: &str) -> ParserResult<T> {
        self.parse_str_with_file_id(str, FileId::None)
    }

    /// Parse a string as a file
    ///
    /// Will use the provided file ID
    fn parse_str_with_file_id(&self, str: &str, file_id: FileId) -> ParserResult<T> {
        self.parse(&mut ParserInput::new(str, file_id))
    }

    /// "Erase" the parser's type
    ///
    /// This is useful when requiring a parser whose type is very simple,
    /// instead of having a combination of nested parsers with lots of generics.
    ///
    /// # Example
    ///
    /// ```rust
    ///  use parsy::{Parser, ParserNonConstUtils, parsers::{LazilyDefined, helpers::{just, lazily_define}}};
    ///
    /// static PARSER_1: LazilyDefined<&'static str> = lazily_define(|| Box::new(just("yeah")));
    /// static PARSER_2: LazilyDefined<&'static str> = lazily_define(|| just("yeah").erase_type());
    /// ```
    fn erase_type(self) -> Box<dyn Parser<T> + Send + Sync>
    where
        Self: Sized + Send + Sync + 'static,
    {
        Box::new(self)
    }
}

/// Constant function utilities for parsers
///
/// These can be evaluated at build time
pub const trait ParserConstUtils<T>: Parser<T> {
    /// Chain this parser with another, getting both parsers' results combined
    fn then<U, P: Parser<U>>(self, other: P) -> Then<T, Self, U, P>
    where
        Self: Sized,
    {
        Then::new(self, other)
    }

    /// Chain this parser with another but discard the latter's parsed value
    fn then_ignore<U, P: Parser<U>>(self, other: P) -> ThenIgnore<T, Self, U, P>
    where
        Self: Sized,
    {
        ThenIgnore::new(self, other)
    }

    /// Chain this parser with another but discard the former's parsed value
    fn ignore_then<U, P: Parser<U>>(self, other: P) -> IgnoreThen<T, Self, U, P>
    where
        Self: Sized,
    {
        IgnoreThen::new(self, other)
    }

    /// Only match if this parser succeeds and the provided parser succeeds as well
    ///
    /// The second parser will not make the input's position advance
    fn followed_by<U, P: Parser<U>>(self, other: P) -> FollowedBy<T, Self, U, P>
    where
        Self: Sized,
    {
        FollowedBy::new(self, other)
    }

    /// Only match if this parser succeeds and the provided parser doesn't
    fn not_followed_by<U, P: Parser<U>>(self, other: P) -> NotFollowedBy<T, Self, U, P>
    where
        Self: Sized,
    {
        NotFollowedBy::new(self, other)
    }

    /// Parse as many times as possible, until the parser eventually fails
    ///
    /// This will not allocate. To get the results directly in a [`Vec`], see [`ParserConstUtils::repeated_into_vec`]
    fn repeated(self) -> Repeated<T, Self, NoAllocContainer>
    where
        Self: Sized,
    {
        Repeated::new(self)
    }

    /// Parse as many times as possible, until the parser eventually fails
    ///
    /// All the parsed values will be put in a [`Vec`].
    /// To use another container, see [`ParserConstUtils::repeated_into_container`]
    fn repeated_into_vec(self) -> Repeated<T, Self, Vec<T>>
    where
        Self: Sized,
    {
        Repeated::new(self)
    }

    /// Parse as many times as possible, until the parser eventually fails
    ///
    /// All the parsed values will be forwarded to the provided [`Container`] type.
    /// The container will then be returned.
    fn repeated_into_container<C: Container<T>>(self) -> Repeated<T, Self, C>
    where
        Self: Sized,
    {
        Repeated::new(self)
    }

    /// Try to parse
    ///
    /// * In case of success, the parser will succeed and return the parsed value wrapped in a [`Some`]
    /// * In case of failure, the parser will succeed and return a [`None`]
    fn or_not(self) -> OrNot<T, Self>
    where
        Self: Sized,
    {
        OrNot::new(self)
    }

    /// Map the parsed value using a function
    ///
    /// Aking to [`Option::map`]
    fn map<U, F: Fn(T) -> U>(self, mapper: F) -> Map<T, Self, U, F>
    where
        Self: Sized,
    {
        Map::new(self, mapper)
    }

    /// Get the input string matched by the parser and map it using a function
    fn map_consumed_str<U, F: Fn(&str) -> U>(self, mapper: F) -> MapConsumedStr<T, Self, U, F>
    where
        Self: Sized,
    {
        MapConsumedStr::new(self, mapper)
    }

    /// Transform and validate the parsed value using the provided function
    ///
    /// If you only want to return a critical error message, see [`ParserConstUtils::and_then_or_critical`]
    fn and_then<U, F: Fn(T) -> Result<U, ParsingError>>(self, mapper: F) -> AndThen<T, Self, U, F>
    where
        Self: Sized,
    {
        AndThen::new(self, mapper)
    }

    /// Transform and validate the parsed value using the provided function
    /// Failures are [critical](`ParserConstUtils::critical`)
    fn and_then_or_critical<U, F: Fn(T) -> Result<U, Cow<'static, str>>>(
        self,
        mapper: F,
    ) -> AndThenOrCritical<T, Self, U, F>
    where
        Self: Sized,
    {
        AndThenOrCritical::new(self, mapper)
    }

    /// Wrap the parsed value in a [`Spanned`]
    fn spanned(self) -> Spanned<T, Self>
    where
        Self: Sized,
    {
        Spanned::new(self)
    }

    /// Collect the parsed value using the provided iterator type
    fn collect<C>(self) -> Map<T, Self, C, fn(T) -> C>
    where
        Self: Sized,
        T: IntoIterator,
        C: FromIterator<T::Item>,
    {
        self.map(C::from_iter)
    }

    /// Collect the input string matched by the parser
    fn collect_string(self) -> CollectString<T, Self>
    where
        Self: Sized,
    {
        CollectString::new(self)
    }

    /// Provide an atomic error if the parser fails
    ///
    /// Atomic errors are the smallest possible error types,
    /// every error nested below their level is discarded
    fn atomic_err(self, message: &'static str) -> AtomicErr<T, Self>
    where
        Self: Sized,
    {
        AtomicErr::new(self, message)
    }

    /// Mark the parser as critical
    ///
    /// In case of failure, the whole chain of parsing will fail with the provided message
    fn critical(self, message: &'static str) -> Critical<T, Self>
    where
        Self: Sized,
    {
        Critical::new(self, Some(message))
    }

    /// Mark the parser as critical
    ///
    /// In case of failure, the whole chain of parsing will fail with a default message
    fn critical_auto_msg(self) -> Critical<T, Self>
    where
        Self: Sized,
    {
        Critical::new(self, None)
    }

    /// Make the parser silent
    ///
    /// The parsed value will be `()`. Akin to using `.map(|_| ())` on the parser.
    fn silenced(self) -> Silenced<T, Self>
    where
        Self: Sized,
    {
        Silenced::new(self)
    }

    /// Require the parser to be preceded by and followed by the provided padding
    ///
    /// The padding parser's values are discarded
    fn padded_by<P, PP: Parser<P>>(self, padding: PP) -> PaddedBy<T, Self, P, PP>
    where
        Self: Sized,
    {
        PaddedBy::new(self, padding)
    }

    /// Require the parser to be preceded by and followed by the provided parsers
    ///
    /// The parsers' values are discarded
    fn surrounded_by<L, LP: Parser<L>, R, RP: Parser<R>>(
        self,
        left: LP,
        right: RP,
    ) -> SurroundedBy<L, LP, T, Self, R, RP>
    where
        Self: Sized,
    {
        SurroundedBy::new(left, self, right)
    }

    /// Repeat the parser with the required provided separator between each repetition
    ///
    /// If you want to collect the results, see [`ParserConstUtils::separated_by_into_vec`].
    fn separated_by<S, P: Parser<S>>(self, sep: P) -> SeparatedBy<T, Self, S, P, NoAllocContainer>
    where
        Self: Sized,
    {
        SeparatedBy::new(self, sep)
    }

    /// Repeat the parser with the required provided separator between each repetition
    ///
    /// All results are collected into a [`Vec`].
    /// To use a custom container, see [`ParserConstUtils::separated_by_into_container`]
    fn separated_by_into_vec<S, P: Parser<S>>(self, sep: P) -> SeparatedBy<T, Self, S, P, Vec<T>>
    where
        Self: Sized,
    {
        SeparatedBy::new(self, sep)
    }

    /// Repeat the parser with the required provided separator between each repetition
    ///
    /// All results are forwarded to the provided [`Container`] type, which is then returned.
    fn separated_by_into_container<C: Container<T>, S, P: Parser<S>>(
        self,
        sep: P,
    ) -> SeparatedBy<T, Self, S, P, C>
    where
        Self: Sized,
    {
        SeparatedBy::new(self, sep)
    }

    /// Flatten the parser
    ///
    /// Requires the parser to return a nested iterator.
    /// The values are discarded. To collect them, see [`ParserConstUtils::flatten_into_vec`]
    fn flattened<U, S>(self) -> Flattened<U, S, T, Self, NoAllocContainer>
    where
        Self: Sized,
        T: IntoIterator<Item = S>,
        S: IntoIterator<Item = U>,
    {
        Flattened::new(self)
    }

    /// Flatten the parser
    /// Requires the parser to return a nested iterator.
    ///
    /// The values are collected into a [`Vec`].
    /// To use a custom container, see [`ParserConstUtils::flatten_into_container`]
    fn flatten_into_vec<U, S>(self) -> Flattened<U, S, T, Self, Vec<U>>
    where
        Self: Sized,
        T: IntoIterator<Item = S>,
        S: IntoIterator<Item = U>,
    {
        Flattened::new(self)
    }

    /// Flatten the parser
    /// Requires the parser to return a nested iterator.
    ///
    /// All results are forwarded to the provided [`Container`] type, which is then returned.
    fn flatten_into_container<U, S, C: Container<U>>(self) -> Flattened<U, S, T, Self, C>
    where
        Self: Sized,
        T: IntoIterator<Item = S>,
        S: IntoIterator<Item = U>,
    {
        Flattened::new(self)
    }

    /// Discard the parsed value and replace it with a fixed value
    fn to<U: Copy>(self, data: U) -> To<T, Self, U>
    where
        Self: Sized,
    {
        To::new(self, data)
    }

    /// Require the parser to match the entire input
    fn full(self) -> Full<T, Self>
    where
        Self: Sized,
    {
        Full::new(self)
    }

    /// Allow the parser to fallback to another parser in case of failure
    ///
    /// If you have multiple choices, see [`choice`](`crate::parsers::helpers::choice`)
    fn or<P: Parser<T>>(self, other: P) -> Choice<(Self, P), T>
    where
        Self: Sized,
    {
        Choice::<(Self, P), T>::new((self, other))
    }

    /// Validate the parsed value with a predicate
    fn validate<F: Fn(&T) -> bool>(self, validator: F) -> Validate<T, Self, F>
    where
        Self: Sized,
    {
        Validate::new(self, validator)
    }

    /// Validate the parsed value with a predicate or return a provided critical error message
    ///
    /// If you want to customize the validation message, use [`ParserConstUtils::validate_or_dynamic_critical`]
    fn validate_or_critical<F: Fn(&T) -> bool>(
        self,
        validator: F,
        message: &'static str,
    ) -> ValidateOrCriticalMsg<T, Self, F>
    where
        Self: Sized,
    {
        ValidateOrCriticalMsg::new(self, validator, message)
    }

    /// Validate the parsed value with a predicate or return a critical error message
    ///
    /// The error message will be provided by the Err() variant of the validator
    fn validate_or_dynamic_critical<F: Fn(&T) -> Result<(), Cow<'static, str>>>(
        self,
        validator: F,
    ) -> ValidateOrDynamicCriticalMsg<T, Self, F>
    where
        Self: Sized,
    {
        ValidateOrDynamicCriticalMsg::new(self, validator)
    }

    /// Debug the input and output values of the parser using the provided debugger
    fn debug<F: for<'a, 'b> Fn(DebugType<'a, 'b, T>)>(self, debugger: F) -> Debugging<T, Self, F>
    where
        Self: Sized,
    {
        Debugging::new(self, debugger)
    }

    /// Wrap a static reference to this parser inside a new parser
    ///
    /// This is useful to reference e.g. [`crate::parsers::LazilyDefined`] parsers
    ///
    /// # Example
    ///
    /// ```rust
    /// use parsy::{Parser, ParserConstUtils, parsers::{LazilyDefined, helpers::{just, lazily_define}}};
    ///
    /// static A: LazilyDefined<()> = lazily_define(|| Box::new(B.static_ref().to(())));
    /// static B: LazilyDefined<()> = lazily_define(|| Box::new(A.static_ref().to(())));
    /// ```
    fn static_ref(&'static self) -> StaticRef<T, Self>
    where
        Self: Sized,
    {
        StaticRef::new(self)
    }
}

// Add cosnt utilities to all parsers
impl<T, P: Parser<T>> const ParserConstUtils<T> for P {}

// Add non-const utilities to all parsers
impl<T, P: Parser<T>> ParserNonConstUtils<T> for P {}

// Implement for
impl<T, P: Parser<T> + ?Sized> Parser<T> for Box<P> {
    fn parse_inner(&self, input: &mut ParserInput) -> ParserResult<T> {
        self.deref().parse_inner(input)
    }
}

impl<T, P: Parser<T>> Parser<T> for LazyLock<P> {
    fn parse_inner(&self, input: &mut ParserInput) -> ParserResult<T> {
        self.deref().parse_inner(input)
    }
}