pub trait Parser<I: Clone, O> {
type Error: Error<I>;
Show 34 methods
fn parse_recovery<'a, Iter, S>(
&self,
stream: S
) -> (Option<O>, Vec<Self::Error>)
where
Self: Sized,
Iter: Iterator<Item = (I, <Self::Error as Error<I>>::Span)> + 'a,
S: Into<Stream<'a, I, <Self::Error as Error<I>>::Span, Iter>>,
{ ... }
fn parse_recovery_verbose<'a, Iter, S>(
&self,
stream: S
) -> (Option<O>, Vec<Self::Error>)
where
Self: Sized,
Iter: Iterator<Item = (I, <Self::Error as Error<I>>::Span)> + 'a,
S: Into<Stream<'a, I, <Self::Error as Error<I>>::Span, Iter>>,
{ ... }
fn parse<'a, Iter, S>(&self, stream: S) -> Result<O, Vec<Self::Error>>
where
Self: Sized,
Iter: Iterator<Item = (I, <Self::Error as Error<I>>::Span)> + 'a,
S: Into<Stream<'a, I, <Self::Error as Error<I>>::Span, Iter>>,
{ ... }
fn debug<T>(self, x: T) -> Debug<Self>
where
Self: Sized,
T: Display + 'static,
{ ... }
fn map<U, F>(self, f: F) -> Map<Self, F, O>
where
Self: Sized,
F: Fn(O) -> U,
{ ... }
fn map_with_span<U, F>(self, f: F) -> MapWithSpan<Self, F, O>
where
Self: Sized,
F: Fn(O, <Self::Error as Error<I>>::Span) -> U,
{ ... }
fn map_err<F>(self, f: F) -> MapErr<Self, F>
where
Self: Sized,
F: Fn(Self::Error) -> Self::Error,
{ ... }
fn or_else<F>(self, f: F) -> OrElse<Self, F>
where
Self: Sized,
F: Fn(Self::Error) -> Result<O, Self::Error>,
{ ... }
fn map_err_with_span<F>(self, f: F) -> MapErrWithSpan<Self, F>
where
Self: Sized,
F: Fn(Self::Error, <Self::Error as Error<I>>::Span) -> Self::Error,
{ ... }
fn try_map<U, F>(self, f: F) -> TryMap<Self, F, O>
where
Self: Sized,
F: Fn(O, <Self::Error as Error<I>>::Span) -> Result<U, Self::Error>,
{ ... }
fn validate<F, U>(self, f: F) -> Validate<Self, O, F>
where
Self: Sized,
F: Fn(O, <Self::Error as Error<I>>::Span, &mut dyn FnMut(Self::Error)) -> U,
{ ... }
fn labelled<L>(self, label: L) -> Label<Self, L>
where
Self: Sized,
L: Into<<Self::Error as Error<I>>::Label> + Clone,
{ ... }
fn to<U>(self, x: U) -> To<Self, O, U>
where
Self: Sized,
U: Clone,
{ ... }
fn foldl<A, B, F>(self, f: F) -> Foldl<Self, F, A, B>
where
Self: Parser<I, (A, B)> + Sized,
B: IntoIterator,
F: Fn(A, B::Item) -> A,
{ ... }
fn foldr<'a, A, B, F>(self, f: F) -> Foldr<Self, F, A, B>
where
Self: Parser<I, (A, B)> + Sized,
A: IntoIterator,
A::IntoIter: DoubleEndedIterator,
F: Fn(A::Item, B) -> B + 'a,
{ ... }
fn ignored(self) -> Ignored<Self, O>
where
Self: Sized,
{ ... }
fn collect<C>(self) -> Map<Self, fn(_: O) -> C, O>
where
Self: Sized,
O: IntoIterator,
C: FromIterator<O::Item>,
{ ... }
fn then<U, P>(self, other: P) -> Then<Self, P>
where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
{ ... }
fn then_with<U, P, F: Fn(O) -> P>(
self,
other: F
) -> ThenWith<I, O, U, Self, P, F>
where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
{ ... }
fn chain<T, U, P>(
self,
other: P
) -> Map<Then<Self, P>, fn(_: (O, U)) -> Vec<T>, (O, U)>
where
Self: Sized,
U: Chain<T>,
O: Chain<T>,
P: Parser<I, U, Error = Self::Error>,
{ ... }
fn flatten<T, Inner>(self) -> Map<Self, fn(_: O) -> Vec<T>, O>
where
Self: Sized,
O: IntoIterator<Item = Inner>,
Inner: IntoIterator<Item = T>,
{ ... }
fn ignore_then<U, P>(self, other: P) -> IgnoreThen<Self, P, O, U>
where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
{ ... }
fn then_ignore<U, P>(self, other: P) -> ThenIgnore<Self, P, O, U>
where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
{ ... }
fn padded_by<U, P>(
self,
other: P
) -> ThenIgnore<IgnoreThen<P, Self, U, O>, P, O, U>
where
Self: Sized,
P: Parser<I, U, Error = Self::Error> + Clone,
{ ... }
fn delimited_by<U, V, L, R>(
self,
start: L,
end: R
) -> DelimitedBy<Self, L, R, U, V>
where
Self: Sized,
L: Parser<I, U, Error = Self::Error>,
R: Parser<I, V, Error = Self::Error>,
{ ... }
fn or<P>(self, other: P) -> Or<Self, P>
where
Self: Sized,
P: Parser<I, O, Error = Self::Error>,
{ ... }
fn recover_with<S>(self, strategy: S) -> Recovery<Self, S>
where
Self: Sized,
S: Strategy<I, O, Self::Error>,
{ ... }
fn or_not(self) -> OrNot<Self>
where
Self: Sized,
{ ... }
fn repeated(self) -> Repeated<Self>
where
Self: Sized,
{ ... }
fn separated_by<U, P>(self, other: P) -> SeparatedBy<Self, P, U>
where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
{ ... }
fn rewind(self) -> Rewind<Self>
where
Self: Sized,
{ ... }
fn boxed<'a>(self) -> BoxedParser<'a, I, O, Self::Error>
where
Self: Sized + 'a,
{ ... }
fn from_str<U>(self) -> Map<Self, fn(_: O) -> Result<U, U::Err>, O>
where
Self: Sized,
U: FromStr,
O: AsRef<str>,
{ ... }
fn unwrapped<U, E>(
self
) -> Map<Self, fn(_: Result<U, E>) -> U, Result<U, E>>
where
Self: Sized + Parser<I, Result<U, E>>,
E: Debug,
{ ... }
}
Expand description
A trait implemented by parsers.
Parsers take a stream of tokens of type I
and attempt to parse them into a value of type O
. In doing so, they
may encounter errors. These need not be fatal to the parsing process: syntactic errors can be recovered from and a
valid output may still be generated alongside any syntax errors that were encountered along the way. Usually, this
output comes in the form of an Abstract Syntax Tree (AST).
You should not need to implement this trait by hand. If you cannot combine existing combintors (and in particular
custom
) to create the combinator you’re looking for, please
open an issue! If you really need to implement this trait,
please check the documentation in the source: some implementation details have been deliberately hidden.
Required Associated Types
Provided Methods
Parse a stream of tokens, yielding an output if possible, and any errors encountered along the way.
If None
is returned (i.e: parsing failed) then there will always be at least one item in the error Vec
.
If you don’t care about producing an output if errors are encountered, use Parser::parse
instead.
Although the signature of this function looks complicated, it’s simpler than you think! You can pass a
&[I]
, a &str
, or a Stream
to it.
Parse a stream of tokens, yielding an output if possible, and any errors encountered along the way. Unlike
Parser::parse_recovery
, this function will produce verbose debugging output as it executes.
If None
is returned (i.e: parsing failed) then there will always be at least one item in the error Vec
.
If you don’t care about producing an output if errors are encountered, use Parser::parse
instead.
Although the signature of this function looks complicated, it’s simpler than you think! You can pass a
&[I]
, a &str
, or a Stream
to it.
You’ll probably want to make sure that this doesn’t end up in production code: it exists only to help you debug your parser. Additionally, its API is quite likely to change in future versions.
This method will receive more extensive documentation as the crate’s debugging features mature.
Parse a stream of tokens, yielding an output or any errors that were encountered along the way.
If you wish to attempt to produce an output even if errors are encountered, use Parser::parse_recovery
.
Although the signature of this function looks complicated, it’s simpler than you think! You can pass a
[&[I]
], a &str
, or a Stream
to it.
Include this parser in the debugging output produced by Parser::parse_recovery_verbose
.
You’ll probably want to make sure that this doesn’t end up in production code: it exists only to help you debug your parser. Additionally, its API is quite likely to change in future versions. Use this parser like a print statement, to display whatever you pass as the argument ‘x’
This method will receive more extensive documentation as the crate’s debugging features mature.
Map the output of this parser to another value.
The output type of this parser is U
, the same as the function’s output.
Examples
#[derive(Debug, PartialEq)]
enum Token { Word(String), Num(u64) }
let word = filter::<_, _, Cheap<char>>(|c: &char| c.is_alphabetic())
.repeated().at_least(1)
.collect::<String>()
.map(Token::Word);
let num = filter::<_, _, Cheap<char>>(|c: &char| c.is_ascii_digit())
.repeated().at_least(1)
.collect::<String>()
.map(|s| Token::Num(s.parse().unwrap()));
let token = word.or(num);
assert_eq!(token.parse("test"), Ok(Token::Word("test".to_string())));
assert_eq!(token.parse("42"), Ok(Token::Num(42)));
fn map_with_span<U, F>(self, f: F) -> MapWithSpan<Self, F, O> where
Self: Sized,
F: Fn(O, <Self::Error as Error<I>>::Span) -> U,
fn map_with_span<U, F>(self, f: F) -> MapWithSpan<Self, F, O> where
Self: Sized,
F: Fn(O, <Self::Error as Error<I>>::Span) -> U,
Map the output of this parser to another value, making use of the pattern’s span when doing so.
This is very useful when generating an AST that attaches a span to each AST node.
The output type of this parser is U
, the same as the function’s output.
Examples
use std::ops::Range;
// It's common for AST nodes to use a wrapper type that allows attaching span information to them
#[derive(Debug, PartialEq)]
pub struct Spanned<T>(T, Range<usize>);
let ident = text::ident::<_, Simple<char>>()
.map_with_span(|ident, span| Spanned(ident, span))
.padded();
assert_eq!(ident.parse("hello"), Ok(Spanned("hello".to_string(), 0..5)));
assert_eq!(ident.parse(" hello "), Ok(Spanned("hello".to_string(), 7..12)));
Map the primary error of this parser to another value.
This function is most useful when using a custom error type, allowing you to augment errors according to context.
The output type of this parser is O
, the same as the original parser.
Map the primary error of this parser to a result. If the result is Ok
, the parser succeeds with that value.
Note that even if the function returns an Ok
, the input stream will still be ‘stuck’ at the input following
the input that triggered the error. You’ll need to follow uses of this combinator with a parser that resets
the input stream to a known-good state (for example, take_until
).
The output type of this parser is U
, the Ok
type of the result.
fn map_err_with_span<F>(self, f: F) -> MapErrWithSpan<Self, F> where
Self: Sized,
F: Fn(Self::Error, <Self::Error as Error<I>>::Span) -> Self::Error,
fn map_err_with_span<F>(self, f: F) -> MapErrWithSpan<Self, F> where
Self: Sized,
F: Fn(Self::Error, <Self::Error as Error<I>>::Span) -> Self::Error,
Map the primary error of this parser to another value, making use of the span from the start of the attempted to the point at which the error was encountered.
This function is useful for augmenting errors to allow them to display the span of the initial part of a pattern, for example to add a “while parsing” clause to your error messages.
The output type of this parser is O
, the same as the original parser.
After a successful parse, apply a fallible function to the output. If the function produces an error, treat it as a parsing error.
If you wish parsing of this pattern to continue when an error is generated instead of halting, consider using
Parser::validate
instead.
The output type of this parser is U
, the Ok
return value of the function.
Examples
let byte = text::int::<_, Simple<char>>(10)
.try_map(|s, span| s
.parse::<u8>()
.map_err(|e| Simple::custom(span, format!("{}", e))));
assert!(byte.parse("255").is_ok());
assert!(byte.parse("256").is_err()); // Out of range
Validate an output, producing non-terminal errors if it does not fulfil certain criteria.
This function also permits mapping the output to a value of another type, similar to Parser::map
.
If you wish parsing of this pattern to halt when an error is generated instead of continuing, consider using
Parser::try_map
instead.
The output type of this parser is O
, the same as the original parser.
Examples
let large_int = text::int::<char, _>(10)
.from_str()
.unwrapped()
.validate(|x: u32, span, emit| {
if x < 256 { emit(Simple::custom(span, format!("{} must be 256 or higher.", x))) }
x
});
assert_eq!(large_int.parse("537"), Ok(537));
assert!(large_int.parse("243").is_err());
Label the pattern parsed by this parser for more useful error messages.
This is useful when you want to give users a more useful description of an expected pattern than simply a list of possible initial tokens. For example, it’s common to use the term “expression” at a catch-all for a number of different constructs in many languages.
This does not label recovered errors generated by sub-patterns within the parser, only error directly emitted by the parser.
This does not label errors where the labelled pattern consumed input (i.e: in unambiguous cases).
The output type of this parser is O
, the same as the original parser.
Note: There is a chance that this method will be deprecated in favour of a more general solution in later versions of the crate.
Examples
let frac = text::digits(10)
.chain(just('.'))
.chain::<char, _, _>(text::digits(10))
.collect::<String>()
.then_ignore(end())
.labelled("number");
assert_eq!(frac.parse("42.3"), Ok("42.3".to_string()));
assert_eq!(frac.parse("hello"), Err(vec![Cheap::expected_input_found(0..1, Vec::new(), Some('h')).with_label("number")]));
assert_eq!(frac.parse("42!"), Err(vec![Cheap::expected_input_found(2..3, vec![Some('.')], Some('!')).with_label("number")]));
Transform all outputs of this parser to a pretermined value.
The output type of this parser is U
, the type of the predetermined value.
Examples
#[derive(Clone, Debug, PartialEq)]
enum Op { Add, Sub, Mul, Div }
let op = just::<_, _, Cheap<char>>('+').to(Op::Add)
.or(just('-').to(Op::Sub))
.or(just('*').to(Op::Mul))
.or(just('/').to(Op::Div));
assert_eq!(op.parse("+"), Ok(Op::Add));
assert_eq!(op.parse("/"), Ok(Op::Div));
Left-fold the output of the parser into a single value.
The output of the original parser must be of type (A, impl IntoIterator<Item = B>)
.
The output type of this parser is A
, the left-hand component of the original parser’s output.
Examples
let int = text::int::<char, Cheap<char>>(10)
.from_str()
.unwrapped();
let sum = int
.then(just('+').ignore_then(int).repeated())
.foldl(|a, b| a + b);
assert_eq!(sum.parse("1+12+3+9"), Ok(25));
assert_eq!(sum.parse("6"), Ok(6));
Right-fold the output of the parser into a single value.
The output of the original parser must be of type (impl IntoIterator<Item = A>, B)
. Because right-folds work
backwards, the iterator must implement DoubleEndedIterator
so that it can be reversed.
The output type of this parser is B
, the right-hand component of the original parser’s output.
Examples
let int = text::int::<char, Cheap<char>>(10)
.from_str()
.unwrapped();
let signed = just('+').to(1)
.or(just('-').to(-1))
.repeated()
.then(int)
.foldr(|a, b| a * b);
assert_eq!(signed.parse("3"), Ok(3));
assert_eq!(signed.parse("-17"), Ok(-17));
assert_eq!(signed.parse("--+-+-5"), Ok(5));
Ignore the output of this parser, yielding ()
as an output instead.
This can be used to reduce the cost of parsing by avoiding unnecessary allocations (most collections containing
ZSTs
do not allocate). For example, it’s common to
want to ignore whitespace in many grammars (see text::whitespace
).
The output type of this parser is ()
.
Examples
// A parser that parses any number of whitespace characters without allocating
let whitespace = filter::<_, _, Cheap<char>>(|c: &char| c.is_whitespace())
.ignored()
.repeated();
assert_eq!(whitespace.parse(" "), Ok(vec![(); 4]));
assert_eq!(whitespace.parse(" hello"), Ok(vec![(); 2]));
fn collect<C>(self) -> Map<Self, fn(_: O) -> C, O> where
Self: Sized,
O: IntoIterator,
C: FromIterator<O::Item>,
fn collect<C>(self) -> Map<Self, fn(_: O) -> C, O> where
Self: Sized,
O: IntoIterator,
C: FromIterator<O::Item>,
Collect the output of this parser into a type implementing FromIterator
.
This is commonly useful for collecting Vec<char>
outputs into String
s, or [(T, U)
] into a
HashMap
and is analagous to Iterator::collect
.
The output type of this parser is C
, the type being collected into.
Examples
let word = filter::<_, _, Cheap<char>>(|c: &char| c.is_alphabetic()) // This parser produces an output of `char`
.repeated() // This parser produces an output of `Vec<char>`
.collect::<String>(); // But `Vec<char>` is less useful than `String`, so convert to the latter
assert_eq!(word.parse("hello"), Ok("hello".to_string()));
Parse one thing and then another thing, yielding a tuple of the two outputs.
The output type of this parser is (O, U)
, a combination of the outputs of both parsers.
Examples
let word = filter::<_, _, Cheap<char>>(|c: &char| c.is_alphabetic())
.repeated().at_least(1)
.collect::<String>();
let two_words = word.then_ignore(just(' ')).then(word);
assert_eq!(two_words.parse("dog cat"), Ok(("dog".to_string(), "cat".to_string())));
assert!(two_words.parse("hedgehog").is_err());
Parse one thing and then another thing, creating the second parser from the result of
the first. If you only have a couple cases to handle, prefer Parser::or
.
The output of this parser is U
, the result of the second parser
Error recovery for this parser may be sub-optimal, as if the first parser succeeds on recovery then the second produces an error, the primary error will point to the location in the second parser which failed, ignoring that the first parser may be the root cause. There may be other pathological errors cases as well.
Examples
let letter_up = one_of::<_, _, Cheap<u8>>((b'a'..=b'z').collect::<Vec<u8>>())
.then_with(|letter: u8| just(letter + 1));
assert_eq!(letter_up.parse(*b"ab"), Ok(b'b'));
assert!(letter_up.parse(*b"ac").is_err());
Parse one thing and then another thing, attempting to chain the two outputs into a Vec
.
The output type of this parser is Vec<T>
, composed of the elements of the outputs of both parsers.
Examples
let int = just('-').or_not()
.chain(filter::<_, _, Cheap<char>>(|c: &char| c.is_ascii_digit() && *c != '0')
.chain(filter::<_, _, Cheap<char>>(|c: &char| c.is_ascii_digit()).repeated()))
.or(just('0').map(|c| vec![c]))
.then_ignore(end())
.collect::<String>()
.from_str()
.unwrapped();
assert_eq!(int.parse("0"), Ok(0));
assert_eq!(int.parse("415"), Ok(415));
assert_eq!(int.parse("-50"), Ok(-50));
assert!(int.parse("-0").is_err());
assert!(int.parse("05").is_err());
fn flatten<T, Inner>(self) -> Map<Self, fn(_: O) -> Vec<T>, O> where
Self: Sized,
O: IntoIterator<Item = Inner>,
Inner: IntoIterator<Item = T>,
fn flatten<T, Inner>(self) -> Map<Self, fn(_: O) -> Vec<T>, O> where
Self: Sized,
O: IntoIterator<Item = Inner>,
Inner: IntoIterator<Item = T>,
Flatten a nested collection.
This use-cases of this method are broadly similar to those of Iterator::flatten
.
The output type of this parser is Vec<T>
, where the original parser output was
impl IntoIterator<Item = impl IntoIterator<Item = T>>
.
fn ignore_then<U, P>(self, other: P) -> IgnoreThen<Self, P, O, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
fn ignore_then<U, P>(self, other: P) -> IgnoreThen<Self, P, O, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
Parse one thing and then another thing, yielding only the output of the latter.
The output type of this parser is U
, the same as the second parser.
Examples
let zeroes = filter::<_, _, Cheap<char>>(|c: &char| *c == '0').ignored().repeated();
let digits = filter(|c: &char| c.is_ascii_digit()).repeated();
let integer = zeroes
.ignore_then(digits)
.collect::<String>()
.from_str()
.unwrapped();
assert_eq!(integer.parse("00064"), Ok(64));
assert_eq!(integer.parse("32"), Ok(32));
fn then_ignore<U, P>(self, other: P) -> ThenIgnore<Self, P, O, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
fn then_ignore<U, P>(self, other: P) -> ThenIgnore<Self, P, O, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
Parse one thing and then another thing, yielding only the output of the former.
The output type of this parser is O
, the same as the original parser.
Examples
let word = filter::<_, _, Cheap<char>>(|c: &char| c.is_alphabetic())
.repeated().at_least(1)
.collect::<String>();
let punctuated = word
.then_ignore(just('!').or(just('?')).or_not());
let sentence = punctuated
.padded() // Allow for whitespace gaps
.repeated();
assert_eq!(
sentence.parse("hello! how are you?"),
Ok(vec![
"hello".to_string(),
"how".to_string(),
"are".to_string(),
"you".to_string(),
]),
);
fn padded_by<U, P>(
self,
other: P
) -> ThenIgnore<IgnoreThen<P, Self, U, O>, P, O, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error> + Clone,
fn padded_by<U, P>(
self,
other: P
) -> ThenIgnore<IgnoreThen<P, Self, U, O>, P, O, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error> + Clone,
Parse a pattern, but with an instance of another pattern on either end, yielding the output of the inner.
The output type of this parser is O
, the same as the original parser.
Examples
let ident = text::ident::<_, Simple<char>>()
.padded_by(just('!'));
assert_eq!(ident.parse("!hello!"), Ok("hello".to_string()));
assert!(ident.parse("hello!").is_err());
assert!(ident.parse("!hello").is_err());
assert!(ident.parse("hello").is_err());
fn delimited_by<U, V, L, R>(
self,
start: L,
end: R
) -> DelimitedBy<Self, L, R, U, V> where
Self: Sized,
L: Parser<I, U, Error = Self::Error>,
R: Parser<I, V, Error = Self::Error>,
fn delimited_by<U, V, L, R>(
self,
start: L,
end: R
) -> DelimitedBy<Self, L, R, U, V> where
Self: Sized,
L: Parser<I, U, Error = Self::Error>,
R: Parser<I, V, Error = Self::Error>,
Parse the pattern surrounded by the given delimiters.
The output type of this parser is O
, the same as the original parser.
Examples
// A LISP-style S-expression
#[derive(Debug, PartialEq)]
enum SExpr {
Ident(String),
Num(u64),
List(Vec<SExpr>),
}
let ident = filter::<_, _, Cheap<char>>(|c: &char| c.is_alphabetic())
.repeated().at_least(1)
.collect::<String>();
let num = text::int(10)
.from_str()
.unwrapped();
let s_expr = recursive(|s_expr| s_expr
.padded()
.repeated()
.map(SExpr::List)
.delimited_by(just('('), just(')'))
.or(ident.map(SExpr::Ident))
.or(num.map(SExpr::Num)));
// A valid input
assert_eq!(
s_expr.parse_recovery("(add (mul 42 3) 15)"),
(
Some(SExpr::List(vec![
SExpr::Ident("add".to_string()),
SExpr::List(vec![
SExpr::Ident("mul".to_string()),
SExpr::Num(42),
SExpr::Num(3),
]),
SExpr::Num(15),
])),
Vec::new(), // No errors!
),
);
Parse one thing or, on failure, another thing.
The output of both parsers must be of the same type, because either output can be produced.
If both parser succeed, the output of the first parser is guaranteed to be prioritised over the output of the second.
If both parsers produce errors, the combinator will attempt to select from or combine the errors to produce an error that is most likely to be useful to a human attempting to understand the problem. The exact algorithm used is left unspecified, and is not part of the crate’s semver guarantees, although regressions in error quality should be reported in the issue tracker of the main repository.
Please note that long chains of Parser::or
combinators have been known to result in poor compilation times.
If you feel you are experiencing this, consider using choice
instead.
The output type of this parser is O
, the output of both parsers.
Examples
let op = just::<_, _, Cheap<char>>('+')
.or(just('-'))
.or(just('*'))
.or(just('/'));
assert_eq!(op.parse("+"), Ok('+'));
assert_eq!(op.parse("/"), Ok('/'));
assert!(op.parse("!").is_err());
Apply a fallback recovery strategy to this parser should it fail.
There is no silver bullet for error recovery, so this function allows you to specify one of several different strategies at the location of your choice. Prefer an error recovery strategy that more precisely mirrors valid syntax where possible to make error recovery more reliable.
Because chumsky is a PEG parser, which always take the first successful parsing route through a grammar, recovering from an error may cause the parser to erroneously miss alternative valid routes through the grammar that do not generate recoverable errors. If you run into cases where valid syntax fails to parse without errors, this might be happening: consider removing error recovery or switching to a more specific error recovery strategy.
The output type of this parser is O
, the same as the original parser.
Examples
#[derive(Debug, PartialEq)]
enum Expr {
Error,
Int(String),
List(Vec<Expr>),
}
let expr = recursive::<_, _, _, _, Simple<char>>(|expr| expr
.separated_by(just(','))
.delimited_by(just('['), just(']'))
.map(Expr::List)
// If parsing a list expression fails, recover at the next delimiter, generating an error AST node
.recover_with(nested_delimiters('[', ']', [], |_| Expr::Error))
.or(text::int(10).map(Expr::Int))
.padded());
assert!(expr.parse("five").is_err()); // Text is not a valid expression in this language...
assert!(expr.parse("[1, 2, 3]").is_ok()); // ...but lists and numbers are!
// This input has two syntax errors...
let (ast, errors) = expr.parse_recovery("[[1, two], [3, four]]");
// ...and error recovery allows us to catch both of them!
assert_eq!(errors.len(), 2);
// Additionally, the AST we get back still has useful information.
assert_eq!(ast, Some(Expr::List(vec![Expr::Error, Expr::Error])));
Attempt to parse something, but only if it exists.
If parsing of the pattern is successful, the output is Some(_)
. Otherwise, the output is None
.
The output type of this parser is Option<O>
.
Examples
let word = filter::<_, _, Cheap<char>>(|c: &char| c.is_alphabetic())
.repeated().at_least(1)
.collect::<String>();
let word_or_question = word
.then(just('?').or_not());
assert_eq!(word_or_question.parse("hello?"), Ok(("hello".to_string(), Some('?'))));
assert_eq!(word_or_question.parse("wednesday"), Ok(("wednesday".to_string(), None)));
Parse a pattern any number of times (including zero times).
Input is eagerly parsed. Be aware that the parser will accept no occurences of the pattern too. Consider using
Repeated::at_least
instead if it better suits your use-case.
The output type of this parser is Vec<O>
.
Examples
let num = filter::<_, _, Cheap<char>>(|c: &char| c.is_ascii_digit())
.repeated().at_least(1)
.collect::<String>()
.from_str()
.unwrapped();
let sum = num.then(just('+').ignore_then(num).repeated())
.foldl(|a, b| a + b);
assert_eq!(sum.parse("2+13+4+0+5"), Ok(24));
fn separated_by<U, P>(self, other: P) -> SeparatedBy<Self, P, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
fn separated_by<U, P>(self, other: P) -> SeparatedBy<Self, P, U> where
Self: Sized,
P: Parser<I, U, Error = Self::Error>,
Parse a pattern, separated by another, any number of times.
You can use SeparatedBy::allow_leading
or SeparatedBy::allow_trailing
to allow leading or trailing
separators.
The output type of this parser is Vec<O>
.
Examples
let shopping = text::ident::<_, Simple<char>>()
.padded()
.separated_by(just(','));
assert_eq!(shopping.parse("eggs"), Ok(vec!["eggs".to_string()]));
assert_eq!(shopping.parse("eggs, flour, milk"), Ok(vec!["eggs".to_string(), "flour".to_string(), "milk".to_string()]));
See SeparatedBy::allow_leading
and SeparatedBy::allow_trailing
for more examples.
Parse a pattern. Afterwards, the input stream will be rewound to its original state, as if parsing had not occurred.
This combinator is useful for cases in which you wish to avoid a parser accidentally consuming too much input, causing later parsers to fail as a result. A typical use-case of this is that you want to parse something that is not followed by something else.
The output type of this parser is O
, the same as the original parser.
Examples
let just_numbers = text::digits::<_, Simple<char>>(10)
.padded()
.then_ignore(none_of("+-*/").rewind())
.separated_by(just(','));
// 3 is not parsed because it's followed by '+'.
assert_eq!(just_numbers.parse("1, 2, 3 + 4"), Ok(vec!["1".to_string(), "2".to_string()]));
fn boxed<'a>(self) -> BoxedParser<'a, I, O, Self::Error> where
Self: Sized + 'a,
fn boxed<'a>(self) -> BoxedParser<'a, I, O, Self::Error> where
Self: Sized + 'a,
Box the parser, yielding a parser that performs parsing through dynamic dispatch.
Boxing a parser might be useful for:
-
Dynamically building up parsers at runtime
-
Improving compilation times (Rust can struggle to compile code containing very long types)
-
Passing a parser over an FFI boundary
-
Getting around compiler implementation problems with long types such as this.
-
Places where you need to name the type of a parser
Boxing a parser is broadly equivalent to boxing other combinators via dynamic dispatch, such as Iterator
.
The output type of this parser is O
, the same as the original parser.
Attempt to convert the output of this parser into something else using Rust’s FromStr
trait.
This is most useful when wanting to convert literal values into their corresponding Rust type, such as when parsing integers.
The output type of this parser is Result<U, U::Err>
, the result of attempting to parse the output, O
, into
the value U
.
Examples
let uint64 = text::int::<_, Simple<char>>(10)
.from_str::<u64>()
.unwrapped();
assert_eq!(uint64.parse("7"), Ok(7));
assert_eq!(uint64.parse("42"), Ok(42));
For parsers that produce a Result
as their output, unwrap the result (panicking if an Err
is
encountered).
In general, this method should be avoided except in cases where all possible that the parser might produce can
by parsed using FromStr
without producing an error.
This combinator is not named unwrap
to avoid confusion: it unwraps during parsing, not immediately.
The output type of this parser is U
, the Ok
value of the Result
.
Examples
let boolean = just::<_, _, Simple<char>>("true")
.or(just("false"))
.from_str::<bool>()
.unwrapped(); // Cannot panic: the only possible outputs generated by the parser are "true" or "false"
assert_eq!(boolean.parse("true"), Ok(true));
assert_eq!(boolean.parse("false"), Ok(false));
// Does not panic, because the original parser only accepts "true" or "false"
assert!(boolean.parse("42").is_err());