union_impl/expr_chain/
expr_chain_with_default.rs

1//!
2//! `ExprChain` definition and `ExprChainWithDefault` implementation.
3//!
4//!
5
6use quote::ToTokens;
7use std::cell::{Ref, RefCell};
8use std::rc::Rc;
9use syn::parse::ParseStream;
10use syn::Expr::Let;
11use syn::{Pat, Token};
12
13use super::*;
14use crate::instant_and_deferred_determiners;
15
16///
17/// Defines inner struct of `ExprChain`.
18///
19struct ExprChainInternal<Member, GroupDeterminer> {
20    members: Vec<Member>,
21    group_determiners: Vec<GroupDeterminer>,
22    pat: Option<Pat>,
23}
24
25///
26/// Defines public struct with inner `ExprChainInternal`.
27///
28pub struct ExprChain<Member, GroupDeterminer> {
29    inner: Rc<RefCell<ExprChainInternal<Member, GroupDeterminer>>>,
30}
31
32///
33/// Defines combination of possible `ProcessActionExpr` with possible `DefaultActionExpr`.
34/// At least one element should be not `None`.
35///
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct ProcessWithDefault(pub Option<ProcessActionExpr>, pub Option<DefaultActionExpr>);
38
39///
40/// ExprChain of `ProcessWithDefault` with determiner `GroupDeterminer`.
41///
42pub type ExprChainWithDefault = ExprChain<ProcessWithDefault, GroupDeterminer>;
43
44///
45/// Implementation of `Chain` with `Member=ProcessWithDefault`.
46///
47impl Chain for ExprChainWithDefault {
48    type Member = ProcessWithDefault;
49
50    fn new(
51        input: ParseStream,
52        other_pattern_check: Box<dyn Fn(ParseStream<'_>) -> bool>,
53    ) -> syn::Result<Option<ExprChainWithDefault>> {
54        let mut group_determiners = instant_and_deferred_determiners! {
55            Map => Token![|], Token![>]; 2,
56            Then => Token![->]; 2,
57            AndThen => Token![=>]; 2,
58            Or => Token![<], Token![|]; 2,
59            OrElse => Token![<=]; 2,
60            Dot => Token![>], Token![.]; 2,
61            MapErr => Token![!], Token![>]; 2,
62            Inspect => Token![?], Token![>]; 2
63        };
64
65        group_determiners.extend(vec![
66            GroupDeterminer::new(None, other_pattern_check, Some(Box::new(is_valid_expr)), 0),
67            GroupDeterminer::new(
68                None,
69                Box::new(|input| input.peek(Token![,])),
70                Some(Box::new(is_valid_expr)),
71                0,
72            ),
73        ]);
74
75        let inner = Rc::new(RefCell::new(ExprChainInternal {
76            members: Vec::new(),
77            group_determiners,
78            pat: None,
79        }));
80
81        let expr_chain = ExprChain { inner };
82
83        if input.is_empty() {
84            Ok(None)
85        } else {
86            expr_chain.process(input)?;
87            Ok(Some(expr_chain))
88        }
89    }
90
91    fn get_members(&self) -> Ref<'_, Vec<Self::Member>> {
92        Ref::map(RefCell::borrow(&self.inner), |inner| &inner.members)
93    }
94
95    fn get_pat(&self) -> Ref<'_, Option<Pat>> {
96        Ref::map(RefCell::borrow(&self.inner), |inner| &inner.pat)
97    }
98}
99
100impl ExprChainWithDefault {
101    ///
102    /// Parses unit using self `GroupDeterminer`'s to determine unit end.
103    ///
104    fn parse_unit(&self, input: ParseStream) -> UnitResult {
105        let expr_chain = RefCell::borrow(&self.inner);
106        parse_until(input, &expr_chain.group_determiners[..])
107    }
108
109    ///
110    /// Parses input, fills self members with given expressions.
111    ///
112    fn process(&self, input: ParseStream) -> syn::Result<()> {
113        let mut group_type = Some(ActionGroup::Instant(CommandGroup::Initial));
114        let mut is_block;
115        let mut member_index = 0;
116
117        while {
118            let input = input;
119            let Unit {
120                mut expr,
121                next_group_type,
122            } = self.parse_unit(input)?;
123
124            if member_index == 0 {
125                if let Let(let_expr) = expr {
126                    self.inner.borrow_mut().pat = Some(let_expr.pat);
127                    expr = *let_expr.expr;
128                }
129            }
130
131            let (default_expr, next_group_type) = match next_group_type {
132                Some(ActionGroup::Instant(CommandGroup::Or))
133                | Some(ActionGroup::Deferred(CommandGroup::Or)) => {
134                    let current_group_type = next_group_type.unwrap();
135                    let Unit {
136                        expr,
137                        next_group_type,
138                    } = self.parse_unit(input)?;
139                    Some((
140                        current_group_type.map_to_default_action_expr(expr),
141                        next_group_type,
142                    ))
143                }
144                Some(ActionGroup::Instant(CommandGroup::OrElse))
145                | Some(ActionGroup::Deferred(CommandGroup::OrElse)) => {
146                    let current_group_type = next_group_type.unwrap();
147                    let Unit {
148                        expr,
149                        next_group_type,
150                    } = self.parse_unit(input)?;
151                    Some((
152                        current_group_type.map_to_default_action_expr(expr),
153                        next_group_type,
154                    ))
155                }
156                _ => None,
157            }
158            .unwrap_or((None, next_group_type));
159
160            let expr = group_type
161                .and_then(|action_group_type| action_group_type.map_to_process_action_expr(expr));
162
163            is_block = default_expr
164                .as_ref()
165                .map_or_else(
166                    || expr.as_ref().map(|expr| expr.extract_expr().clone()),
167                    |v| Some(v.extract_expr().clone()),
168                )
169                .map(|expr| is_block_expr(&expr))
170                .unwrap_or(false);
171
172            let member = ProcessWithDefault(expr, default_expr);
173
174            if member_index == 0
175                && match &member {
176                    ProcessWithDefault(expr, _) => expr
177                        .as_ref()
178                        .unwrap()
179                        .extract_expr()
180                        .into_token_stream()
181                        .is_empty(),
182                }
183            {
184                return Err(input.error("Chain first member can't be empty"));
185            }
186
187            if member.0.is_some() || member.1.is_some() {
188                self.inner.borrow_mut().members.push(member);
189            }
190
191            member_index += 1;
192
193            group_type = next_group_type;
194
195            group_type.is_some()
196        } {}
197
198        let members = &RefCell::borrow(&self.inner).members;
199
200        if members.is_empty() {
201            Err(input.error("Chain can't be empty"))
202        } else {
203            if is_block {
204                input.parse::<Option<Token![,]>>()?;
205            } else if !input.is_empty() {
206                input.parse::<Token![,]>()?;
207            }
208            Ok(())
209        }
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::super::expr::{DefaultExpr, ProcessExpr};
216    use super::*;
217    use ::quote::quote;
218    use ::syn::parse::Parse;
219
220    impl Parse for ExprChainWithDefault {
221        fn parse(input: ParseStream) -> syn::Result<Self> {
222            ExprChainWithDefault::new(input, Box::new(|_| false))
223                .transpose()
224                .ok_or(input.error("empty"))?
225        }
226    }
227
228    #[test]
229    fn it_parses_chain_from_3_process_expr() {
230        let chain =
231            ::syn::parse2::<ExprChainWithDefault>(quote! { Ok(2) => |v| Ok(v + 1) |> |v| v + 2 })
232                .unwrap();
233        assert_eq!(chain.get_members().len(), 3);
234        assert!(chain.get_pat().is_none());
235    }
236
237    #[test]
238    fn it_parses_chain_from_3_process_expr_and_1_default_expr() {
239        let chain = ::syn::parse2::<ExprChainWithDefault>(
240            quote! { Ok(2) => |v| Ok(v + 1) |> |v| v + 2 <| Ok(2) },
241        )
242        .unwrap();
243        assert_eq!(chain.get_members().len(), 3);
244        assert!(chain.get_pat().is_none());
245    }
246
247    #[test]
248    fn it_parses_chain_from_initial_expr() {
249        let chain = ::syn::parse2::<ExprChainWithDefault>(quote! { Ok(2) }).unwrap();
250        assert_eq!(chain.get_members().len(), 1);
251        assert!(chain.get_pat().is_none());
252    }
253
254    #[test]
255    fn it_attempts_to_parse_empty_chain() {
256        assert!(::syn::parse2::<ExprChainWithDefault>(quote! {}).is_err());
257    }
258
259    #[test]
260    fn it_parses_chain_with_all_possible_command_expressions() {
261        let chain = ::syn::parse2::<ExprChainWithDefault>(quote! {
262            Ok(2) => |_| Ok(3) |> |_| 4 <| Ok(5) => |v| Ok(v) <= |_| Ok(8) ?> |v| println!("{}", v) -> |v| v
263        })
264        .unwrap();
265        let members = chain.get_members();
266        assert_eq!(
267            members[0],
268            ProcessWithDefault(
269                Some(ProcessActionExpr::Instant(ProcessExpr::Initial(
270                    syn::parse2(quote! { Ok(2) }).unwrap()
271                ))),
272                None
273            )
274        );
275        assert_eq!(
276            members[1],
277            ProcessWithDefault(
278                Some(ProcessActionExpr::Instant(ProcessExpr::AndThen(
279                    syn::parse2(quote! { |_| Ok(3) }).unwrap()
280                ))),
281                None
282            )
283        );
284
285        assert_eq!(
286            members[2],
287            ProcessWithDefault(
288                Some(ProcessActionExpr::Instant(ProcessExpr::Map(
289                    syn::parse2(quote! { |_| 4 }).unwrap()
290                ))),
291                Some(DefaultActionExpr::Instant(DefaultExpr::Or(
292                    syn::parse2(quote! { Ok(5) }).unwrap()
293                )))
294            )
295        );
296
297        assert_eq!(
298            members[3],
299            ProcessWithDefault(
300                Some(ProcessActionExpr::Instant(ProcessExpr::AndThen(
301                    syn::parse2(quote! { |v| Ok(v) }).unwrap()
302                ))),
303                Some(DefaultActionExpr::Instant(DefaultExpr::OrElse(
304                    syn::parse2(quote! { |_| Ok(8) }).unwrap()
305                )))
306            )
307        );
308
309        assert_eq!(
310            members[4],
311            ProcessWithDefault(
312                Some(ProcessActionExpr::Instant(ProcessExpr::Inspect(
313                    syn::parse2(quote! { |v| println!("{}", v) }).unwrap()
314                ))),
315                None
316            )
317        );
318
319        assert_eq!(
320            members[5],
321            ProcessWithDefault(
322                Some(ProcessActionExpr::Instant(ProcessExpr::Then(
323                    syn::parse2(quote! { |v| v }).unwrap()
324                ))),
325                None
326            )
327        );
328    }
329
330    #[test]
331    fn it_parses_chain_with_all_possible_deferred_command_expressions() {
332        let chain = ::syn::parse2::<ExprChainWithDefault>(quote! {
333            Ok(2) ~=> |_| Ok(3) ~|> |_| 4 ~<| Ok(5) ~=> |v| Ok(v) ~<= |_| Ok(8) ~?> |v| println!("{}", v) ~-> |v| v
334        }).unwrap();
335
336        let members = chain.get_members();
337        assert_eq!(
338            members[0],
339            ProcessWithDefault(
340                Some(ProcessActionExpr::Instant(ProcessExpr::Initial(
341                    syn::parse2(quote! { Ok(2) }).unwrap()
342                ))),
343                None
344            )
345        );
346        assert_eq!(
347            members[1],
348            ProcessWithDefault(
349                Some(ProcessActionExpr::Deferred(ProcessExpr::AndThen(
350                    syn::parse2(quote! { |_| Ok(3) }).unwrap()
351                ))),
352                None
353            )
354        );
355
356        assert_eq!(
357            members[2],
358            ProcessWithDefault(
359                Some(ProcessActionExpr::Deferred(ProcessExpr::Map(
360                    syn::parse2(quote! { |_| 4 }).unwrap()
361                ))),
362                Some(DefaultActionExpr::Deferred(DefaultExpr::Or(
363                    syn::parse2(quote! { Ok(5) }).unwrap()
364                )))
365            )
366        );
367
368        assert_eq!(
369            members[3],
370            ProcessWithDefault(
371                Some(ProcessActionExpr::Deferred(ProcessExpr::AndThen(
372                    syn::parse2(quote! { |v| Ok(v) }).unwrap()
373                ))),
374                Some(DefaultActionExpr::Deferred(DefaultExpr::OrElse(
375                    syn::parse2(quote! { |_| Ok(8) }).unwrap()
376                )))
377            )
378        );
379
380        assert_eq!(
381            members[4],
382            ProcessWithDefault(
383                Some(ProcessActionExpr::Deferred(ProcessExpr::Inspect(
384                    syn::parse2(quote! { |v| println!("{}", v) }).unwrap()
385                ))),
386                None
387            )
388        );
389
390        assert_eq!(
391            members[5],
392            ProcessWithDefault(
393                Some(ProcessActionExpr::Deferred(ProcessExpr::Then(
394                    syn::parse2(quote! { |v| v }).unwrap()
395                ))),
396                None
397            )
398        );
399    }
400}