Separated by

This commit is contained in:
Greg Shuflin 2022-10-20 23:29:06 -07:00
parent d624a54fb0
commit 5705876477
1 changed files with 59 additions and 13 deletions

View File

@ -49,15 +49,16 @@ where
}
}
pub fn delimited_by<D, O2>(self, delimiter: D) -> DelimitedBy<'a, I, O>
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,
{
DelimitedBy {
SeparatedBy {
inner_repeated: self,
delimiter: BoxedParser::new(delimiter.to(())),
allow_trailing,
}
}
}
@ -94,21 +95,24 @@ where
}
}
pub struct DelimitedBy<'a, I, O>
pub struct SeparatedBy<'a, I, O>
where
I: Clone,
{
inner_repeated: Repeated<'a, I, O>,
delimiter: BoxedParser<'a, I, (), I>,
allow_trailing: bool,
}
impl<'a, I, O> Parser<I, Vec<O>, I> for DelimitedBy<'a, I, O>
impl<'a, I, O> Parser<I, Vec<O>, I> for SeparatedBy<'a, I, O>
where
I: Clone + 'a,
{
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, I> {
let at_least = self.inner_repeated.at_least.unwrap_or(0);
let at_most = self.inner_repeated.at_most.unwrap_or(u16::MAX);
let parser = &self.inner_repeated.inner_parser;
let delimiter = &self.delimiter;
if at_most == 0 {
return Ok((vec![], input));
@ -116,20 +120,51 @@ where
let mut results = Vec::new();
let mut count: u16 = 0;
let mut further_input = input.clone();
let mut further_input;
match parser.parse(input.clone()) {
Ok((item, rest)) => {
results.push(item);
further_input = rest;
}
Err(_e) => {
if at_least > 0 {
return Err(input);
} else {
return Ok((vec![], input));
}
}
}
loop {
match delimiter.parse(further_input.clone()) {
Ok(((), rest)) => {
further_input = rest;
}
Err(_e) => {
break;
}
}
match parser.parse(further_input.clone()) {
Ok((item, rest)) => {
results.push(item);
further_input = rest;
count += 1;
}
Err(_e) if self.allow_trailing => {
break;
}
Err(e) => {
return Err(e);
}
}
while let Ok((item, rest)) = self
.inner_repeated
.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);
}
@ -175,4 +210,15 @@ mod tests {
assert_eq!(output.len(), 1);
assert_eq!(rest, "ecks");
}
#[test]
fn test_separated_by() {
let p = repeated(literal("garb").to(20))
.separated_by(repeated(literal(" ")).at_least(1), false);
assert_eq!(
p.parse("garb garb garb garb").unwrap(),
(vec![20, 20, 20, 20], "")
);
}
}