Finite state machines in rust; bendns fork to add types.
_ syntax :hmm
| -rw-r--r-- | rust-fsm-dsl/src/lib.rs | 10 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/variant.rs | 86 |
2 files changed, 55 insertions, 41 deletions
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs index 1b25fba..ed1d729 100644 --- a/rust-fsm-dsl/src/lib.rs +++ b/rust-fsm-dsl/src/lib.rs @@ -111,7 +111,9 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { .unwrap(); let (initial_, guard_) = initial_state.separate(); - let final_ = final_state.reduce(); + let final_ = final_state + .reduce() + .map_or(initial_state.match_on(), |x| quote! { #x }); let (input_, guard) = input_value.separate(); let guard = guard_ .clone() @@ -129,7 +131,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { .map(|x| { #[cfg(feature = "diagram")] mermaid_diagram.push_str(&format!(" [\"{x}\"]")); - let output = x.reduce(); + let output = x.reduce().unwrap(); quote! { ::core::option::Option::Some(Self::Output::#output) } }) .unwrap_or(quote! { ::core::option::Option::None }); @@ -144,10 +146,10 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { mermaid_diagram.push('\n'); states.push(initial_state.clone()); - states.push(final_state.clone().variant()); + states.extend(final_state.clone().variant()); inputs.push(input_value.clone()); if let Some(output) = output { - outputs.push(output.clone().variant()); + outputs.push(output.clone().variant().unwrap()); } } diff --git a/rust-fsm-dsl/src/variant.rs b/rust-fsm-dsl/src/variant.rs index 681b0a2..3bbd080 100644 --- a/rust-fsm-dsl/src/variant.rs +++ b/rust-fsm-dsl/src/variant.rs @@ -130,57 +130,69 @@ impl Display for Variant { } /// type and expression #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Final(Variant); +pub struct Final(Option<Variant>); impl Parse for Final { fn parse(input: parse::ParseStream) -> Result<Self> { - let ident: Ident = input.parse()?; - let field = if input.peek(token::Paren) { - let inp; - parenthesized!(inp in input); - let t = inp - .to_string() - .contains("=>") - .then(|| { - inp.parse() - .and_then(|x| inp.parse::<Token![=>]>().map(|_| x)) - }) - .transpose()?; + let b = input.peek(Token![_]); + b.then(|| input.parse::<Token![_]>()).transpose()?; + (!b).then(|| { + let ident: Ident = input.parse()?; + let field = if input.peek(token::Paren) { + let inp; + parenthesized!(inp in input); + let t = inp + .to_string() + .contains("=>") + .then(|| { + inp.parse() + .and_then(|x| inp.parse::<Token![=>]>().map(|_| x)) + }) + .transpose()?; - Some(( - t, - Pat::Wild(PatWild { - attrs: vec![], - underscore_token: Default::default(), - }), - Some(inp.parse()?), - )) - } else { - None - }; - Ok(Final(Variant { ident, field })) + Some(( + t, + Pat::Wild(PatWild { + attrs: vec![], + underscore_token: Default::default(), + }), + Some(inp.parse()?), + )) + } else { + None + }; + Ok(Variant { ident, field }) + }) + .transpose() + .map(Self) } } impl Final { - pub fn reduce(&self) -> proc_macro2::TokenStream { - if let Self(Variant { - ident, - field: Some((_, _, v)), - }) = self - { - quote::quote! { #ident ( #v ) } - } else { - self.0.ident.to_token_stream() - } + pub fn reduce(&self) -> Option<proc_macro2::TokenStream> { + self.0.as_ref().map(|x: &Variant| { + if let Variant { + ident, + field: Some((_, _, v)), + } = x + { + quote::quote! { #ident ( #v ) } + } else { + x.ident.to_token_stream() + } + }) } - pub fn variant(self) -> Variant { + pub fn variant(self) -> Option<Variant> { self.0 } } impl Display for Final { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) + write!( + f, + "{}", + self.0.as_ref().map(|x| x.to_string()).unwrap_or("_".into()) + ) } } |