323 lines
9.4 KiB
Rust
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)
|
|
});
|
|
}
|
|
}
|