Finite state machines in rust; bendns fork to add types.
rust_fsm_dsl: move the parser to a separate submodule
Yevhenii Babichenko 2019-05-23
parent e678ea0 · commit 08093cd
-rw-r--r--rust_fsm_dsl/src/lib.rs151
-rw-r--r--rust_fsm_dsl/src/parser.rs147
2 files changed, 150 insertions, 148 deletions
diff --git a/rust_fsm_dsl/src/lib.rs b/rust_fsm_dsl/src/lib.rs
index 18b9b00..cfa93b3 100644
--- a/rust_fsm_dsl/src/lib.rs
+++ b/rust_fsm_dsl/src/lib.rs
@@ -7,154 +7,9 @@ extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use std::collections::HashSet;
-use syn::{
- braced, bracketed, parenthesized,
- parse::{Error, Parse, ParseStream, Result},
- parse_macro_input,
- token::{Bracket, Paren},
- Ident, Token, Visibility,
-};
+use syn::{parse_macro_input, Ident};
-/// The output of a state transition
-struct Output(Option<Ident>);
-
-impl Parse for Output {
- fn parse(input: ParseStream) -> Result<Self> {
- if input.lookahead1().peek(Bracket) {
- let output_content;
- bracketed!(output_content in input);
- Ok(Self(Some(output_content.parse()?)))
- } else {
- Ok(Self(None))
- }
- }
-}
-
-impl Into<Option<Ident>> for Output {
- fn into(self) -> Option<Ident> {
- self.0
- }
-}
-
-/// Represents a part of state transition without the initial state. The `Parse`
-/// trait is implemented for the compact form.
-struct TransitionEntry {
- input_value: Ident,
- final_state: Ident,
- output: Option<Ident>,
-}
-
-impl Parse for TransitionEntry {
- fn parse(input: ParseStream) -> Result<Self> {
- let input_value = input.parse()?;
- input.parse::<Token![=>]>()?;
- let final_state = input.parse()?;
- let output = input.parse::<Output>()?.into();
- Ok(Self {
- input_value,
- final_state,
- output,
- })
- }
-}
-
-/// Parses the transition in any of the possible formats.
-struct TransitionDef {
- initial_state: Ident,
- transitions: Vec<TransitionEntry>,
-}
-
-impl Parse for TransitionDef {
- fn parse(input: ParseStream) -> Result<Self> {
- let initial_state = input.parse()?;
- // Parse the transition in the simple format
- // InitialState(Input) => ResultState [Output]
- let transitions = if input.lookahead1().peek(Paren) {
- let input_content;
- parenthesized!(input_content in input);
- let input_value = input_content.parse()?;
- input.parse::<Token![=>]>()?;
- let final_state = input.parse()?;
- let output = input.parse::<Output>()?.into();
-
- vec![TransitionEntry {
- input_value,
- final_state,
- output,
- }]
- } else {
- // Parse the transition in the compact format
- // InitialState => {
- // Input1 => State1,
- // Input2 => State2 [Output]
- // }
- input.parse::<Token![=>]>()?;
- let entries_content;
- braced!(entries_content in input);
-
- let entries: Vec<_> = entries_content
- .parse_terminated::<_, Token![,]>(TransitionEntry::parse)?
- .into_iter()
- .collect();
- if entries.is_empty() {
- return Err(Error::new_spanned(
- initial_state,
- "No transitions provided for a compact representation",
- ));
- }
- entries
- };
- Ok(Self {
- initial_state,
- transitions,
- })
- }
-}
-
-/// Parses the whole state machine definition in the following form (example):
-///
-/// ```rust,ignore
-/// state_machine! {
-/// CircuitBreaker(Closed)
-///
-/// Closed(Unsuccessful) => Open [SetupTimer],
-/// Open(TimerTriggered) => HalfOpen,
-/// HalfOpen => {
-/// Successful => Closed,
-/// Unsuccessful => Open [SetupTimer]
-/// }
-/// }
-/// ```
-struct StateMachineDef {
- /// The visibility modifier (applies to all generated items)
- visibility: Visibility,
- name: Ident,
- initial_state: Ident,
- transitions: Vec<TransitionDef>,
-}
-
-impl Parse for StateMachineDef {
- fn parse(input: ParseStream) -> Result<Self> {
- let visibility = input.parse()?;
- let name = input.parse()?;
-
- let initial_state_content;
- parenthesized!(initial_state_content in input);
- let initial_state = initial_state_content.parse()?;
-
- let transitions = input
- .parse_terminated::<_, Token![,]>(TransitionDef::parse)?
- .into_iter()
- .collect();
-
- Ok(Self {
- visibility,
- name,
- initial_state,
- transitions,
- })
- }
-}
+mod parser;
/// The full information about a state transition. Used to unify the
/// represantion of the simple and the compact forms.
@@ -167,7 +22,7 @@ struct Transition<'a> {
#[proc_macro]
pub fn state_machine(tokens: TokenStream) -> TokenStream {
- let input = parse_macro_input!(tokens as StateMachineDef);
+ let input = parse_macro_input!(tokens as parser::StateMachineDef);
if input.transitions.is_empty() {
let output = quote! {
diff --git a/rust_fsm_dsl/src/parser.rs b/rust_fsm_dsl/src/parser.rs
new file mode 100644
index 0000000..0eb3f7c
--- /dev/null
+++ b/rust_fsm_dsl/src/parser.rs
@@ -0,0 +1,147 @@
+use syn::{
+ braced, bracketed, parenthesized,
+ parse::{Error, Parse, ParseStream, Result},
+ token::{Bracket, Paren},
+ Ident, Token, Visibility,
+};
+
+/// The output of a state transition
+pub struct Output(Option<Ident>);
+
+impl Parse for Output {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.lookahead1().peek(Bracket) {
+ let output_content;
+ bracketed!(output_content in input);
+ Ok(Self(Some(output_content.parse()?)))
+ } else {
+ Ok(Self(None))
+ }
+ }
+}
+
+impl Into<Option<Ident>> for Output {
+ fn into(self) -> Option<Ident> {
+ self.0
+ }
+}
+
+/// Represents a part of state transition without the initial state. The `Parse`
+/// trait is implemented for the compact form.
+pub struct TransitionEntry {
+ pub input_value: Ident,
+ pub final_state: Ident,
+ pub output: Option<Ident>,
+}
+
+impl Parse for TransitionEntry {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let input_value = input.parse()?;
+ input.parse::<Token![=>]>()?;
+ let final_state = input.parse()?;
+ let output = input.parse::<Output>()?.into();
+ Ok(Self {
+ input_value,
+ final_state,
+ output,
+ })
+ }
+}
+
+/// Parses the transition in any of the possible formats.
+pub struct TransitionDef {
+ pub initial_state: Ident,
+ pub transitions: Vec<TransitionEntry>,
+}
+
+impl Parse for TransitionDef {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let initial_state = input.parse()?;
+ // Parse the transition in the simple format
+ // InitialState(Input) => ResultState [Output]
+ let transitions = if input.lookahead1().peek(Paren) {
+ let input_content;
+ parenthesized!(input_content in input);
+ let input_value = input_content.parse()?;
+ input.parse::<Token![=>]>()?;
+ let final_state = input.parse()?;
+ let output = input.parse::<Output>()?.into();
+
+ vec![TransitionEntry {
+ input_value,
+ final_state,
+ output,
+ }]
+ } else {
+ // Parse the transition in the compact format
+ // InitialState => {
+ // Input1 => State1,
+ // Input2 => State2 [Output]
+ // }
+ input.parse::<Token![=>]>()?;
+ let entries_content;
+ braced!(entries_content in input);
+
+ let entries: Vec<_> = entries_content
+ .parse_terminated::<_, Token![,]>(TransitionEntry::parse)?
+ .into_iter()
+ .collect();
+ if entries.is_empty() {
+ return Err(Error::new_spanned(
+ initial_state,
+ "No transitions provided for a compact representation",
+ ));
+ }
+ entries
+ };
+ Ok(Self {
+ initial_state,
+ transitions,
+ })
+ }
+}
+
+/// Parses the whole state machine definition in the following form (example):
+///
+/// ```rust,ignore
+/// state_machine! {
+/// CircuitBreaker(Closed)
+///
+/// Closed(Unsuccessful) => Open [SetupTimer],
+/// Open(TimerTriggered) => HalfOpen,
+/// HalfOpen => {
+/// Successful => Closed,
+/// Unsuccessful => Open [SetupTimer]
+/// }
+/// }
+/// ```
+pub struct StateMachineDef {
+ /// The visibility modifier (applies to all generated items)
+ pub visibility: Visibility,
+ pub name: Ident,
+ pub initial_state: Ident,
+ pub transitions: Vec<TransitionDef>,
+}
+
+impl Parse for StateMachineDef {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let visibility = input.parse()?;
+ let name = input.parse()?;
+
+ let initial_state_content;
+ parenthesized!(initial_state_content in input);
+ let initial_state = initial_state_content.parse()?;
+
+ let transitions = input
+ .parse_terminated::<_, Token![,]>(TransitionDef::parse)?
+ .into_iter()
+ .collect();
+
+ Ok(Self {
+ visibility,
+ name,
+ initial_state,
+ transitions,
+ })
+ }
+}