git-subtree-dir: subtrees/parser-combinator git-subtree-split: 5526ce7bd17beda52047fbc3442e23e0174b79a7
95 lines
2.3 KiB
Rust
95 lines
2.3 KiB
Rust
use crate::combinators::separated_by::SeparatedBy;
|
|
use crate::parser::{BoxedParser, ParseResult, Parser, ParserInput, Representation};
|
|
|
|
pub fn repeated<'a, P, I, O>(parser: P) -> Repeated<'a, I, O>
|
|
where
|
|
P: Parser<I, O, I> + 'a,
|
|
I: ParserInput + Clone + 'a,
|
|
{
|
|
Repeated {
|
|
inner_parser: BoxedParser::new(parser),
|
|
at_least: None,
|
|
at_most: None,
|
|
}
|
|
}
|
|
|
|
pub struct Repeated<'a, I, O>
|
|
where
|
|
I: ParserInput + Clone,
|
|
{
|
|
pub(super) inner_parser: BoxedParser<'a, I, O, I>,
|
|
pub(super) at_least: Option<u16>,
|
|
pub(super) at_most: Option<u16>,
|
|
}
|
|
|
|
impl<'a, I, O> Repeated<'a, I, O>
|
|
where
|
|
I: ParserInput + Clone,
|
|
{
|
|
pub fn at_least(self, n: u16) -> Self {
|
|
Self {
|
|
at_least: Some(n),
|
|
..self
|
|
}
|
|
}
|
|
pub fn at_most(self, n: u16) -> Self {
|
|
Self {
|
|
at_most: Some(n),
|
|
..self
|
|
}
|
|
}
|
|
|
|
pub fn separated_by<D, O2>(self, delimiter: D, allow_trailing: bool) -> SeparatedBy<'a, I, O>
|
|
where
|
|
D: Parser<I, O2, I> + 'a,
|
|
O2: 'a,
|
|
I: 'a,
|
|
{
|
|
SeparatedBy {
|
|
inner_repeated: self,
|
|
delimiter: BoxedParser::new(delimiter.to(())),
|
|
allow_trailing,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, I, O> Parser<I, Vec<O>, I> for Repeated<'a, I, O>
|
|
where
|
|
I: ParserInput + Clone + 'a,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, I> {
|
|
let at_least = self.at_least.unwrap_or(0);
|
|
let at_most = self.at_most.unwrap_or(u16::MAX);
|
|
|
|
if at_most == 0 {
|
|
return Ok((vec![], input));
|
|
}
|
|
|
|
let mut results = Vec::new();
|
|
let mut count: u16 = 0;
|
|
let mut further_input = input.clone();
|
|
|
|
while let Ok((item, rest)) = self.inner_parser.parse(further_input.clone()) {
|
|
results.push(item);
|
|
further_input = rest;
|
|
count += 1;
|
|
if count >= at_most {
|
|
break;
|
|
}
|
|
}
|
|
if count < at_least {
|
|
return Err(input);
|
|
}
|
|
|
|
Ok((results, further_input))
|
|
}
|
|
|
|
fn representation(&self) -> Representation {
|
|
Representation::repeated(
|
|
self.inner_parser.representation(),
|
|
self.at_least.unwrap_or(0),
|
|
self.at_most.unwrap_or(u16::MAX),
|
|
)
|
|
}
|
|
}
|