+ Default,
P: Parser,
S: Parser,
{
SepEndBy1 {
parser,
separator,
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct Chainl1(P, Op);
impl Parser for Chainl1
where
Input: Stream,
P: Parser,
Op: Parser,
Op::Output: FnOnce(P::Output, P::Output) -> P::Output,
{
type Output = P::Output;
type PartialState = (
Option<(P::Output, Commit<()>)>,
<(Op, P) as Parser>::PartialState,
);
parse_mode!(Input);
#[inline]
fn parse_mode_impl(
&mut self,
mut mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult
where
M: ParseMode,
{
let (ref mut l_state, ref mut child_state) = *state;
let (mut l, mut committed) = match l_state.take() {
Some(x) => x,
None => {
let x = ctry!(self.0.parse_partial(input, &mut child_state.B.state));
mode.set_first();
x
}
};
loop {
let before = input.checkpoint();
match (&mut self.1, &mut self.0)
.parse_mode(mode, input, child_state)
.into()
{
Ok(((op, r), rest)) => {
l = op(l, r);
committed = committed.merge(rest);
mode.set_first();
}
Err(Commit::Commit(err)) => {
*l_state = Some((l, committed));
return CommitErr(err.error);
}
Err(Commit::Peek(_)) => {
ctry!(input.reset(before).committed());
break;
}
}
}
Ok((l, committed)).into()
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
self.0.add_error(errors)
}
}
/// Parses `p` 1 or more times separated by `op`. The value returned is the one produced by the
/// left associative application of the function returned by the parser `op`.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char::digit;
/// # fn main() {
/// let number = digit().map(|c: char| c.to_digit(10).unwrap());
/// let sub = token('-').map(|_| |l: u32, r: u32| l - r);
/// let mut parser = chainl1(number, sub);
/// assert_eq!(parser.parse("9-3-5"), Ok((1, "")));
/// # }
/// ```
pub fn chainl1(parser: P, op: Op) -> Chainl1
where
Input: Stream,
P: Parser,
Op: Parser,
Op::Output: FnOnce(P::Output, P::Output) -> P::Output,
{
Chainl1(parser, op)
}
#[derive(Copy, Clone)]
pub struct Chainr1
(P, Op);
impl Parser for Chainr1
where
Input: Stream,
P: Parser,
Op: Parser,
Op::Output: FnOnce(P::Output, P::Output) -> P::Output,
{
type Output = P::Output;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
// FIXME FastResult
let (mut l, mut committed) = ctry!(self.0.parse_lazy(input));
loop {
let before = input.checkpoint();
let op = match self.1.parse_lazy(input).into() {
Ok((x, rest)) => {
committed = committed.merge(rest);
x
}
Err(Commit::Commit(err)) => return CommitErr(err.error),
Err(Commit::Peek(_)) => {
ctry!(input.reset(before).committed());
break;
}
};
let before = input.checkpoint();
match self.parse_lazy(input).into() {
Ok((r, rest)) => {
l = op(l, r);
committed = committed.merge(rest);
}
Err(Commit::Commit(err)) => return CommitErr(err.error),
Err(Commit::Peek(_)) => {
ctry!(input.reset(before).committed());
break;
}
}
}
Ok((l, committed)).into()
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
self.0.add_error(errors)
}
}
/// Parses `p` one or more times separated by `op`. The value returned is the one produced by the
/// right associative application of the function returned by `op`.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char::digit;
/// # fn main() {
/// let number = digit().map(|c: char| c.to_digit(10).unwrap());
/// let pow = token('^').map(|_| |l: u32, r: u32| l.pow(r));
/// let mut parser = chainr1(number, pow);
/// assert_eq!(parser.parse("2^3^2"), Ok((512, "")));
/// }
/// ```
pub fn chainr1(parser: P, op: Op) -> Chainr1
where
Input: Stream,
P: Parser,
Op: Parser,
Op::Output: FnOnce(P::Output, P::Output) -> P::Output,
{
Chainr1(parser, op)
}
#[derive(Copy, Clone)]
pub struct TakeUntil {
end: P,
_marker: PhantomData F>,
}
impl Parser for TakeUntil
where
Input: Stream,
F: Extend<::Token> + Default,
P: Parser,
{
type Output = F;
type PartialState = (F, P::PartialState);
parse_mode!(Input);
#[inline]
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult
where
M: ParseMode,
{
let (ref mut output, ref mut end_state) = *state;
let mut committed = Commit::Peek(());
loop {
let before = input.checkpoint();
match self.end.parse_mode(mode, input, end_state).into() {
Ok((_, rest)) => {
ctry!(input.reset(before).committed());
return match committed.merge(rest) {
Commit::Commit(()) => CommitOk(mem::take(output)),
Commit::Peek(()) => PeekOk(mem::take(output)),
};
}
Err(Commit::Peek(_)) => {
ctry!(input.reset(before).committed());
output.extend(Some(ctry!(uncons(input)).0));
committed = Commit::Commit(());
}
Err(Commit::Commit(e)) => {
ctry!(input.reset(before).committed());
return CommitErr(e.error);
}
};
}
}
}
/// Takes input until `end` is encountered or `end` indicates that it has committed input before
/// failing (`attempt` can be used to make it look like it has not committed any input)
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char;
/// # use combine::parser::byte;
/// # use combine::parser::combinator::attempt;
/// # use combine::parser::repeat::take_until;
/// # fn main() {
/// let mut char_parser = take_until(char::digit());
/// assert_eq!(char_parser.parse("abc123"), Ok(("abc".to_string(), "123")));
///
/// let mut byte_parser = take_until(byte::bytes(&b"TAG"[..]));
/// assert_eq!(byte_parser.parse(&b"123TAG"[..]), Ok((b"123".to_vec(), &b"TAG"[..])));
/// assert!(byte_parser.parse(&b"123TATAG"[..]).is_err());
///
/// // `attempt` must be used if the `end` should be consume input before failing
/// let mut byte_parser = take_until(attempt(byte::bytes(&b"TAG"[..])));
/// assert_eq!(byte_parser.parse(&b"123TATAG"[..]), Ok((b"123TA".to_vec(), &b"TAG"[..])));
/// # }
/// ```
pub fn take_until(end: P) -> TakeUntil
where
Input: Stream,
F: Extend<::Token> + Default,
P: Parser,
{
TakeUntil {
end,
_marker: PhantomData,
}
}
parser! {
pub struct SkipUntil;
type PartialState = , Value> as Parser>::PartialState;
/// Skips input until `end` is encountered or `end` indicates that it has committed input before
/// failing (`attempt` can be used to make it look like it has not committed any input)
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char;
/// # use combine::parser::byte;
/// # use combine::parser::combinator::attempt;
/// # use combine::parser::repeat::skip_until;
/// # fn main() {
/// let mut char_parser = skip_until(char::digit());
/// assert_eq!(char_parser.parse("abc123"), Ok(((), "123")));
///
/// let mut byte_parser = skip_until(byte::bytes(&b"TAG"[..]));
/// assert_eq!(byte_parser.parse(&b"123TAG"[..]), Ok(((), &b"TAG"[..])));
/// assert!(byte_parser.parse(&b"123TATAG"[..]).is_err());
///
/// // `attempt` must be used if the `end` should consume input before failing
/// let mut byte_parser = skip_until(attempt(byte::bytes(&b"TAG"[..])));
/// assert_eq!(byte_parser.parse(&b"123TATAG"[..]), Ok(((), &b"TAG"[..])));
/// # }
/// ```
pub fn skip_until[Input, P](end: P)(Input) -> ()
where [
P: Parser,
]
{
take_until::(end).with(value(()))
}
}
#[derive(Copy, Clone)]
pub struct RepeatUntil {
parser: P,
end: E,
_marker: PhantomData F>,
}
impl Parser for RepeatUntil
where
Input: Stream,
F: Extend + Default,
P: Parser,
E: Parser,
{
type Output = F;
type PartialState = (F, bool, P::PartialState, E::PartialState);
parse_mode!(Input);
#[inline]
fn parse_mode_impl(
&mut self,
mut mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult
where
M: ParseMode,
{
let (output, is_parse, parse_state, end_state) = state;
let mut committed = Commit::Peek(());
loop {
if *is_parse {
let (token, c) = ctry!(self.parser.parse_mode(mode, input, parse_state));
output.extend(Some(token));
committed = committed.merge(c);
*is_parse = false;
} else {
let before = input.checkpoint();
match self.end.parse_mode(mode, input, end_state).into() {
Ok((_, rest)) => {
ctry!(input.reset(before).committed());
return match committed.merge(rest) {
Commit::Commit(()) => CommitOk(mem::take(output)),
Commit::Peek(()) => PeekOk(mem::take(output)),
};
}
Err(Commit::Peek(_)) => {
ctry!(input.reset(before).committed());
mode.set_first();
*is_parse = true;
}
Err(Commit::Commit(e)) => {
ctry!(input.reset(before).committed());
return CommitErr(e.error);
}
}
}
}
}
}
pub fn repeat_until(parser: P, end: E) -> RepeatUntil
where
Input: Stream,
F: Extend + Default,
P: Parser,
E: Parser,
{
RepeatUntil {
parser,
end,
_marker: PhantomData,
}
}
parser! {
pub struct SkipRepeatUntil;
type PartialState = , Value> as Parser>::PartialState;
/// Skips input until `end` is encountered or `end` indicates that it has committed input before
/// failing (`attempt` can be used to continue skipping even if `end` has committed input)
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char;
/// # use combine::parser::byte;
/// # use combine::parser::combinator::attempt;
/// # use combine::parser::repeat::skip_until;
/// # fn main() {
/// let mut char_parser = skip_until(char::digit());
/// assert_eq!(char_parser.parse("abc123"), Ok(((), "123")));
///
/// let mut byte_parser = skip_until(byte::bytes(&b"TAG"[..]));
/// assert_eq!(byte_parser.parse(&b"123TAG"[..]), Ok(((), &b"TAG"[..])));
/// assert!(byte_parser.parse(&b"123TATAG"[..]).is_err());
///
/// // `attempt` must be used because the `end` will commit to `TA` before failing,
/// // but we want to continue skipping
/// let mut byte_parser = skip_until(attempt(byte::bytes(&b"TAG"[..])));
/// assert_eq!(byte_parser.parse(&b"123TATAG"[..]), Ok(((), &b"TAG"[..])));
/// }
/// ```
pub fn repeat_skip_until[Input, P, E](parser: P, end: E)(Input) -> ()
where [
P: Parser,
E: Parser,
]
{
repeat_until::(parser, end).with(value(()))
}
}
#[derive(Default)]
pub struct EscapedState(PhantomData<(T, U)>);
pub struct Escaped {
parser: P,
escape: I,
escape_parser: Q,
}
impl Parser for Escaped
where
Input: Stream,
P: Parser,
::Token: PartialEq,
Q: Parser,
{
type Output = ();
type PartialState = EscapedState;
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
let mut committed = Commit::Peek(());
loop {
match self.parser.parse_lazy(input) {
PeekOk(_) => {}
CommitOk(_) => {
committed = Commit::Commit(());
}
PeekErr(_) => {
let checkpoint = input.checkpoint();
match uncons(input) {
CommitOk(ref c) | PeekOk(ref c) if *c == self.escape => {
match self.escape_parser.parse_committed_mode(
FirstMode,
input,
&mut Default::default(),
) {
PeekOk(_) => {}
CommitOk(_) => {
committed = Commit::Commit(());
}
CommitErr(err) => return CommitErr(err),
PeekErr(err) => {
return CommitErr(err.error);
}
}
}
CommitErr(err) => {
return CommitErr(err);
}
_ => {
ctry!(input.reset(checkpoint).committed());
return if committed.is_peek() {
PeekOk(())
} else {
CommitOk(())
};
}
}
}
CommitErr(err) => return CommitErr(err),
}
}
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
use crate::error;
self.parser.add_error(errors);
errors.error.add_expected(error::Token(self.escape.clone()));
}
}
/// Parses an escaped string by first applying `parser` which accept the normal characters which do
/// not need escaping. Once `parser` can not consume any more input it checks if the next token
/// is `escape`. If it is then `escape_parser` is used to parse the escaped character and then
/// resumes parsing using `parser`. If `escape` was not found then the parser finishes
/// successfully.
///
/// This returns `()` since there isn't a good way to collect the output of the parsers so it is
/// best paired with one of the `recognize` parsers.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::repeat::escaped;
/// # use combine::parser::char;
/// # use combine::parser::range::{recognize, take_while1};
/// # fn main() {
/// let mut parser = recognize(
/// escaped(take_while1(|c| c != '"' && c != '\\'), '\\', one_of(r#"nr"\"#.chars()))
/// );
/// assert_eq!(parser.parse(r#"ab\"12\n\rc""#), Ok((r#"ab\"12\n\rc"#, r#"""#)));
/// assert!(parser.parse(r#"\"#).is_err());
/// assert!(parser.parse(r#"\a"#).is_err());
/// }
/// ```
pub fn escaped(
parser: P,
escape: ::Token,
escape_parser: Q,
) -> Escaped
where
Input: Stream,
P: Parser,
::Token: PartialEq,
Q: Parser,
{
Escaped {
parser,
escape,
escape_parser,
}
}
pub struct Iterate {
parser: P,
iterable: I,
_marker: PhantomData F>,
}
impl<'s, 'a, P, Q, I, J, F> Parser for Iterate
where
P: FnMut(&J::Item, &mut I) -> Q,
Q: Parser,
I: Stream,
J: IntoIterator + Clone,
F: Extend + Default,
{
type Output = F;
type PartialState = (
Option<(J::IntoIter, Option)>,
bool,
F,
Q::PartialState,
);
parse_mode!(I);
fn parse_mode_impl(
&mut self,
mut mode: M,
input: &mut I,
state: &mut Self::PartialState,
) -> ParseResult
where
M: ParseMode,
{
let (opt_iter, committed, buf, next) = state;
let (iter, next_item) = match opt_iter {
Some(iter) if !mode.is_first() => iter,
_ => {
*opt_iter = Some((self.iterable.clone().into_iter(), None));
opt_iter.as_mut().unwrap()
}
};
let mut consume = |item: J::Item| {
let mut parser = (self.parser)(&item, input);
let before = input.checkpoint();
match parser.parse_mode(mode, input, next) {
PeekOk(v) => {
mode.set_first();
Ok(v)
}
CommitOk(v) => {
mode.set_first();
*committed = true;
Ok(v)
}
PeekErr(err) => {
if let Err(err) = input.reset(before) {
return Err((item, CommitErr(err)));
}
Err((
item,
if *committed {
CommitErr(err.error)
} else {
PeekErr(err)
},
))
}
CommitErr(err) => Err((item, CommitErr(err))),
}
};
let result = (|| {
if let Some(item) = next_item.take() {
buf.extend(Some(consume(item)?));
}
let mut result = Ok(());
let size_hint = iter.size_hint();
buf.extend(suggest_size_hint(
iter.scan((), |_, item| match consume(item) {
Ok(item) => Some(item),
Err(err) => {
result = Err(err);
None
}
}),
size_hint,
));
result
})();
if let Err((item, err)) = result {
*next_item = Some(item);
return err;
}
opt_iter.take();
let value = mem::take(buf);
if *committed {
*committed = false;
CommitOk(value)
} else {
PeekOk(value)
}
}
}
///
/// ```
/// # use combine::parser::repeat::{count_min_max, iterate};
/// # use combine::*;
///
/// assert_eq!(
/// iterate(0..3, |&i, _| count_min_max(i, i, any())).parse("abbccc"),
/// Ok((vec!["".to_string(), "a".to_string(), "bb".to_string()], "ccc")),
/// );
/// ```
pub fn iterate(iterable: J, parser: P) -> Iterate
where
P: FnMut(&J::Item, &mut I) -> Q,
Q: Parser,
I: Stream,
J: IntoIterator + Clone,
F: Extend + Default,
{
Iterate {
parser,
iterable,
_marker: PhantomData,
}
}