finny_derive/
parse_blocks.rs1use 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 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}