use crate::{Error, Input, InputToken, Parser};
pub fn many0<P, IT, O>(parser: &P) -> impl Parser<IT, Vec<O>>
where
P: Parser<IT, O>,
IT: InputToken,
{
|input| {
let output: Vec<O> = Vec::new();
many(parser)(input, output)
}
}
pub fn many1<P, IT, O>(parser: &P) -> impl Parser<IT, Vec<O>>
where
P: Parser<IT, O>,
IT: InputToken,
{
|input| {
let mut output: Vec<O> = Vec::new();
match parser(input) {
Ok(token) => {
output.push(token);
many(parser)(input, output)
}
Err(e) => Err(e),
}
}
}
fn many<P, IT, O>(parser: &P) -> impl Fn(&mut Input<IT>, Vec<O>) -> Result<Vec<O>, Error>
where
P: Parser<IT, O>,
IT: InputToken,
{
|input, mut output| {
let mut previous_count: Option<usize> = None;
loop {
match parser(input) {
Ok(token) => {
let new_count = input.consumed_count();
if let Some(previous) = previous_count
&& previous == new_count
{
return Err(Error::NonConsumingLoop(
input.source_name(),
input.position(),
));
}
output.push(token);
previous_count = Some(new_count);
}
Err(_) => return Ok(output),
}
}
}
}
#[cfg(test)]
mod tests {
mod many0 {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let parser = is('h');
let mut input = Input::new_from_chars("".chars(), None);
let parser_many0 = many0(&parser);
let output = parser_many0(&mut input).unwrap();
assert_eq!(output.len(), 0);
}
#[test]
fn empty_shortcut() {
let parser = is('h').many0();
let mut input = Input::new_from_chars("".chars(), None);
let output = parser(&mut input).unwrap();
assert_eq!(output.len(), 0);
}
#[test]
fn no_match_not_empty() {
let token_count = 100;
let parser = is('h');
let tokens = std::iter::repeat_n('j', token_count).collect::<Vec<_>>();
let mut input = Input::new_from_chars(tokens, None);
let parser_many0 = many0(&parser);
let output = parser_many0(&mut input).unwrap();
assert_eq!(output.len(), 0);
assert_eq!(input.consumed_count(), 0);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn no_match_not_empty_shortcut() {
let token_count = 100;
let parser = is('h').many0();
let tokens = std::iter::repeat_n('j', token_count).collect::<Vec<_>>();
let mut input = Input::new_from_chars(tokens, None);
let output = parser(&mut input).unwrap();
assert_eq!(output.len(), 0);
assert_eq!(input.consumed_count(), 0);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn match_not_empty() {
let token_count = 100;
let parser = is('h');
let tokens = std::iter::repeat_n('h', token_count).collect::<Vec<_>>();
let mut input = Input::new_from_chars(tokens, None);
let parser_many0 = many0(&parser);
let output = parser_many0(&mut input).unwrap();
assert_eq!(output.len(), token_count);
assert_eq!(input.consumed_count(), token_count);
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn match_not_empty_shortcut() {
let token_count = 100;
let parser = is('h').many0();
let tokens = std::iter::repeat_n('h', token_count).collect::<Vec<_>>();
let mut input = Input::new_from_chars(tokens, None);
let output = parser(&mut input).unwrap();
assert_eq!(output.len(), token_count);
assert_eq!(input.consumed_count(), token_count);
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn non_consuming_parser_does_not_loop() {
let parser = success(1); let mut input = Input::new_from_chars("hello".chars(), None);
let parser = parser.many0();
let output = parser(&mut input);
let position = Position::new(1, 1);
assert_eq!(output, Err(Error::NonConsumingLoop(None, position)));
}
#[test]
fn match_consuming_upon_failure() {
let parser = |input: &mut StringInput| {
let o1 = is('#')(input)?;
let o2 = is('a')(input)?;
Ok((o1, o2))
};
let mut input = Input::new_from_chars("#a#e".chars(), None);
let many_parser = parser.many0();
let output = many_parser(&mut input).unwrap();
assert_eq!(output.len(), 1);
assert_eq!(output[0], ('#', 'a'));
assert_eq!(input.consumed_count(), 3); assert_eq!(any()(&mut input), Ok('e'));
assert!(end_of_input()(&mut input).is_ok()); }
}
mod many1 {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let parser = is('h');
let mut input = Input::new_from_chars("".chars(), None);
let parser_many1 = many1(&parser);
assert_eq!(
parser_many1(&mut input),
Err(Error::EndOfInput(Some(Box::new('h'))))
);
}
#[test]
fn empty_shortcut() {
let parser = is('h').many1();
let mut input = Input::new_from_chars("".chars(), None);
assert_eq!(
parser(&mut input),
Err(Error::EndOfInput(Some(Box::new('h'))))
);
}
#[test]
fn no_match() {
let parser = is('h');
let mut input = Input::new_from_chars("jklmno".chars(), None);
let parser_many1 = many1(&parser);
let mismatch = Mismatch::new('h', 'j');
assert_eq!(
parser_many1(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn no_match_shortcut() {
let parser = is('h').many1();
let mut input = Input::new_from_chars("jklmno".chars(), None);
let mismatch = Mismatch::new('h', 'j');
assert_eq!(
parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn one_match() {
let parser = is('h');
let mut input = Input::new_from_chars("hallo".chars(), None);
let parser_many1 = many1(&parser);
let output = parser_many1(&mut input).unwrap();
assert_eq!(output.len(), 1);
assert_eq!(input.consumed_count(), 1);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn one_match_shortcut() {
let parser = is('h').many1();
let mut input = Input::new_from_chars("hallo".chars(), None);
let output = parser(&mut input).unwrap();
assert_eq!(output.len(), 1);
assert_eq!(input.consumed_count(), 1);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn multiple_matches() {
let token_count = 100;
let parser = is('h');
let tokens = std::iter::repeat_n('h', token_count).collect::<Vec<_>>();
let mut input = Input::new_from_chars(tokens, None);
let parser_many1 = many1(&parser);
let output = parser_many1(&mut input).unwrap();
assert_eq!(output.len(), token_count);
assert!(output.iter().all(|x| *x == 'h'));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn partial_match_then_stop() {
let parser = is('h');
let mut input = Input::new_from_chars("hhjklmnop".chars(), None);
let parser_many1 = many1(&parser);
let output = parser_many1(&mut input).unwrap();
assert_eq!(output, vec!['h', 'h']);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn non_consuming_parser_does_not_loop() {
let parser = success(1); let mut input = Input::new_from_chars("hello".chars(), None);
let parser = parser.many1();
let output = parser(&mut input);
let position = Position::new(1, 1);
assert_eq!(output, Err(Error::NonConsumingLoop(None, position)));
}
#[test]
fn match_consuming_upon_failure() {
let parser = |input: &mut StringInput| {
let o1 = is('#')(input)?;
let o2 = is('a')(input)?;
Ok((o1, o2))
};
let mut input = Input::new_from_chars("#a#e".chars(), None);
let many_parser = parser.many1();
let output = many_parser(&mut input).unwrap();
assert_eq!(output.len(), 1);
assert_eq!(output[0], ('#', 'a'));
assert_eq!(input.consumed_count(), 3); assert_eq!(any()(&mut input), Ok('e'));
assert!(end_of_input()(&mut input).is_ok()); }
}
}