use crate::{
parsers::{empty, EmptyParser},
types::ParserOutput,
ParseContext, ParseIter, Parser, Reported, Result,
};
#[derive(Clone, Copy)]
pub struct RepeatParser<Pattern, Sep> {
pattern: Pattern,
min: usize,
max: Option<usize>,
sep: Sep,
sep_is_terminator: bool,
}
pub struct RepeatParseIter<'parse, Pattern, Sep>
where
Pattern: Parser + 'parse,
Sep: Parser + 'parse,
{
params: &'parse RepeatParser<Pattern, Sep>,
start: usize,
pattern_iters: Vec<Pattern::Iter<'parse>>,
sep_iters: Vec<Sep::Iter<'parse>>,
}
impl<Pattern, Sep> Parser for RepeatParser<Pattern, Sep>
where
Pattern: Parser,
Sep: Parser,
{
type Output = Vec<Pattern::Output>;
type RawOutput = (Vec<Pattern::Output>,);
type Iter<'parse> = RepeatParseIter<'parse, Pattern, Sep>
where
Pattern: 'parse,
Sep: 'parse;
fn parse_iter<'parse>(
&'parse self,
context: &mut ParseContext<'parse>,
start: usize,
) -> Result<Self::Iter<'parse>, Reported> {
let mut iter = RepeatParseIter {
params: self,
start,
pattern_iters: vec![],
sep_iters: vec![],
};
iter.next(context, Mode::Advance)?;
Ok(iter)
}
}
impl<Pattern, Sep> RepeatParser<Pattern, Sep> {
fn check_repeat_count(&self, count: usize) -> bool {
let expected_parity = !self.sep_is_terminator as usize;
let nmatches = (count + expected_parity) / 2;
(count == 0 || count % 2 == expected_parity)
&& self.min <= nmatches
&& match self.max {
None => true,
Some(max) => nmatches <= max,
}
}
}
enum Mode {
BacktrackTopIter,
Advance,
Exhausted,
YieldThenBacktrack,
}
impl<'parse, Pattern, Sep> RepeatParseIter<'parse, Pattern, Sep>
where
Pattern: Parser,
Sep: Parser,
{
fn num_matches(&self) -> usize {
self.pattern_iters.len() + self.sep_iters.len()
}
fn is_pattern_next(&self) -> bool {
self.pattern_iters.len() == self.sep_iters.len()
}
fn end(&self) -> usize {
if self.num_matches() == 0 {
self.start
} else if self.is_pattern_next() {
self.sep_iters.last().unwrap().match_end()
} else {
self.pattern_iters.last().unwrap().match_end()
}
}
fn advance(&mut self, context: &mut ParseContext<'parse>) -> Result<(), Reported> {
loop {
assert_eq!(self.pattern_iters.len(), (self.num_matches() + 1) / 2);
assert_eq!(self.sep_iters.len(), self.num_matches() / 2);
if self.is_pattern_next() {
let start = self.end();
let iter = self.params.pattern.parse_iter(context, start)?;
self.pattern_iters.push(iter);
}
let start = self.end();
let iter = self.params.sep.parse_iter(context, start)?;
self.sep_iters.push(iter);
}
}
fn next(&mut self, context: &mut ParseContext<'parse>, mut mode: Mode) -> Result<(), Reported> {
loop {
match mode {
Mode::BacktrackTopIter => {
assert_eq!(self.pattern_iters.len(), (self.num_matches() + 1) / 2);
assert_eq!(self.sep_iters.len(), self.num_matches() / 2);
if self.num_matches() == 0 {
return Err(Reported);
}
let backtrack_result = if self.is_pattern_next() {
self.sep_iters.last_mut().unwrap().backtrack(context)
} else {
self.pattern_iters.last_mut().unwrap().backtrack(context)
};
mode = match backtrack_result {
Ok(()) => Mode::Advance,
Err(Reported) => Mode::Exhausted,
};
}
Mode::Advance => {
let _ = self.advance(context);
mode = Mode::YieldThenBacktrack;
}
Mode::Exhausted => {
assert_eq!(self.pattern_iters.len(), (self.num_matches() + 1) / 2);
assert_eq!(self.sep_iters.len(), self.num_matches() / 2);
if self.is_pattern_next() {
self.sep_iters.pop();
} else {
self.pattern_iters.pop();
}
mode = Mode::YieldThenBacktrack;
}
Mode::YieldThenBacktrack => {
if self.params.check_repeat_count(self.num_matches()) {
return Ok(());
}
mode = Mode::BacktrackTopIter;
}
}
}
}
}
impl<'parse, Pattern, Sep> ParseIter<'parse> for RepeatParseIter<'parse, Pattern, Sep>
where
Pattern: Parser,
Sep: Parser,
{
type RawOutput = (Vec<Pattern::Output>,);
fn match_end(&self) -> usize {
self.end()
}
fn backtrack(&mut self, context: &mut ParseContext<'parse>) -> Result<(), Reported> {
self.next(context, Mode::BacktrackTopIter)
}
fn convert(&self) -> (Vec<Pattern::Output>,) {
let v = self
.pattern_iters
.iter()
.map(|iter| iter.convert().into_user_type())
.collect();
(v,)
}
}
pub fn repeat<Pattern, Sep>(
pattern: Pattern,
sep: Sep,
min: usize,
max: Option<usize>,
sep_is_terminator: bool,
) -> RepeatParser<Pattern, Sep> {
RepeatParser {
pattern,
min,
max,
sep,
sep_is_terminator,
}
}
#[doc(hidden)]
pub fn star<Pattern>(pattern: Pattern) -> RepeatParser<Pattern, EmptyParser> {
repeat(pattern, empty(), 0, None, false)
}
#[doc(hidden)]
pub fn plus<Pattern>(pattern: Pattern) -> RepeatParser<Pattern, EmptyParser> {
repeat(pattern, empty(), 1, None, false)
}
pub fn repeat_sep<Pattern, Sep>(pattern: Pattern, sep: Sep) -> RepeatParser<Pattern, Sep> {
repeat(pattern, sep, 0, None, false)
}