use crate::{
error::{Error, ErrorKind},
parser::*,
};
use std::marker::PhantomData;
#[derive(Clone)]
pub struct PDelim<P1, P2, A> {
p: P1,
delim: P2,
at_least: usize,
at_most: usize,
allow_trailing: bool,
_marker: PhantomData<A>,
}
pub fn pdelim<P1, P2, A>(
p: P1,
delim: P2,
at_least: usize,
at_most: usize,
allow_trailing: bool,
) -> PDelim<P1, P2, A> {
PDelim {
p,
delim,
at_least,
at_most,
allow_trailing,
_marker: PhantomData,
}
}
impl<P, PDelim_, A> PDelim<P, PDelim_, A> {
pub fn no_trailing(mut self) -> Self {
self.allow_trailing = false;
self
}
pub fn at_least(mut self, n: usize) -> Self {
self.at_least = n;
self
}
pub fn at_most(mut self, n: usize) -> Self {
self.at_most = n;
self
}
}
impl<'a, K, O, P, PDelim_, B> ParserCore<'a, K, Vec<O>> for PDelim<P, PDelim_, B>
where
K: PartialEq + Clone + 'a,
O: Clone + 'a,
B: Clone + 'a,
P: Parser<'a, K, O>,
PDelim_: Parser<'a, K, B>,
{
fn parse(&self, i: PInput<'a, K>) -> Result<PSuccess<'a, K, Vec<O>>, Error<'a, K>> {
let start = i.loc;
let mut vals = vec![];
let mut input = i;
loop {
let loop_start = input.loc;
match self.p.parse(input.clone()) {
Ok(PSuccess { val, rest }) => {
vals.push(val);
input = rest;
match self.delim.parse(input.clone()) {
Ok(PSuccess { val: _, rest }) => {
input = rest;
continue;
}
Err(Error {
kind: _,
span,
state,
}) => {
if vals.len() >= self.at_least && vals.len() <= self.at_most {
return Ok(PSuccess {
val: vals,
rest: input,
});
} else {
return Err(Error {
kind: vec![ErrorKind::Custom(format!(
"Expected {} elements, but found {} elements.",
if self.at_most == usize::MAX {
format!("at least {}", self.at_least)
} else {
format!(
"between {} and {}",
self.at_least, self.at_most
)
},
vals.len()
))],
span: (start, span.1),
state,
});
}
}
}
}
Err(Error {
kind: _,
span,
state,
}) => {
if !self.allow_trailing && !vals.is_empty() {
return Err(Error {
kind: vec![ErrorKind::Custom("Trailing delimiter found.".to_string())],
span: (loop_start, state.loc),
state,
});
} else if vals.len() >= self.at_least && vals.len() <= self.at_most {
return Ok(PSuccess {
val: vals,
rest: input,
});
} else {
return Err(Error {
kind: vec![ErrorKind::Custom(format!(
"Expected {} elements, but found {} elements.",
if self.at_most == usize::MAX {
format!("at least {}", self.at_least)
} else {
format!("between {} and {}", self.at_least, self.at_most)
},
vals.len()
))],
span: (start, span.1),
state,
});
}
}
}
}
}
}
impl<'a, K, O, P, PDelim_, B> Parser<'a, K, Vec<O>> for PDelim<P, PDelim_, B>
where
K: PartialEq + Clone + 'a,
O: Clone + 'a,
B: Clone + 'a,
P: Parser<'a, K, O>,
PDelim_: Parser<'a, K, B>,
{
}