repeated combinator
This commit is contained in:
parent
26f813ee16
commit
567ea60642
@ -147,12 +147,15 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::combinators::one_or_more;
|
use crate::combinators::repeated;
|
||||||
use crate::primitives::literal;
|
use crate::primitives::literal;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_choice() {
|
fn test_choice() {
|
||||||
let p = choice2(literal("gnostika").to(1), one_or_more(literal(" ")).to(2));
|
let p = choice2(
|
||||||
|
literal("gnostika").to(1),
|
||||||
|
repeated(literal(" ")).at_least(1).to(2),
|
||||||
|
);
|
||||||
assert_eq!(p.parse("gnostika twentynine"), Ok((1, " twentynine")));
|
assert_eq!(p.parse("gnostika twentynine"), Ok((1, " twentynine")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::parser::Parser;
|
use crate::parser::{BoxedParser, ParseResult, Parser};
|
||||||
|
|
||||||
pub fn optional<P, I, O, E>(parser: P) -> impl Parser<I, Option<O>, E>
|
pub fn optional<P, I, O, E>(parser: P) -> impl Parser<I, Option<O>, E>
|
||||||
where
|
where
|
||||||
@ -23,6 +23,78 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Repeated<'a, I, O>
|
||||||
|
where
|
||||||
|
I: Clone,
|
||||||
|
{
|
||||||
|
inner_parser: BoxedParser<'a, I, O, I>,
|
||||||
|
at_least: Option<u16>,
|
||||||
|
at_most: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, O> Repeated<'a, I, O>
|
||||||
|
where
|
||||||
|
I: 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, O> Parser<I, Vec<O>, I> for Repeated<'a, I, O>
|
||||||
|
where
|
||||||
|
I: Clone + 'a,
|
||||||
|
{
|
||||||
|
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, I> {
|
||||||
|
let mut results = Vec::new();
|
||||||
|
let mut count: u16 = 0;
|
||||||
|
|
||||||
|
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((results, input));
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeated<'a, P, I, O>(parser: P) -> Repeated<'a, I, O>
|
||||||
|
where
|
||||||
|
P: Parser<I, O, I> + 'static,
|
||||||
|
I: Clone + 'static,
|
||||||
|
{
|
||||||
|
Repeated {
|
||||||
|
inner_parser: BoxedParser::new(parser),
|
||||||
|
at_least: None,
|
||||||
|
at_most: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn zero_or_more<P, I, O>(parser: P) -> impl Parser<I, Vec<O>, I>
|
pub fn zero_or_more<P, I, O>(parser: P) -> impl Parser<I, Vec<O>, I>
|
||||||
where
|
where
|
||||||
P: Parser<I, O, I>,
|
P: Parser<I, O, I>,
|
||||||
@ -60,7 +132,6 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::combinators::one_or_more;
|
|
||||||
use crate::primitives::literal;
|
use crate::primitives::literal;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -72,7 +143,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_one_or_more() {
|
fn test_one_or_more() {
|
||||||
let p = one_or_more(literal("bongo "));
|
let p = repeated(literal("bongo ")).at_least(1);
|
||||||
let input = "bongo bongo bongo bongo bongo ";
|
let input = "bongo bongo bongo bongo bongo ";
|
||||||
|
|
||||||
let (output, rest) = p.parse(input).unwrap();
|
let (output, rest) = p.parse(input).unwrap();
|
||||||
|
@ -60,7 +60,7 @@ pub struct BoxedParser<'a, I, O, E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, O, E> BoxedParser<'a, I, O, E> {
|
impl<'a, I, O, E> BoxedParser<'a, I, O, E> {
|
||||||
fn new<P>(inner: P) -> Self
|
pub(crate) fn new<P>(inner: P) -> Self
|
||||||
where
|
where
|
||||||
P: Parser<I, O, E> + 'a,
|
P: Parser<I, O, E> + 'a,
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user