use super::{Tree, Location, Token, Stream};
pub struct Context<I: Stream> {
input: I,
stack: Vec<(Location, Box<dyn Tree>)>,
locs: Vec<Location>,
}
impl<I: Stream> Context<I> {
pub fn new(input: I) -> Self {
Self {input, stack: Vec::new(), locs: Vec::new()}
}
pub fn pop(&mut self) -> Location {
self.locs.pop().expect("No tokens have been read")
}
pub fn drain(&mut self) -> impl Iterator<Item=Location> + '_ { self.locs.drain(..) }
fn read_inner(&mut self) -> Token {
if let Some((loc, t)) = self.stack.pop() {
Token(loc, Ok(t))
} else {
self.input.read()
}
}
pub fn read_any(&mut self) -> Result<Box<dyn Tree>, String> {
let Token(loc, t) = self.read_inner();
self.locs.push(loc);
t
}
pub fn read<T: Tree>(&mut self) -> Result<Option<Box<T>>, String> {
Ok(match self.read_any()?.downcast::<T>() {
Ok(t) => Some(t),
Err(t) => { self.unread(t); None },
})
}
pub fn read_if<T: Tree>(
&mut self,
is_wanted: impl FnOnce(&T) -> bool,
) -> Result<Option<Box<T>>, String> {
Ok(self.read::<T>()?.and_then(
|t| if is_wanted(&*t) { Some(t) } else { self.unread(t); None }
))
}
pub fn unread(&mut self, tree: Box<dyn Tree>) {
let loc = self.pop();
self.stack.push((loc, tree));
}
}
pub trait Parse: Sized {
fn parse(
&self,
input: &mut Context<impl Stream>,
) -> Result<Box<dyn Tree>, String>;
fn parse_stream<I: Stream>(self, input: I) -> ParseStream<Self, I> {
ParseStream {parse: self, input: Context::new(input)}
}
}
pub struct ParseStream<P: Parse, I: Stream> {
parse: P,
input: Context<I>,
}
impl<P: Parse, I: Stream> Stream for ParseStream<P, I> {
fn read(&mut self) -> Token {
match self.parse.parse(&mut self.input) {
Ok(token) => {
let loc = Location::union(self.input.drain());
Token(loc, Ok(token))
},
Err(e) => {
let loc = self.input.pop();
let _ = self.input.drain();
Token(loc, Err(e.into()))
},
}
}
}