Finite state machines in rust; bendns fork to add types.
Diffstat (limited to 'rust-fsm-dsl/src/variant.rs')
-rw-r--r--rust-fsm-dsl/src/variant.rs123
1 files changed, 115 insertions, 8 deletions
diff --git a/rust-fsm-dsl/src/variant.rs b/rust-fsm-dsl/src/variant.rs
index f9f45f3..a59a5f6 100644
--- a/rust-fsm-dsl/src/variant.rs
+++ b/rust-fsm-dsl/src/variant.rs
@@ -5,9 +5,8 @@ use syn::{parse::Parse, *};
/// Variant with no discriminator
#[derive(Hash, Debug, PartialEq, Eq)]
pub struct Variant {
- // attrs: Vec<Attribute>,
- ident: Ident,
- field: Option<(Type, Pat)>,
+ pub ident: Ident,
+ field: Option<(Type, Pat, Option<Expr>)>,
}
impl Parse for Variant {
@@ -20,7 +19,15 @@ impl Parse for Variant {
parenthesized!(inp in input);
let t = inp.parse()?;
inp.parse::<Token![=>]>()?;
- Some((t, Pat::parse_multi(&inp)?))
+
+ Some((
+ t,
+ Pat::parse_multi(&inp)?,
+ inp.lookahead1()
+ .peek(Token![if])
+ .then(|| inp.parse::<Token![if]>().and_then(|_| inp.parse::<Expr>()))
+ .transpose()?,
+ ))
} else {
None
};
@@ -46,7 +53,7 @@ impl Ord for Variant {
impl ToTokens for Variant {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
self.ident.to_tokens(tokens);
- if let Some((t, _)) = &self.field {
+ if let Some((t, _, _)) = &self.field {
tokens.extend(quote::quote! { (#t) })
}
}
@@ -56,18 +63,118 @@ impl Variant {
pub fn match_on(&self) -> proc_macro2::TokenStream {
if let Self {
ident,
- field: Some((_, p)),
+ field: Some((_, p, g)),
} = self
{
- quote::quote! { #ident(#p) }
+ let b = g
+ .as_ref()
+ .map_or_else(Default::default, |x| quote::quote! { if #x });
+ quote::quote! { #ident(#p) #b }
} else {
self.ident.to_token_stream()
}
}
+ pub fn separate(&self) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+ if let Self {
+ ident,
+ field: Some((_, p, g)),
+ } = self
+ {
+ let b = g
+ .as_ref()
+ .map(|x| quote::quote! { if #x })
+ .unwrap_or_default();
+ (quote::quote! { #ident(#p) }, b)
+ } else {
+ (self.ident.to_token_stream(), quote::quote! {})
+ }
+ }
}
impl Display for Variant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.match_on())
+ write!(f, "{}", self.ident)
+ }
+}
+/// type and expression
+#[derive(Hash, Debug, PartialEq, Eq, Clone)]
+pub struct Final {
+ pub ident: Ident,
+ field: Option<(Type, Expr)>,
+}
+
+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.parse()?;
+ inp.parse::<Token![=>]>()?;
+
+ Some((t, inp.parse()?))
+ } else {
+ None
+ };
+ Ok(Final {
+ // attrs,
+ ident,
+ field,
+ })
+ }
+}
+
+impl PartialOrd for Final {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ self.ident.partial_cmp(&other.ident)
+ }
+}
+impl Ord for Final {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.ident.cmp(&other.ident)
+ }
+}
+
+impl ToTokens for Final {
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+ self.ident.to_tokens(tokens);
+ if let Some((v, _)) = &self.field {
+ tokens.extend(quote::quote! { (#v) })
+ }
+ }
+}
+
+impl Final {
+ pub fn reduce(&self) -> proc_macro2::TokenStream {
+ if let Self {
+ ident,
+ field: Some((_, v)),
+ } = self
+ {
+ quote::quote! { #ident ( #v ) }
+ } else {
+ self.ident.to_token_stream()
+ }
+ }
+ pub fn variant(self) -> Variant {
+ Variant {
+ ident: self.ident,
+ field: self.field.map(|(x, _)| {
+ (
+ x,
+ Pat::Wild(PatWild {
+ attrs: vec![],
+ underscore_token: Default::default(),
+ }),
+ None,
+ )
+ }),
+ }
+ }
+}
+
+impl Display for Final {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.ident)
}
}