use pest::{iterators::QueueableToken, ParseResult as PestResult, ParserState}; use super::Rule; type PSR<'a> = Box>; /// This is a hack around the literal syntax to allow us to parse characters statefully. pub(crate) fn literal_internal(mut state: PSR) -> PestResult { // debug!("STATE: {:?}", state); use pest::Atomicity; // yoinked from the generated code #[inline] #[allow(non_snake_case, unused_variables)] pub fn digit(state: PSR) -> PestResult { state.match_range('\u{30}'..'\u{39}') } #[inline] #[allow(non_snake_case, unused_variables)] pub fn number(state: PSR) -> PestResult { state.rule(Rule::number, |state| { state.sequence(|state| { debug!("number::atomic::sequence"); digit(state).and_then(|state| state.repeat(digit)) }) }) } #[inline] #[allow(non_snake_case, unused_variables)] pub fn char8(state: PSR) -> PestResult { state.rule(Rule::char8, |state| { state.atomic(Atomicity::Atomic, |state| { state.match_range('\u{1}'..'\u{ff}') }) }) } #[inline] #[allow(non_snake_case, unused_variables)] pub fn crlf(state: PSR) -> PestResult { debug!( "running rule 'crlf' {:?}", state.queue().iter().rev().take(10).collect::>() ); state.sequence(|state| state.match_string("\r")?.match_string("\n")) } let state: PSR = state.match_string("{").and_then(number)?; let num_chars = { let queue = state.queue(); let (start_idx, end_pos) = queue .iter() .rev() .find_map(|p| match p { QueueableToken::End { start_token_index: start, rule: Rule::number, input_pos: pos, } => Some((*start, *pos)), _ => None, }) .unwrap(); let start_pos = match queue[start_idx] { QueueableToken::Start { input_pos: pos, .. } => pos, _ => unreachable!(), }; debug!("start_pos: {}, end_pos: {}", start_pos, end_pos); let inp = state.position().get_str(); let seg = &inp[start_pos..end_pos]; match seg.parse::() { Ok(v) => { debug!("got length: {}", v); v } Err(e) => { error!( "failed to parse int from {}..{} {:?}: {}", start_pos, end_pos, seg, e ); return Err(state); } } }; state .match_string("}") .and_then(crlf)? .rule(Rule::literal_str, |state| { state.atomic(Atomicity::Atomic, |state| { let mut state = Ok(state); for _ in 0..num_chars { state = state.and_then(char8); } state }) }) // todo!("hit internal state: {:?}", state,); } pub(crate) fn noop(state: PSR) -> PestResult { // TODO: probably should be unreachable? Ok(state) }