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
//! Core traits.
use crate::types::ParserOutput;
use crate::{ParseContext, Reported, Result};
/// Trait implemented by all parsers.
///
/// This is implemented by the built-in parsers, like `i32`, as well as
/// user-defined parsers created with `parser!`.
///
/// To run a parser, pass some text to [the `parse` method][Parser::parse].
pub trait Parser {
/// The type of value this parser produces from text.
type Output;
/// The type this parser produces internally before converting to the output type.
///
/// Some combinators use the `RawOutput` to determine how types should combine.
/// For example, if `A::RawOutput = ()`, then `A` produces no output;
/// and if `B::RawOutput = (i32,)` then `B` produces an integer;
/// `SequenceParser<A, B>::RawOutput` will then be `(i32,)`, the
/// result of concatenating the two raw tuples, rather than `((), i32)`.
///
/// However, `RawOutput` is very often a singleton tuple, and these are
/// awkward for users, so we convert to the `Output` type before presenting a
/// result to the user.
type RawOutput: ParserOutput<UserType = Self::Output>;
/// The type that implements matching, backtracking, and type conversion
/// for this parser, an implementation detail.
type Iter<'parse>: ParseIter<'parse, RawOutput = Self::RawOutput>
where
Self: 'parse;
/// Fully parse the given source string `s` and return the resulting value.
///
/// This is the main way of using a `Parser`.
///
/// This succeeds only if this parser matches the entire input string. It's
/// an error if any unmatched characters are left over at the end of `s`.
fn parse(&self, s: &str) -> Result<Self::Output> {
self.parse_raw(s).map(|v| v.into_user_type())
}
/// Produce a [parse iterator][ParseIter]. This is an internal implementation detail of
/// the parser and shouldn't normally be called directly from application code.
fn parse_iter<'parse>(
&'parse self,
context: &mut ParseContext<'parse>,
start: usize,
) -> Result<Self::Iter<'parse>, Reported>;
/// Like `parse` but produce the output in its [raw form][Self::RawOutput].
fn parse_raw(&self, s: &str) -> Result<Self::RawOutput> {
let mut ctx = ParseContext::new(s);
let mut it = match self.parse_iter(&mut ctx, 0) {
Ok(iter) => iter,
Err(Reported) => return Err(ctx.into_reported_error()),
};
while it.match_end() != s.len() {
ctx.error_extra(it.match_end());
if it.backtrack(&mut ctx).is_err() {
return Err(ctx.into_reported_error());
}
}
Ok(it.convert())
}
}
/// A parser in action. Some parsers can match in several different ways (for
/// example, in `foo* bar` backtracking is accomplished by `foo*` first
/// matching as much as possible, then backing off one match at a time), so
/// this is an iterator.
///
/// This doesn't return a `RawOutput` value from `next_parse` but instead waits
/// until you're sure you have a complete, successful parse, and are thus ready
/// to destroy the iterator. This helps us avoid building values only to drop
/// them later when some downstream parser fails to match, so it makes
/// backtracking faster. It also means we don't call `.map` closures until
/// there is a successful overall match and the values are actually needed.
pub trait ParseIter<'parse> {
/// The type this iterator can produce on a successful match.
type RawOutput;
/// Position at the end of the current match.
fn match_end(&self) -> usize;
/// Reject the current match and find the next-most-preferable match.
/// Returns true if another match was found, false if not.
///
/// Once this returns `false`, no more method calls should be made.
fn backtrack(&mut self, context: &mut ParseContext<'parse>) -> Result<(), Reported>;
/// Convert the matched text to a Rust value.
fn convert(&self) -> Self::RawOutput;
}
impl<'a, P> Parser for &'a P
where
P: Parser + ?Sized,
{
type Output = P::Output;
type RawOutput = P::RawOutput;
type Iter<'parse> = P::Iter<'parse>
where
P: 'parse,
'a: 'parse;
fn parse_iter<'parse>(
&'parse self,
context: &mut ParseContext<'parse>,
start: usize,
) -> Result<Self::Iter<'parse>, Reported> {
<P as Parser>::parse_iter(self, context, start)
}
}