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.rs147
1 files changed, 80 insertions, 67 deletions
diff --git a/rust-fsm-dsl/src/variant.rs b/rust-fsm-dsl/src/variant.rs
index a59a5f6..82e981c 100644
--- a/rust-fsm-dsl/src/variant.rs
+++ b/rust-fsm-dsl/src/variant.rs
@@ -1,12 +1,47 @@
-use std::fmt::Display;
+use std::{collections::BTreeSet, fmt::Display};
+use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{parse::Parse, *};
/// Variant with no discriminator
-#[derive(Hash, Debug, PartialEq, Eq)]
+#[derive(Debug, Clone)]
pub struct Variant {
pub ident: Ident,
- field: Option<(Type, Pat, Option<Expr>)>,
+ pub field: Option<(Option<Type>, Pat, Option<Expr>)>,
+}
+
+pub fn find_type(of: &Variant, list: &[Variant]) -> Option<Type> {
+ of.field.clone().and_then(|(x, _, _)| {
+ x.or_else(|| {
+ let i = &of.ident;
+ list.iter()
+ .filter(|x| &x.ident == i)
+ .filter_map(|x| x.field.as_ref().and_then(|x| x.0.clone()))
+ .next()
+ })
+ })
+}
+pub fn tokenize(
+ inputs: &[Variant],
+ f: impl FnOnce(Vec<TokenStream>) -> TokenStream,
+) -> TokenStream {
+ let (Ok(x) | Err(x)) = BTreeSet::from_iter(inputs)
+ .into_iter()
+ .map(|x| {
+ let i = &x.ident;
+ x.field
+ .as_ref()
+ .map(|_| {
+ let y = find_type(x, &*inputs);
+ y.ok_or(Error::new_spanned(&x.ident, "type never specified"))
+ .map(|y| quote::quote! {#i(#y)})
+ })
+ .unwrap_or(Ok(quote::quote! { #i }))
+ })
+ .collect::<Result<_>>()
+ .map_err(Error::into_compile_error)
+ .map(f);
+ x
}
impl Parse for Variant {
@@ -17,11 +52,17 @@ impl Parse for Variant {
let field = if input.peek(token::Paren) {
let inp;
parenthesized!(inp in input);
- let t = inp.parse()?;
- inp.parse::<Token![=>]>()?;
+ let ty = inp
+ .to_string()
+ .contains("=>")
+ .then(|| {
+ inp.parse()
+ .and_then(|x| inp.parse::<Token![=>]>().map(|_| x))
+ })
+ .transpose()?;
Some((
- t,
+ ty,
Pat::parse_multi(&inp)?,
inp.lookahead1()
.peek(Token![if])
@@ -39,6 +80,13 @@ impl Parse for Variant {
}
}
+impl PartialEq for Variant {
+ fn eq(&self, other: &Self) -> bool {
+ self.ident == other.ident
+ }
+}
+impl Eq for Variant {}
+
impl PartialOrd for Variant {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.ident.partial_cmp(&other.ident)
@@ -50,15 +98,6 @@ 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 {
- tokens.extend(quote::quote! { (#t) })
- }
- }
-}
-
impl Variant {
pub fn match_on(&self) -> proc_macro2::TokenStream {
if let Self {
@@ -82,7 +121,7 @@ impl Variant {
{
let b = g
.as_ref()
- .map(|x| quote::quote! { if #x })
+ .map(|x| quote::quote! { if (#x) })
.unwrap_or_default();
(quote::quote! { #ident(#p) }, b)
} else {
@@ -97,11 +136,8 @@ impl Display for Variant {
}
}
/// type and expression
-#[derive(Hash, Debug, PartialEq, Eq, Clone)]
-pub struct Final {
- pub ident: Ident,
- field: Option<(Type, Expr)>,
-}
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct Final(Variant);
impl Parse for Final {
fn parse(input: parse::ParseStream) -> Result<Self> {
@@ -109,72 +145,49 @@ impl Parse for Final {
let field = if input.peek(token::Paren) {
let inp;
parenthesized!(inp in input);
- let t = inp.parse()?;
- inp.parse::<Token![=>]>()?;
+ let t = inp
+ .to_string()
+ .contains("=>")
+ .then(|| {
+ inp.parse()
+ .and_then(|x| inp.parse::<Token![=>]>().map(|_| x))
+ })
+ .transpose()?;
- Some((t, inp.parse()?))
+ Some((
+ t,
+ Pat::Wild(PatWild {
+ attrs: vec![],
+ underscore_token: Default::default(),
+ }),
+ Some(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) })
- }
+ Ok(Final(Variant { ident, field }))
}
}
impl Final {
pub fn reduce(&self) -> proc_macro2::TokenStream {
- if let Self {
+ if let Self(Variant {
ident,
- field: Some((_, v)),
- } = self
+ field: Some((_, _, v)),
+ }) = self
{
quote::quote! { #ident ( #v ) }
} else {
- self.ident.to_token_stream()
+ self.0.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,
- )
- }),
- }
+ self.0
}
}
impl Display for Final {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.ident)
+ write!(f, "{}", self.0)
}
}