use crate::parser::{code, Input, Parser, ParseResult};
use super::SequenceError;
pub fn many0<'a, 'b, F, O>(mut element: F) -> impl FnMut(Input<'a>) -> ParseResult<'a, Vec<O>>
where
O: 'b,
F: Parser<'a, 'b, O>,
{
move |input| {
let mut acc = Vec::new();
let mut cursor = input;
while let Ok((item, next)) = element.parse(cursor) {
infinite_loop_check!(cursor, next);
acc.push(item);
cursor = next;
}
Ok((acc, cursor))
}
}
pub fn many1<'a, 'b, F, O>(mut element: F) -> impl FnMut(Input<'a>) -> ParseResult<'a, Vec<O>>
where
O: 'b,
F: Parser<'a, 'b, O>,
{
move |input| {
let (mut acc, mut cursor) = match element.parse(input) {
Ok((item, next)) => Ok((vec![item], next)),
Err(mut err) => {
err.push(input, code::ERR_MANY_1, SequenceError::Many1);
Err(err)
}
}?;
infinite_loop_check!(input, cursor);
while let Ok((item, next)) = element.parse(cursor) {
infinite_loop_check!(cursor, next);
acc.push(item);
cursor = next;
}
Ok((acc, cursor))
}
}
pub fn many_m_n<'a, 'b, F, O>(
m: usize,
n: usize,
mut element: F,
) -> impl FnMut(Input<'a>) -> ParseResult<'a, Vec<O>>
where
O: 'b,
F: Parser<'a, 'b, O>,
{
assert!(m <= n, "m must be less than or equal to n");
move |input| {
if n - m == 0 && n == 0 {
return Ok((vec![], input));
}
let (mut acc, mut cursor) = if m == 0 {
if let Ok((item, cursor)) = element.parse(input) {
(vec![item], cursor)
} else {
return Ok((vec![], input));
}
} else {
let (item, cursor) = element.parse(input).map_err(|mut err| {
err.push(input, code::ERR_MANY_M, SequenceError::ManyM(m));
err
})?;
(vec![item], cursor)
};
infinite_loop_check!(input, cursor);
for i in 1..n {
match element.parse(cursor) {
Ok((item, next)) => {
infinite_loop_check!(cursor, next);
acc.push(item);
cursor = next;
}
Err(mut err) => {
if i < m {
err.push(cursor, code::ERR_MANY_M, SequenceError::ManyM(m));
return Err(err);
}
return Ok((acc, cursor));
}
}
}
Ok((acc, cursor))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::{prelude::*, ParseError, Position};
#[test]
fn many0_success() {
let (value, input) = many0(char('a'))(Input::new("")).expect("valid input");
assert_eq!(value, vec![]);
assert_eq!(input.position(), Position::new(0, 1, 1));
assert_eq!(input.current(), None);
let (value, input) = many0(char('a'))(Input::new("aaa")).expect("valid input");
assert_eq!(value, vec!['a', 'a', 'a']);
assert_eq!(input.position(), Position::new(3, 1, 4));
assert_eq!(input.current(), None);
let (value, input) = many0(char('a'))(Input::new("aaaö")).expect("valid input");
assert_eq!(value, vec!['a', 'a', 'a']);
assert_eq!(input.position(), Position::new(3, 1, 4));
assert_eq!(input.current(), Some('ö'));
let (value, input) = many0(char('ä'))(Input::new("äääo")).expect("valid input");
assert_eq!(value, vec!['ä', 'ä', 'ä']);
assert_eq!(input.position(), Position::new(6, 1, 4));
assert_eq!(input.current(), Some('o'));
let (value, input) = many0(char('ä'))(Input::new("äääö")).expect("valid input");
assert_eq!(value, vec!['ä', 'ä', 'ä']);
assert_eq!(input.position(), Position::new(6, 1, 4));
assert_eq!(input.current(), Some('ö'));
}
#[test]
fn many0_infinite_loop() {
let error = many0(opt(char('a')))(Input::new("ab")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_INFINITE,
SequenceError::Infinite
)
);
let error = many0(opt(char('a')))(Input::new("a")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_INFINITE,
SequenceError::Infinite
)
);
}
#[test]
fn many1_success() {
let (value, input) = many1(char('a'))(Input::new("aaa")).expect("valid input");
assert_eq!(value, vec!['a', 'a', 'a']);
assert_eq!(input.position(), Position::new(3, 1, 4));
assert_eq!(input.current(), None);
let (value, input) = many1(char('a'))(Input::new("aaaö")).expect("valid input");
assert_eq!(value, vec!['a', 'a', 'a']);
assert_eq!(input.position(), Position::new(3, 1, 4));
assert_eq!(input.current(), Some('ö'));
let (value, input) = many1(char('ä'))(Input::new("äääo")).expect("valid input");
assert_eq!(value, vec!['ä', 'ä', 'ä']);
assert_eq!(input.position(), Position::new(6, 1, 4));
assert_eq!(input.current(), Some('o'));
let (value, input) = many1(char('ä'))(Input::new("äääö")).expect("valid input");
assert_eq!(value, vec!['ä', 'ä', 'ä']);
assert_eq!(input.position(), Position::new(6, 1, 4));
assert_eq!(input.current(), Some('ö'));
}
#[test]
fn many1_infinte_loop() {
let error = many1(opt(char('a')))(Input::new("ab")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_INFINITE,
SequenceError::Infinite
)
);
let error = many1(opt(char('a')))(Input::new("a")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_INFINITE,
SequenceError::Infinite
)
);
}
#[test]
fn many1_failure() {
let error = many1(char('a'))(Input::new("öbbb")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_MANY_1,
SequenceError::Many1
)
);
}
#[test]
fn many_m_n_success() {
let (value, input) =
many_m_n(2, 3, char('a'))(Input::new("aaa")).expect("valid input");
assert_eq!(value, vec!['a', 'a', 'a']);
assert_eq!(input.position(), Position::new(3, 1, 4));
assert_eq!(input.current(), None);
let (value, input) =
many_m_n(2, 3, char('a'))(Input::new("aaaö")).expect("valid input");
assert_eq!(value, vec!['a', 'a', 'a']);
assert_eq!(input.position(), Position::new(3, 1, 4));
assert_eq!(input.current(), Some('ö'));
let (value, input) =
many_m_n(2, 3, char('ä'))(Input::new("äääo")).expect("valid input");
assert_eq!(value, vec!['ä', 'ä', 'ä']);
assert_eq!(input.position(), Position::new(6, 1, 4));
assert_eq!(input.current(), Some('o'));
let (value, input) =
many_m_n(2, 3, char('ä'))(Input::new("äääö")).expect("valid input");
assert_eq!(value, vec!['ä', 'ä', 'ä']);
assert_eq!(input.position(), Position::new(6, 1, 4));
assert_eq!(input.current(), Some('ö'));
}
#[test]
fn many_m_n_infinite_loop() {
let error =
many_m_n(2, 3, opt(char('a')))(Input::new("ab")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_INFINITE,
SequenceError::Infinite
)
);
let error =
many_m_n(2, 3, opt(char('a')))(Input::new("a")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_INFINITE,
SequenceError::Infinite
)
);
}
#[test]
fn many_m_n_failure() {
let error = many_m_n(2, 3, char('a'))(Input::new("öbbb")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_MANY_M,
SequenceError::ManyM(2)
)
);
let error =
many_m_n(2, 3, char('a'))(Input::new("aöbbb")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_MANY_M,
SequenceError::ManyM(2)
)
);
let error = many_m_n(2, 3, char('a'))(Input::new("a")).expect_err("invalid input");
assert_eq!(
error,
ParseError::new(
Position::new(1, 1, 2),
code::ERR_EOF,
SequenceError::ManyM(2)
)
);
}
}