mod builder;
mod snapshot;
pub use builder::*;
pub use snapshot::*;
use crate::{
action::{Action, Input, Output},
combinator::Take,
digest::Digest,
instant::Instant,
};
use std::{ops::RangeFrom, slice::SliceIndex};
#[derive(Debug)]
pub struct Parser<'text, T: Action> {
pub state: T::State,
pub heap: T::Heap,
pub instant: Instant<&'text T::Text>,
pub entry: T,
}
impl<T: Action<State: Clone, Heap: Clone> + Clone> Clone for Parser<'_, T> {
fn clone(&self) -> Self {
Parser {
state: self.state.clone(),
heap: self.heap.clone(),
instant: self.instant.clone(),
entry: self.entry.clone(),
}
}
}
impl Parser<'static, Take> {
#[inline]
pub const fn builder() -> Builder<()> {
Builder::new()
}
}
impl<'text, T: Action> Parser<'text, T> {
#[inline]
pub fn reload(self, text: &T::Text) -> Parser<T>
where
T::State: Default,
{
self.reload_with(T::State::default(), text)
}
#[inline]
pub fn reload_with(self, state: impl Into<Option<T::State>>, text: &T::Text) -> Parser<T> {
Parser {
entry: self.entry,
heap: self.heap,
state: state.into().unwrap_or(self.state),
instant: Instant::new(text),
}
}
#[inline]
pub fn snapshot(&self) -> Snapshot<&'text T::Text, T::State>
where
T::State: Clone,
{
Snapshot {
state: self.state.clone(),
instant: self.instant.clone(),
}
}
#[inline]
pub fn restore(&mut self, snapshot: Snapshot<&'text T::Text, T::State>) {
self.state = snapshot.state;
self.instant = snapshot.instant;
}
#[inline]
pub fn peek(&mut self) -> (Option<Output<T::Value>>, T::State)
where
T::State: Clone,
{
let mut tmp_state = self.state.clone();
(
self.entry.exec(Input {
instant: &self.instant,
state: &mut tmp_state,
heap: &mut self.heap,
}),
tmp_state,
)
}
}
impl<T: Action<Text: Digest>> Iterator for Parser<'_, T>
where
RangeFrom<usize>: SliceIndex<T::Text, Output = T::Text>,
{
type Item = Output<T::Value>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self
.entry
.exec(Input {
instant: &self.instant,
state: &mut self.state,
heap: &mut self.heap,
})
.inspect(|output| unsafe { self.instant.digest_unchecked(output.digested) })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::contextual;
use std::rc::Rc;
#[test]
fn parser_builder() {
contextual!(i32, i32);
let parser = Parser::builder()
.state(123)
.heap(123)
.entry(eat("123"))
.build("123");
assert_eq!(parser.state, 123);
assert_eq!(parser.heap, 123);
assert_eq!(parser.instant.text(), "123");
}
#[test]
fn parser_clone() {
contextual!(i32, i32);
let parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: Rc::new(eat("123")),
}
.clone();
assert_eq!(parser.state, 123);
assert_eq!(parser.heap, 123);
}
#[test]
fn parser_getters() {
contextual!(i32, i32);
let parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
assert_eq!(
parser
.entry
.exec(Input {
instant: &Instant::new("123"),
state: &mut 0,
heap: &mut 0
})
.unwrap()
.digested,
3
);
assert_eq!(parser.instant.digested(), 0);
}
#[test]
fn parser_reload() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
parser.next();
assert_eq!(parser.instant.digested(), 3);
assert_eq!(parser.instant.rest(), "");
let parser = parser.reload("456");
assert_eq!(parser.instant.text(), "456");
assert_eq!(parser.instant.rest(), "456");
assert_eq!(parser.instant.digested(), 0);
assert_eq!(parser.state, 0);
assert_eq!(parser.heap, 123);
}
#[test]
fn parser_reload_with() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
parser.next();
assert_eq!(parser.instant.digested(), 3);
assert_eq!(parser.instant.rest(), "");
let parser = parser.reload_with(None, "456");
assert_eq!(parser.instant.text(), "456");
assert_eq!(parser.instant.rest(), "456");
assert_eq!(parser.instant.digested(), 0);
assert_eq!(parser.state, 123);
assert_eq!(parser.heap, 123);
}
#[test]
fn parser_snapshot_restore() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
parser.next();
let snapshot = parser.snapshot();
assert_eq!(snapshot.state, 123);
assert_eq!(snapshot.instant.text(), "123");
assert_eq!(snapshot.instant.digested(), 3);
assert_eq!(snapshot.instant.rest(), "");
let mut parser = Parser {
state: 0,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
parser.restore(snapshot);
assert_eq!(parser.state, 123);
assert_eq!(parser.instant.text(), "123");
assert_eq!(parser.instant.digested(), 3);
assert_eq!(parser.instant.rest(), "");
}
#[test]
fn parser_parse() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
let output = parser.next().unwrap();
assert_eq!(output.digested, 3);
assert_eq!(output.value, ());
assert_eq!(parser.instant.digested(), 3);
assert_eq!(parser.instant.rest(), "");
assert!(parser.next().is_none());
}
#[test]
fn parser_peek() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123"),
entry: eat("123"),
};
let (output, state) = parser.peek();
let output = output.unwrap();
assert_eq!(state, 123);
assert_eq!(output.digested, 3);
assert_eq!(output.value, ());
assert_eq!(parser.instant.digested(), 0);
assert_eq!(parser.instant.rest(), "123");
assert!(parser.next().is_some());
}
#[test]
fn parser_iterator_in_for_loop() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123123123"),
entry: eat("123"),
};
for o in &mut parser {
assert_eq!(o.digested, 3);
}
assert_eq!(parser.instant.digested(), 9);
}
#[test]
fn parser_iterator_with_iter_methods() {
contextual!(i32, i32);
let mut parser = Parser {
state: 123,
heap: 123,
instant: Instant::new("123123123"),
entry: eat("123"),
};
for (_, o) in (&mut parser).enumerate() {
assert_eq!(o.digested, 3);
}
assert_eq!(parser.instant.digested(), 9);
}
}