pub mod fn_stream;
pub mod io_stream;
pub type StreamGetFn<'a,T> = dyn FnMut() -> Option<T> + 'a;
pub enum StreamResult<T> {
Ok(T),
Err(StreamError)
}
impl<T: fmt::Debug> fmt::Debug for StreamResult<T> {
fn fmt(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Ok(v) => write!(f,"Ok({:?})",v),
Self::Err(e) => write!(f,"Err({:?})",e),
}
}
}
#[derive(Clone,Debug,PartialEq,Eq,Hash)]
pub enum StreamError {
EmptyStream,
NotHandledPattern,
Str(String),
}
use std::fmt;
impl fmt::Display for StreamError {
fn fmt(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StreamError::EmptyStream => write!(f,"empty stream"),
StreamError::NotHandledPattern => write!(f,"stream pattern not handled"),
StreamError::Str(s) => write!(f,"stream error: '{}'",s),
}
}
}
pub trait Stream<'a> {
type Item;
fn token(&mut self,x: usize) -> StreamResult<Self::Item>;
fn junk(&mut self,x: usize);
fn pos(&self) -> usize;
}
#[macro_export]
macro_rules! smatch {
(@p $body: expr;$stream: expr,$cnt: expr; -> $($pat: tt)*) => {{
smatch!(@p $body; ; $stream,$cnt ;$($pat)*)
}
};
(@p $body: expr; $($assign: ident),*; $stream: expr,$cnt: expr; _ => $($rest:tt)*) => {
{let res = $stream.token($cnt);
match res {
StreamResult::Ok(_) => {smatch!(@p $body; $name; $stream,$cnt + 1;$($rest)*)},
_ => (None,false)
}
}
};
(@p $body: expr; $($assign: ident),*; $stream: expr,$cnt: expr; $name : ident => $($rest:tt)*) => {
{let p = $stream.token($cnt);
if let StreamResult::Ok($name) = p {
smatch!(@p $body; $name; $stream,$cnt + 1;$($rest)*)
} else {
(None,false)
}
}
};
(@p $body:expr;$($assign: ident),*;$stream: expr,$cnt: expr; $p: pat => $($rest:tt)*) => {{
let p = $stream.token($cnt);
if let StreamResult::Ok($p) = p {
$(
let $assign = $assign;
)*
smatch!(@p $body; ; $stream,$cnt + 1;$($rest)*)
} else {
(None,false)
}
}
};
(@p $body: expr; $($assign: ident),*; $stream: expr,$cnt: expr; $name : ident = $p: expr => $($rest:tt)*) => {
{let $name = $p;
smatch!(@p $body; $name; $stream,$cnt + 1;$($rest)*)
}
};
(@p $body: expr; $($assign: ident),*;$stream: expr,$cnt: expr;) => {
{$stream.junk($cnt);
(Some($body),true)
}
};
(match ($s: expr) {
$(
[ $($p: tt)* ] => $body: expr
),*
}) => {
loop {
$(
let res = smatch!(@p $body; $s,0; -> $($p)*);
if let (Some(val),true) = res {
break $crate::StreamResult::Ok(val);
}
)*
break $crate::StreamResult::Err($crate::StreamError::EmptyStream)
}
};
}