Compare commits
2 Commits
9efd9d78d1
...
2ad7707349
Author | SHA1 | Date | |
---|---|---|---|
|
2ad7707349 | ||
|
0e26ef1ea6 |
@ -1,26 +1,181 @@
|
|||||||
use crate::Parser;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub fn repeated<P, I, O, E>(parser: P) -> impl Parser<I, Vec<O>, E>
|
use crate::{ParseResult, Parser};
|
||||||
|
|
||||||
|
pub fn repeated<P, I, O, E>(parser: P) -> Repeated<P, I, O, E>
|
||||||
where
|
where
|
||||||
P: Parser<I, O, E>,
|
P: Parser<I, O, E>,
|
||||||
{
|
{
|
||||||
move |input: I| {
|
Repeated::new(parser)
|
||||||
let mut acc = input;
|
}
|
||||||
|
|
||||||
|
pub struct Repeated<P, I, O, E>
|
||||||
|
where
|
||||||
|
P: Parser<I, O, E>,
|
||||||
|
{
|
||||||
|
inner_parser: P,
|
||||||
|
phantom: PhantomData<(I, O, E)>,
|
||||||
|
at_least: Option<u32>,
|
||||||
|
at_most: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, I, O, E> Repeated<P, I, O, E>
|
||||||
|
where
|
||||||
|
P: Parser<I, O, E>,
|
||||||
|
{
|
||||||
|
fn new(inner_parser: P) -> Self {
|
||||||
|
Self {
|
||||||
|
inner_parser,
|
||||||
|
phantom: PhantomData,
|
||||||
|
at_least: None,
|
||||||
|
at_most: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn at_least(self, at_least: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
at_least: Some(at_least),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn at_most(self, at_most: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
at_most: Some(at_most),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn separated_by<D>(self, delimiter: D) -> SeparatedBy<D, P, I, O, E>
|
||||||
|
where
|
||||||
|
D: Parser<I, (), E>,
|
||||||
|
E: Default,
|
||||||
|
{
|
||||||
|
SeparatedBy {
|
||||||
|
inner_repeated: self,
|
||||||
|
delimiter,
|
||||||
|
allow_trailing: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, I, O, E> Parser<I, Vec<O>, E> for Repeated<P, I, O, E>
|
||||||
|
where
|
||||||
|
P: Parser<I, O, E>,
|
||||||
|
E: Default,
|
||||||
|
{
|
||||||
|
fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
|
||||||
|
let at_least = self.at_least.unwrap_or(0);
|
||||||
|
let at_most = self.at_most.unwrap_or(u32::MAX);
|
||||||
|
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
if at_most == 0 {
|
||||||
|
return Ok((vec![], input));
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match parser.parse(acc) {
|
match self.inner_parser.parse(input) {
|
||||||
Ok((item, rest)) => {
|
Ok((item, rest)) => {
|
||||||
results.push(item);
|
results.push(item);
|
||||||
acc = rest;
|
input = rest;
|
||||||
|
count += 1;
|
||||||
|
if count >= at_most {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err((_err, rest)) => {
|
Err((_err, rest)) => {
|
||||||
acc = rest;
|
input = rest;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((results, acc))
|
|
||||||
|
if count < at_least {
|
||||||
|
return Err((Default::default(), input));
|
||||||
|
}
|
||||||
|
Ok((results, input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SeparatedBy<D, P, I, O, E>
|
||||||
|
where
|
||||||
|
D: Parser<I, (), E>,
|
||||||
|
P: Parser<I, O, E>,
|
||||||
|
E: Default,
|
||||||
|
{
|
||||||
|
inner_repeated: Repeated<P, I, O, E>,
|
||||||
|
delimiter: D,
|
||||||
|
allow_trailing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, P, I, O, E> Parser<I, Vec<O>, E> for SeparatedBy<D, P, I, O, E>
|
||||||
|
where
|
||||||
|
D: Parser<I, (), E>,
|
||||||
|
P: Parser<I, O, E>,
|
||||||
|
E: Default,
|
||||||
|
{
|
||||||
|
fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
|
||||||
|
let at_least = self.inner_repeated.at_least.unwrap_or(0);
|
||||||
|
let at_most = self.inner_repeated.at_most.unwrap_or(u32::MAX);
|
||||||
|
let inner = &self.inner_repeated.inner_parser;
|
||||||
|
let delimiter = &self.delimiter;
|
||||||
|
|
||||||
|
if at_most == 0 {
|
||||||
|
return Ok((vec![], input));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut results = Vec::new();
|
||||||
|
let mut count: u32 = 0;
|
||||||
|
|
||||||
|
match inner.parse(input) {
|
||||||
|
Ok((item, rest)) => {
|
||||||
|
results.push(item);
|
||||||
|
input = rest;
|
||||||
|
}
|
||||||
|
Err((err, rest)) => {
|
||||||
|
if at_least > 0 {
|
||||||
|
return Err((err, rest));
|
||||||
|
} else {
|
||||||
|
return Ok((vec![], rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match delimiter.parse(input) {
|
||||||
|
Ok(((), rest)) => {
|
||||||
|
input = rest;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
Err((_err, rest)) => {
|
||||||
|
input = rest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match inner.parse(input) {
|
||||||
|
Ok((item, rest)) => {
|
||||||
|
input = rest;
|
||||||
|
results.push(item);
|
||||||
|
}
|
||||||
|
Err((err, rest)) => {
|
||||||
|
if self.allow_trailing {
|
||||||
|
input = rest;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return Err((err, rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count >= at_most {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if count < at_least {
|
||||||
|
//return Err(??, rest) <- need to handle errors better
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((results, input))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/lib.rs
10
src/lib.rs
@ -87,4 +87,14 @@ mod tests {
|
|||||||
let output2 = parser.parse("alpha beta").unwrap();
|
let output2 = parser.parse("alpha beta").unwrap();
|
||||||
assert_eq!(output2.0 .0, Some("alpha"));
|
assert_eq!(output2.0 .0, Some("alpha"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_repeated() {
|
||||||
|
let spaces = repeated(literal_char(' ')).at_least(1);
|
||||||
|
let bongo = literal("bongo");
|
||||||
|
let parser = repeated(bongo).separated_by(map(spaces, |_| ()));
|
||||||
|
let output = parser.parse("bongo bongo bongo bongo");
|
||||||
|
let output = output.unwrap();
|
||||||
|
assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user