Skip to content

Commit

Permalink
Add 'try_collect'.
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioBenitez committed Feb 11, 2020
1 parent 218ba04 commit 2b6532e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
36 changes: 33 additions & 3 deletions lib/src/combinators.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::hash::Hash;
use std::collections::{HashMap, BTreeMap};

use crate::input::{Input, Token, Result};
use crate::input::{Input, Rewind, Token, Result};
use crate::macros::parser;
use crate::parsers::*;

Expand Down Expand Up @@ -76,7 +76,7 @@ pub fn surrounded<I, O, F, P>(input: &mut I, mut p: P, mut f: F) -> Result<O, I>
}

/// Parses as many `p` as possible until EOF is reached, collecting them into a
/// `C`. `C` may be empty.
/// `C`. Fails if `p` every fails. `C` may be empty.
#[parser(raw)]
pub fn collect<C, I, O, P>(input: &mut I, mut p: P) -> Result<C, I>
where C: Collection<Item=O>, I: Input, P: FnMut(&mut I) -> Result<O, I>
Expand All @@ -92,7 +92,7 @@ pub fn collect<C, I, O, P>(input: &mut I, mut p: P) -> Result<C, I>
}

/// Parses as many `p` as possible until EOF is reached, collecting them into a
/// `C`. `C` is not allowed to be empty.
/// `C`. Fails if `p` ever fails. `C` is not allowed to be empty.
#[parser(raw)]
pub fn collect_some<C, I, O, P>(input: &mut I, mut p: P) -> Result<C, I>
where C: Collection<Item=O>, I: Input, P: FnMut(&mut I) -> Result<O, I>
Expand All @@ -106,6 +106,36 @@ pub fn collect_some<C, I, O, P>(input: &mut I, mut p: P) -> Result<C, I>
}
}

/// Parses as many `p` as possible until EOF is reached or `p` fails, collecting
/// them into a `C`. `C` may be empty.
#[parser(raw)]
pub fn try_collect<C, I, O, P>(input: &mut I, mut p: P) -> Result<C, I>
where C: Collection<Item=O>, I: Input + Rewind, P: FnMut(&mut I) -> Result<O, I>
{
let mut collection = C::new();
loop {
if eof(input).is_ok() {
return Ok(collection);
}

// FIXME: We should be able to call `parse_marker!` here.
let start = input.mark(&crate::input::ParserInfo {
name: "try_collect",
raw: true
});

match p(input) {
Ok(val) => collection.add(val),
Err(_) => {
input.rewind_to(&start);
break;
}
}
}

Ok(collection)
}

/// Parses many `separator` delimited `p`s, the entire collection of which must
/// start with `start` and end with `end`. `item` Gramatically, this is:
///
Expand Down
2 changes: 1 addition & 1 deletion lib/tests/parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ fn test_window_termination() {
let result = take_while_window(&mut Text::from("aa"), 2, |_| false);
assert_eq!(result.unwrap(), "");

let result = take_some_while_window(&mut Text::from("a"), 2, |_| false);
let result = take_some_while_some_window(&mut Text::from("a"), 2, |_| false);
assert!(result.is_err());

let result = take_some_while_window(&mut Text::from("aa"), 2, |_| false);
Expand Down

0 comments on commit 2b6532e

Please sign in to comment.