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}