panorama/imap/src/parser/literal.rs

105 lines
3.2 KiB
Rust
Raw Normal View History

2021-03-08 23:07:44 +00:00
use pest::{iterators::QueueableToken, ParseResult as PestResult, ParserState};
2021-03-02 22:47:33 +00:00
use super::Rule;
type PSR<'a> = Box<ParserState<'a, Rule>>;
2021-03-02 22:47:33 +00:00
/// This is a hack around the literal syntax to allow us to parse characters statefully.
2021-03-08 23:07:44 +00:00
pub(crate) fn literal_internal(mut state: PSR) -> PestResult<PSR> {
// debug!("STATE: {:?}", state);
use pest::Atomicity;
// yoinked from the generated code
#[inline]
#[allow(non_snake_case, unused_variables)]
pub fn digit(state: PSR) -> PestResult<PSR> {
2021-03-08 23:07:44 +00:00
state.match_range('\u{30}'..'\u{39}')
}
#[inline]
#[allow(non_snake_case, unused_variables)]
pub fn number(state: PSR) -> PestResult<PSR> {
state.rule(Rule::number, |state| {
2021-03-08 23:07:44 +00:00
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<PSR> {
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<PSR> {
2021-03-08 23:07:44 +00:00
debug!(
"running rule 'crlf' {:?}",
state.queue().iter().rev().take(10).collect::<Vec<_>>()
);
state.sequence(|state| state.match_string("\r")?.match_string("\n"))
}
2021-03-08 23:07:44 +00:00
let state: PSR = state.match_string("{").and_then(number)?;
let num_chars = {
2021-03-08 23:07:44 +00:00
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();
2021-03-08 23:07:44 +00:00
let seg = &inp[start_pos..end_pos];
match seg.parse::<usize>() {
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<PSR> {
// TODO: probably should be unreachable?
Ok(state)
}