1pub mod fn_stream;
2pub mod io_stream;
3pub type StreamGetFn<'a,T> = dyn FnMut() -> Option<T> + 'a;
4
5pub enum StreamResult<T> {
6 Ok(T),
7 Err(StreamError)
8}
9
10impl<T: fmt::Debug> fmt::Debug for StreamResult<T> {
11 fn fmt(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result {
12 match self {
13 Self::Ok(v) => write!(f,"Ok({:?})",v),
14 Self::Err(e) => write!(f,"Err({:?})",e),
15 }
16 }
17}
18
19#[derive(Clone,Debug,PartialEq,Eq,Hash)]
20pub enum StreamError {
21 EmptyStream,
22 NotHandledPattern,
23 Str(String),
24}
25
26use std::fmt;
27impl fmt::Display for StreamError {
28 fn fmt(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 StreamError::EmptyStream => write!(f,"empty stream"),
31 StreamError::NotHandledPattern => write!(f,"stream pattern not handled"),
32 StreamError::Str(s) => write!(f,"stream error: '{}'",s),
33 }
34 }
35}
36
37
38pub trait Stream<'a> {
57 type Item;
58 fn token(&mut self,x: usize) -> StreamResult<Self::Item>;
60 fn junk(&mut self,x: usize);
62 fn pos(&self) -> usize;
64}
65
66#[macro_export]
72macro_rules! smatch {
73 (@p $body: expr;$stream: expr,$cnt: expr; -> $($pat: tt)*) => {{
74
75 smatch!(@p $body; ; $stream,$cnt ;$($pat)*)
76
77 }
78 };
79 (@p $body: expr; $($assign: ident),*; $stream: expr,$cnt: expr; _ => $($rest:tt)*) => {
80 {let res = $stream.token($cnt);
81 match res {
82 StreamResult::Ok(_) => {smatch!(@p $body; $name; $stream,$cnt + 1;$($rest)*)},
83 _ => (None,false)
84 }
85 }
91 };
92 (@p $body: expr; $($assign: ident),*; $stream: expr,$cnt: expr; $name : ident => $($rest:tt)*) => {
93 {let p = $stream.token($cnt);
94 if let StreamResult::Ok($name) = p {
95 smatch!(@p $body; $name; $stream,$cnt + 1;$($rest)*)
96 } else {
97 (None,false)
98 }
99 }
100 };
101 (@p $body:expr;$($assign: ident),*;$stream: expr,$cnt: expr; $p: pat => $($rest:tt)*) => {{
102 let p = $stream.token($cnt);
103 if let StreamResult::Ok($p) = p {
104
105 $(
106 let $assign = $assign;
107 )*
108 smatch!(@p $body; ; $stream,$cnt + 1;$($rest)*)
109 } else {
110
111 (None,false)
112 }
113 }
114 };
115 (@p $body: expr; $($assign: ident),*; $stream: expr,$cnt: expr; $name : ident = $p: expr => $($rest:tt)*) => {
128 {let $name = $p;
129 smatch!(@p $body; $name; $stream,$cnt + 1;$($rest)*)
133 }
134 };
135
136 (@p $body: expr; $($assign: ident),*;$stream: expr,$cnt: expr;) => {
137 {$stream.junk($cnt);
138 (Some($body),true)
139 }
140 };
141
142 (match ($s: expr) {
143 $(
144 [ $($p: tt)* ] => $body: expr
145 ),*
146 }) => {
147 loop {
148 $(
149 let res = smatch!(@p $body; $s,0; -> $($p)*);
150 if let (Some(val),true) = res {
151 break $crate::StreamResult::Ok(val);
152 }
153 )*
154 break $crate::StreamResult::Err($crate::StreamError::EmptyStream)
155 }
156 };
157
158}