Finite state machines in rust; bendns fork to add types.
_ syntax :hmm
bendn 5 months ago
parent 633b2e2 · commit 02a2666
-rw-r--r--rust-fsm-dsl/src/lib.rs10
-rw-r--r--rust-fsm-dsl/src/variant.rs86
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())
+ )
}
}