zero-parser/src/combinators/many_parsers.rs

323 lines
9.4 KiB
Rust

use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
use std::cell::RefCell;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::rc::Rc;
pub struct ManyParser<P> {
pub(crate) parser: P,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Vec<T>, TContext> for ManyParser<P>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> {
let mut result = vec![];
let mut input = input;
while let Ok((i, r)) = self.parser.parse(context.clone(), input) {
result.push(r);
input = i;
}
Ok((input, result))
}
}
pub struct Many1Parser<P> {
pub(crate) parser: P,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Vec<T>, TContext> for Many1Parser<P>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, first_result) = self.parser.parse(context.clone(), input)?;
let mut result = vec![first_result];
while let Ok((i, r)) = self.parser.parse(context.clone(), input) {
result.push(r);
input = i;
}
Ok((input, result))
}
}
pub struct SkipParser<P, T> {
pub(crate) parser: P,
pub(crate) phantom_data: PhantomData<T>,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, (), TContext> for SkipParser<P, T>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, ()> {
let mut input = input;
while let Ok((i, _)) = self.parser.parse(context.clone(), input) {
input = i;
}
Ok((input, ()))
}
}
pub struct Skip1Parser<P, T> {
pub(crate) parser: P,
pub(crate) phantom_data: PhantomData<T>,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, (), TContext> for Skip1Parser<P, T>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, ()> {
let (mut input, _) = self.parser.parse(context.clone(), input)?;
while let Ok((i, _)) = self.parser.parse(context.clone(), input) {
input = i;
}
Ok((input, ()))
}
}
pub struct ManyTillParser<P, PTerminator, TTerminator> {
pub(crate) parser: P,
pub(crate) terminator: PTerminator,
pub(crate) phantom_data: PhantomData<TTerminator>,
}
impl<'a, TToken, T: 'a, TTerminator: 'a, TContext, P, PTerminator>
Parser<'a, TToken, Vec<T>, TContext> for ManyTillParser<P, PTerminator, TTerminator>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> {
let mut input = input;
let mut result = vec![];
loop {
if self.terminator.parse(context.clone(), input).is_ok() {
return Ok((input, result));
}
if let Ok((i, r)) = self.parser.parse(context.clone(), input) {
input = i;
result.push(r);
} else {
return Err((
input,
FailedParserResult::new("End with other elements.".to_owned()),
));
}
}
}
}
pub struct Many1TillParser<P, PTerminator, TTerminator> {
pub(crate) parser: P,
pub(crate) terminator: PTerminator,
pub(crate) phantom_data: PhantomData<TTerminator>,
}
impl<'a, TToken, T: 'a, TTerminator: 'a, TContext, P, PTerminator>
Parser<'a, TToken, Vec<T>, TContext> for Many1TillParser<P, PTerminator, TTerminator>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<T>> {
let (mut input, r) = self.parser.parse(context.clone(), input)?;
let mut result = vec![r];
loop {
if self.terminator.parse(context.clone(), input).is_ok() {
return Ok((input, result));
}
if let Ok((i, r)) = self.parser.parse(context.clone(), input) {
result.push(r);
input = i;
} else {
return Err((
input,
FailedParserResult::new("End with other elements.".to_owned()),
));
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::combinators::{take1_till, take_till, tuple, ParserExt};
use crate::parser::{failed_parser_test_helper, parser_test_helper};
use crate::text::char_parser;
#[test]
fn many_test() {
parser_test_helper(
ParserContext::new_with_str("aaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("aaabbaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many().parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("bbaa", ()), &vec![], |c, i| {
char_parser('a').many().parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("", ()), &vec![], |c, i| {
char_parser('a').many().parse(c, i)
});
}
#[test]
fn many1_test() {
parser_test_helper(
ParserContext::new_with_str("aaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many1().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("aaabbaa", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many1().parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("bbaa", ()), |c, i| {
char_parser('a').many1().parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("", ()), |c, i| {
char_parser('a').many1().parse(c, i)
});
}
#[test]
fn skip_test() {
parser_test_helper(ParserContext::new_with_str("aaab", ()), &'b', |c, i| {
char_parser('a').skip().right(char_parser('b')).parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', |c, i| {
char_parser('a').skip().right(char_parser('b')).parse(c, i)
});
}
#[test]
fn skip1_test() {
parser_test_helper(ParserContext::new_with_str("aaab", ()), &'b', |c, i| {
char_parser('a').skip1().right(char_parser('b')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
char_parser('a').skip1().right(char_parser('b')).parse(c, i)
});
}
#[test]
fn many_till_test() {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many_till(char_parser('b')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("b", ()), &vec![], |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i)
});
}
#[test]
fn many1_till_test() {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&vec!['a', 'a', 'a'],
|c, i| char_parser('a').many1_till(char_parser('b')).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i)
});
}
#[test]
fn take_till_test() {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&(vec!['a', 'a', 'a'], 'b'),
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("b", ()),
&(vec![], 'b'),
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
}
#[test]
fn take1_till_test() {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&(vec!['a', 'a', 'a'], 'b'),
|c, i| tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i)
});
}
}