amfiteatr_core/util/stream_parsed.rs
1use nom::character::complete::space0;
2use nom::error::ErrorKind;
3use nom::IResult;
4use nom::Parser;
5
6/// Trait for data that can be constructed with [`nom`] parser.
7/// It is designed to support hierarchical construction, typically for action.
8/// **Currently it does not work - there are some bugs to investigate**
9// /// # Example 1: Simple 2-level action construction
10// /// ```
11// /// use amfiteatr_core::util::StrParsed;
12// /// use amfiteatr_proc_macro::StrParsed;
13// /// #[derive( StrParsed, PartialEq, Debug)]
14// /// pub enum Direction{
15// /// #[keywords("up", "w")]
16// /// Up,
17// /// #[keywords("down", "s", )]
18// /// Down,
19// /// #[keywords("right", "d")]
20// /// Right,
21// /// #[keywords("left", "a")]
22// /// Left
23// /// }
24// /// #[derive(StrParsed, PartialEq, Debug)]
25// /// pub enum Action<T: amfiteatr_core::util::StrParsed >{
26// /// #[keywords("move", "m")]
27// /// Move(Direction, T),
28// /// #[keywords("look", "l", )]
29// /// Look(Direction),
30// /// #[keywords("wait", "w")]
31// /// Wait(T),
32// /// }
33// /// let a = Action::parse_from_str("m w 72 h");
34// /// let a2 = Action::parse_from_str("m w 72 h");
35// /// let d = Direction::parse_from_str("w 72 h");
36// /// assert_eq!(d, Ok(("72 h", Direction::Up)));
37// /// assert_eq!(a, Ok(("h", Action::Move(Direction::Up, 72u8))));
38// /// assert_eq!(a2, Ok(("h", Action::Move(Direction::Up, 72u8))));
39// /// ```
40pub trait StrParsed: Sized{
41 fn parse_from_str(input: &str) -> IResult<&str, Self>;
42}
43
44
45impl StrParsed for u8{
46 fn parse_from_str(input: &str) -> IResult<&str, Self> {
47 nom::sequence::terminated(nom::character::complete::u8, space0).parse(input)
48 }
49}
50
51impl StrParsed for (){
52 fn parse_from_str(input: &str) -> IResult<&str, Self> {
53 Ok((input, ()))
54 }
55}
56
57
58
59
60
61/// Helper trait to allow derived parsed from tokens like U8(u8).
62/// > When in different crate `TokenParsed` macro would fail if for something like:
63///
64/// ```no_run
65/// use amfiteatr_proc_macro::TokenVariant;
66/// #[derive(TokenVariant, PartialEq, Debug)]
67/// pub enum AToken{
68/// Up,
69/// Down,
70/// Left,
71/// Right,
72/// Wait(u8),
73/// }
74/// ```
75/// will panic because it tires to parse `u8` which is not defined in this system.
76/// To work around we define additional `[primitive]U8(u8)` that and in tree use `Wait(u8)).
77/// It may be changed in the future, when I figure out how to do it better. For now, it works.
78pub trait PrimitiveMarker<Pt>{
79
80
81 fn primitive(&self) -> Option<Pt>;
82}
83
84impl<'a, T: PrimitiveMarker<Pt>, Pt> TokenParsed<TokensBorrowed<'a, T>> for Pt{
85 fn parse_from_tokens(input: TokensBorrowed<'a, T>) -> IResult<TokensBorrowed<'a, T>, Self> {
86
87 if input.is_empty(){
88 return Err(nom::Err::Failure(nom::error::Error{input, code: ErrorKind::Eof}))
89 }
90 let token = &input[0];
91 match token.primitive(){
92 None => Err(nom::Err::Error(nom::error::Error{input, code: ErrorKind::Tag})),
93 Some(t) => {
94 let rest = TokensBorrowed(&input.0[1..]);
95 Ok((rest, t))
96 }
97 }
98
99 }
100}
101
102/// **This is very likely to change in the future**
103/// Represents slice of tokens on which parser operates.
104#[derive(Clone, Debug)]
105pub struct TokensBorrowed<'a, T>(pub &'a [T]);
106impl<'a, T> From<&'a [T]> for TokensBorrowed<'a, T>{
107 fn from(value: &'a [T]) -> Self {
108 Self(value)
109 }
110}
111
112impl<'a, T> From<&'a Vec<T>> for TokensBorrowed<'a, T>{
113 fn from(value: &'a Vec<T>) -> Self {
114 Self(&value[..])
115 }
116}
117
118
119impl<'a, T> TokensBorrowed<'a, T>{
120 pub fn len(&self) -> usize{
121 self.0.len()
122 }
123 pub fn is_empty(&self) -> bool{
124 self.len() == 0
125 }
126
127 pub(crate) fn transform_error(error: nom::error::Error<Self>) -> nom::error::Error<&'a[T]>{
128 nom::error::Error{
129 input: error.input.0,
130 code: error.code,
131 }
132 }
133 pub(crate) fn transform_err(err: nom::Err<nom::error::Error<Self>>) -> nom::Err<nom::error::Error<&'a[T]>>{
134 match err{
135 nom::Err::Incomplete(needed) => nom::Err::Incomplete(needed),
136 nom::Err::Error(error) => nom::Err::Error(Self::transform_error(error)),
137 nom::Err::Failure(fail) => nom::Err::Failure(Self::transform_error(fail))
138 }
139 }
140}
141impl<T, Idx> std::ops::Index<Idx> for TokensBorrowed<'_, T>
142where Idx: std::slice::SliceIndex<[T]>{
143 type Output = Idx::Output;
144
145 fn index(&self, index: Idx) -> &Self::Output {
146 &self.0[index]
147 }
148}
149
150/// Trait for data that can be constructed with [`nom`] parser.
151/// It is designed to support hierarchical construction, typically for action.
152/// # Example 1: Simple 2-level action construction
153/// ```
154/// use std::fmt::Alignment::Left;
155/// use nom::Input;
156/// use amfiteatr_core::util::{PrimitiveMarker, TokenParsed, TokensBorrowed};
157/// use amfiteatr_proc_macro::{TokenParsed, TokenVariant};
158///
159///
160/// #[derive(TokenVariant, PartialEq, Debug)]
161/// pub enum AToken{
162/// Up,
163/// Down,
164/// Left,
165/// Right,
166/// Move,
167/// Look,
168/// Wait,
169/// #[primitive]
170/// U8(u8),
171/// #[primitive]
172/// F32(f32),
173/// }
174///
175/// #[derive( TokenParsed, PartialEq, Debug)]
176/// #[token_type(AToken)]
177/// pub enum Direction{
178/// #[token(Up)]
179/// Up,
180/// #[token(Down)]
181/// Down,
182/// #[token(Right)]
183/// Right,
184/// #[token(Left)]
185/// Left
186/// }
187///
188///
189/// #[derive(TokenParsed, PartialEq, Debug)]
190/// #[token_type(AToken)]
191/// pub enum Action<T>
192/// where AToken: PrimitiveMarker<T>{
193/// #[token(Move)]
194/// Move{
195/// direction: Direction,
196/// distance: T
197/// },
198/// #[token(Look)]
199/// Look(Direction),
200/// #[token(Wait)]
201/// Wait(u8),
202/// }
203///
204/// let tokens_move = vec![AToken::Move, AToken::Left, AToken::U8(5u8), AToken::Look, AToken::Down ];///
205/// let borrowed = TokensBorrowed(&tokens_move[..]);
206/// let (rest, action) = Action::<u8>::parse_from_tokens(borrowed).unwrap();
207/// assert_eq!(action, Action::Move{direction: Direction::Left, distance: 5u8});
208/// assert_eq!(rest.0, &tokens_move[3..]);
209/// let (rest, action2) = Action::<u8>::parse_from_tokens(rest).unwrap();
210/// assert_eq!(action2, Action::Look(Direction::Down));
211///
212/// //let action: Action<u8> = Action::parse_from_tokens(borrowed).unwrap().1;
213/// ```
214pub trait TokenParsed<T>: Sized{
215
216 fn parse_from_tokens(input: T) -> IResult<T, Self>;
217}
218
219
220
221impl<'a, T: Sized> TokenParsed<&'a [T]> for T
222where T: TokenParsed<TokensBorrowed<'a, T>>{
223 fn parse_from_tokens(input: &'a [T]) -> IResult<&'a [T], Self> {
224 let tb = TokensBorrowed::from(input);
225 T::parse_from_tokens(tb)
226 .map(|(rest, element)|{
227 (rest.0, element)
228 }).map_err(|e| TokensBorrowed::transform_err(e))
229 }
230}
231
232/*
233impl<I> TokenParsed<I> for (){
234 fn parse_from_tokens(input: I) -> IResult<I, Self> {
235 Ok((input, ()))
236 }
237}
238
239 */
240/*
241impl TokenParsed<&str> for u8{
242 fn parse_from_tokens(input: &str) -> IResult<&str, Self> {
243 nom::sequence::terminated(nom::character::complete::u8, space0)(input)
244 }
245}
246
247
248 */
249
250#[cfg(test)]
251mod tests{
252
253}