finny_derive/
parse_blocks.rs

1use syn::{Expr, ExprMethodCall, MethodTurbofish, spanned::Spanned};
2
3use crate::parse::FsmFnBase;
4
5
6#[derive(Debug)]
7pub enum FsmBlock {
8    MethodCall(FsmBlockMethodCall)
9}
10#[derive(Debug)]
11pub struct FsmBlockStruct {
12
13}
14
15pub fn decode_blocks(base: &FsmFnBase, item_fn: &syn::ItemFn) -> syn::Result<Vec<FsmBlock>> {
16    let mut ret = vec![];
17
18    for statement in &item_fn.block.stmts {
19        match statement {
20            syn::Stmt::Expr(expr) => {
21                let call = decode_method_call(base, expr)?;
22                ret.push(FsmBlock::MethodCall(call));
23            }
24            syn::Stmt::Semi(expr, _col) => {
25                let call = decode_method_call(base, expr)?;
26                ret.push(FsmBlock::MethodCall(call));
27            }
28            _ => {
29                return Err(syn::Error::new(statement.span(), "Unsupported statement."));
30            }
31        }
32    }
33
34    Ok(ret)
35}
36
37
38#[derive(Debug)]
39pub struct FsmBlockMethodCall {
40    pub expr_call: ExprMethodCall,
41    pub method_calls: Vec<ExprMethodCall>
42}
43
44pub fn decode_method_call(base: &FsmFnBase, expr: &Expr) -> syn::Result<FsmBlockMethodCall> {
45    // verify if the receiver is our builder
46    let mc = match expr {
47        Expr::MethodCall(mc) => Ok(mc),
48        _ => Err(syn::Error::new(expr.span(), "Unsupported expression. Only calls on the builder are allowed."))
49    }?;
50
51    let receiver_ident = get_method_receiver_ident(&mc.receiver)?;
52    if receiver_ident != &base.builder_ident {
53        return Err(syn::Error::new(receiver_ident.span(), "Only method calls referring to the FSM builder are allowed!"));
54    }
55
56    Ok(FsmBlockMethodCall {
57        expr_call: mc.clone(),
58        method_calls: flatten_method_calls(&mc)?
59    })
60}
61
62pub fn get_method_receiver_ident(expr: &Expr) -> syn::Result<&syn::Ident> {
63    let path = match expr {
64        Expr::MethodCall(call) => {
65            return get_method_receiver_ident(&call.receiver);
66        },
67        Expr::Path(ep) => Ok(ep),
68        _ => {
69            Err(syn::Error::new(expr.span(), "Expected a simple method receiver!"))
70        }
71    }?;
72
73    let segment = match (path.path.segments.len(), path.path.segments.first()) {
74        (1, Some(segment)) => Ok(segment),
75        (_, _) => Err(syn::Error::new(path.path.segments.span(), "Expected a single segment"))
76    }?;
77
78    Ok(&segment.ident)
79}
80
81pub fn flatten_method_calls(mc: &ExprMethodCall) -> syn::Result<Vec<ExprMethodCall>> {
82    let mut ret = vec![];
83    ret.push(mc.clone());
84
85    let mut t = &mc.receiver;
86    loop {
87        match **t {
88            Expr::MethodCall(ref ex) => {
89                ret.push(ex.clone());
90                t = &ex.receiver;
91            }
92            Expr::Path(_) => { break; }
93            _ => { return Err(syn::Error::new(mc.receiver.span(), "Unsupported.")); }
94        }
95    }
96
97    ret.reverse();
98    Ok(ret)
99}
100
101pub fn get_generics(turbofish: &Option<MethodTurbofish>) -> syn::Result<Vec<syn::Type>> {
102    let mut ret = vec![];
103
104    if let Some(turbofish) = turbofish {
105        for arg in &turbofish.args {
106            match arg {
107                syn::GenericMethodArgument::Type(ty) => { ret.push(ty.clone()); },
108                _ => { return Err(syn::Error::new(arg.span(), "Unsupported.")); }
109            }
110        }
111    }
112
113    Ok(ret)
114}