From ca4fe43f9a521bb47c1b53fbe2288a6384e14dc2 Mon Sep 17 00:00:00 2001 From: Martin Broers Date: Thu, 27 Jun 2024 20:42:44 +0200 Subject: [PATCH] Removed on_entry flag Also the parse will not parse ">" and "<" states anymore, since all on_entry and on_exit functions will be autogenerated. Signed-off-by: Martin Broers --- README.md | 24 +--------- examples/on_entry_on_exit.rs | 70 ---------------------------- examples/on_entry_on_exit_generic.rs | 3 +- macros/src/codegen.rs | 59 ++++++++--------------- macros/src/parser/mod.rs | 37 --------------- macros/src/parser/state_machine.rs | 25 +--------- macros/src/parser/transition.rs | 33 +------------ 7 files changed, 24 insertions(+), 227 deletions(-) delete mode 100644 examples/on_entry_on_exit.rs diff --git a/README.md b/README.md index 31251fc..3eb87a0 100644 --- a/README.md +++ b/README.md @@ -262,28 +262,8 @@ This example is available in `ex3.rs`. ### Using entry and exit functions in transitions -DSL implementation: - -```rust -statemachine!{ - transitions: { - *State1 + Event1 = State2, - State2 < exit_state_2 + Event2 = State1, - State1 > enter_state_3 + Event3 = State3, - State2 + Event3 = State3, - } -} -``` -For all transitions entering State3, the function `enter_state_3` will be -called. For all transitions exiting State2, the function `exit_state_2` will be -called, in the right order, so first the `exit` function prior to the `entry` -function. - -An example is available in `on_entry_on_exit`. - -There is also a generic flag available, `generate_on_entry_on_exit`, which will -generate for all states in the statemachine an entry and an exit function. If -they are not used, they will be optimized away by the compiler. An example be +The statemachine will create for all states an `on_entry_` and `on_exit_` function. +If the are not used, they will be optimized away by the compiler. An example be found in `on_entry_on_exit_generic`. ## Helpers diff --git a/examples/on_entry_on_exit.rs b/examples/on_entry_on_exit.rs deleted file mode 100644 index f01a564..0000000 --- a/examples/on_entry_on_exit.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! An example of using state data to propagate events (See issue-17) - -#![deny(missing_docs)] - -use smlang::statemachine; - -statemachine! { - name: OnEntryExample, - generate_entry_exit_states: true, - transitions: { - *D0 > exit_d0 + ToD1 = D1, - D0 + ToD3 = D3, - D1 < enter_d1 + ToD2 = D2, - D2 + ToD1 = D1, - D1 + ToD0 = D0, - }, -} - -/// Context -pub struct Context { - exited_d0: i32, - entered_d1: i32, -} - -impl OnEntryExampleStateMachineContext for Context { - fn on_exit_d0(&mut self) { - self.exited_d0 += 1; - } - fn on_entry_d1(&mut self) { - self.entered_d1 += 1; - } -} - -fn main() { - let mut sm = OnEntryExampleStateMachine::new(Context { - exited_d0: 0, - entered_d1: 0, - }); - - // first event starts the dominos - let _ = sm.process_event(OnEntryExampleEvents::ToD1).unwrap(); - - assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D1))); - assert_eq!(sm.context().exited_d0, 1); - assert_eq!(sm.context().entered_d1, 1); - - let _ = sm.process_event(OnEntryExampleEvents::ToD2).unwrap(); - - assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D2))); - assert_eq!(sm.context().exited_d0, 1); - assert_eq!(sm.context().entered_d1, 1); - - let _ = sm.process_event(OnEntryExampleEvents::ToD1).unwrap(); - - assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D1))); - assert_eq!(sm.context().exited_d0, 1); - assert_eq!(sm.context().entered_d1, 2); - - let _ = sm.process_event(OnEntryExampleEvents::ToD0).unwrap(); - - assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D0))); - assert_eq!(sm.context().exited_d0, 1); - assert_eq!(sm.context().entered_d1, 2); - - let _ = sm.process_event(OnEntryExampleEvents::ToD3).unwrap(); - - assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D3))); - assert_eq!(sm.context().exited_d0, 2); - assert_eq!(sm.context().entered_d1, 2); -} diff --git a/examples/on_entry_on_exit_generic.rs b/examples/on_entry_on_exit_generic.rs index bde15e5..608869b 100644 --- a/examples/on_entry_on_exit_generic.rs +++ b/examples/on_entry_on_exit_generic.rs @@ -6,9 +6,8 @@ use smlang::statemachine; statemachine! { name: OnEntryExample, - generate_entry_exit_states: true, transitions: { - *D0 < exit_d0 + ToD1 = D1, + *D0 + ToD1 = D1, D0 + ToD3 = D3, D1 + ToD2 = D2, D2 + ToD1 = D1, diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index b742db3..ab77552 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -19,12 +19,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { let state_machine_context_type_name = format_ident!("{sm_name}StateMachineContext", span = sm_name_span); - let generate_entry_exit_states = sm.generate_entry_exit_states; let generate_transition_callback = sm.generate_transition_callback; - let mut entry_fns = sm.entry_functions.clone(); - let mut exit_fns = sm.exit_functions.clone(); - // Get only the unique states let mut state_list: Vec<_> = sm.states.values().collect(); state_list.sort_by_key(|state| state.to_string()); @@ -255,18 +251,6 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { let mut action_list = proc_macro2::TokenStream::new(); let mut entries_exits = proc_macro2::TokenStream::new(); - for ident in entry_fns.values() { - entries_exits.extend(quote! { - #[allow(missing_docs)] - fn #ident(&mut self){} - }); - } - for ident in exit_fns.values() { - entries_exits.extend(quote! { - #[allow(missing_docs)] - fn #ident(&mut self){} - }); - } for (state, event_mappings) in transitions.iter() { // create the state data token stream @@ -275,20 +259,17 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { Some(st) => quote! { state_data: &#st, }, None => quote! {}, }; - if generate_entry_exit_states { - let entry_ident = format_ident!("on_entry_{}", string_morph::to_snake_case(state)); - entries_exits.extend(quote! { - #[allow(missing_docs)] - fn #entry_ident(&mut self){} - }); - entry_fns.insert(format_ident!("{}", state), entry_ident); - let exit_ident = format_ident!("on_exit_{}", string_morph::to_snake_case(state)); - entries_exits.extend(quote! { - #[allow(missing_docs)] - fn #exit_ident(&mut self){} - }); - exit_fns.insert(format_ident!("{}", state), exit_ident); - }; + + let entry_ident = format_ident!("on_entry_{}", string_morph::to_snake_case(state)); + entries_exits.extend(quote! { + #[allow(missing_docs)] + fn #entry_ident(&mut self){} + }); + let exit_ident = format_ident!("on_exit_{}", string_morph::to_snake_case(state)); + entries_exits.extend(quote! { + #[allow(missing_docs)] + fn #exit_ident(&mut self){} + }); for (event, event_mapping) in event_mappings { for transition in &event_mapping.transitions { @@ -446,19 +427,17 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { let binding = out_state.to_string(); let out_state_string = &binding.split('(').collect::>()[0]; - let entry_ident = format_ident!("on_entry_{}",string_morph::to_snake_case(out_state_string )); let binding = in_state.to_string(); let in_state_string = &binding.split('(').collect::>()[0]; - let exit_ident = format_ident!("on_exit_{}",string_morph::to_snake_case(in_state_string)); - let entry_exit_states = if generate_entry_exit_states { - quote! { - self.context_mut().#exit_ident(); - self.context_mut().#entry_ident(); - } - } else { - quote! { } - }; + let entry_ident = format_ident!("on_entry_{}", string_morph::to_snake_case(out_state_string)); + let exit_ident = format_ident!("on_exit_{}", string_morph::to_snake_case(in_state_string)); + + let entry_exit_states = + quote! { + self.context_mut().#exit_ident(); + self.context_mut().#entry_ident(); + }; let (is_async_action,action_code) = generate_action(action, &temporary_context_call, g_a_param); is_async_state_machine |= is_async_action; if let Some(expr) = guard { // Guarded transition diff --git a/macros/src/parser/mod.rs b/macros/src/parser/mod.rs index 418b9ba..dbb01aa 100644 --- a/macros/src/parser/mod.rs +++ b/macros/src/parser/mod.rs @@ -20,13 +20,6 @@ use syn::{parse, Ident, Type}; use transition::StateTransition; pub type TransitionMap = HashMap>; -#[derive(Debug, Clone)] -pub struct EntryIdent { - pub ident: Ident, - pub state: Vec, - pub is_async: bool, -} - #[derive(Debug, Clone)] pub struct AsyncIdent { pub ident: Ident, @@ -64,10 +57,7 @@ pub struct ParsedStateMachine { pub event_data: DataDefinitions, pub states_events_mapping: HashMap>, - pub generate_entry_exit_states: bool, pub generate_transition_callback: bool, - pub entry_functions: HashMap, - pub exit_functions: HashMap, } // helper function for adding a transition to a transition event map @@ -147,29 +137,6 @@ impl ParsedStateMachine { let mut event_data = DataDefinitions::new(); let mut states_events_mapping = TransitionMap::new(); - let mut states_with_exit_function = HashMap::new(); - let mut states_with_entry_function = HashMap::new(); - - fn add_entry(map: &mut HashMap, vec: &Vec) -> parse::Result<()> { - for identifier in vec { - for input_state in &identifier.state { - if let Some(existing_identifier) = - map.insert(input_state.ident.clone(), identifier.ident.clone()) - { - if identifier.ident != existing_identifier { - return Err(parse::Error::new( - Span::call_site(), - "Different entry or exit functions defined for state", - )); - } - } - } - } - Ok(()) - } - add_entry(&mut states_with_entry_function, &sm.entries)?; - add_entry(&mut states_with_exit_function, &sm.exits)?; - for transition in sm.transitions.iter() { // Collect states let in_state_name = transition.in_state.ident.to_string(); @@ -265,11 +232,7 @@ impl ParsedStateMachine { events, event_data, states_events_mapping, - generate_entry_exit_states: sm.generate_entry_exit_states, generate_transition_callback: sm.generate_transition_callback, - - entry_functions: states_with_entry_function, - exit_functions: states_with_exit_function, }) } } diff --git a/macros/src/parser/state_machine.rs b/macros/src/parser/state_machine.rs index 48f9e9c..5933f62 100644 --- a/macros/src/parser/state_machine.rs +++ b/macros/src/parser/state_machine.rs @@ -1,7 +1,4 @@ -use super::{ - transition::{StateTransition, StateTransitions}, - EntryIdent, -}; +use super::transition::{StateTransition, StateTransitions}; use syn::{braced, bracketed, parse, spanned::Spanned, token, Ident, Token, Type}; #[derive(Debug)] @@ -12,10 +9,7 @@ pub struct StateMachine { pub name: Option, pub derive_states: Vec, pub derive_events: Vec, - pub generate_entry_exit_states: bool, pub generate_transition_callback: bool, - pub entries: Vec, - pub exits: Vec, } impl StateMachine { @@ -27,10 +21,7 @@ impl StateMachine { name: None, derive_states: Vec::new(), derive_events: Vec::new(), - generate_entry_exit_states: false, generate_transition_callback: false, - entries: Vec::new(), - exits: Vec::new(), } } @@ -45,12 +36,6 @@ impl StateMachine { }; self.transitions.push(transition); } - if let Some(entry) = transitions.entry { - self.entries.push(entry); - } - if let Some(exit) = transitions.exit { - self.exits.push(exit); - } } } @@ -155,13 +140,6 @@ impl parse::Parse for StateMachine { }; } } - "generate_entry_exit_states" => { - input.parse::()?; - let generate_entry_exit_states: syn::LitBool = input.parse()?; - if generate_entry_exit_states.value { - statemachine.generate_entry_exit_states = true - } - } "generate_transition_callback" => { input.parse::()?; let generate_transition_callback: syn::LitBool = input.parse()?; @@ -179,7 +157,6 @@ impl parse::Parse for StateMachine { \"custom_guard_error\", \"derive_states\", \"derive_events\", - \"generate_entry_exit_states\", \"generate_transition_callback\", ]", keyword diff --git a/macros/src/parser/transition.rs b/macros/src/parser/transition.rs index efe2ef1..e7031ef 100644 --- a/macros/src/parser/transition.rs +++ b/macros/src/parser/transition.rs @@ -1,7 +1,7 @@ +use super::event::Event; use super::input_state::InputState; use super::output_state::OutputState; use super::AsyncIdent; -use super::{event::Event, EntryIdent}; use proc_macro2::TokenStream; use quote::quote; use std::fmt; @@ -22,8 +22,6 @@ pub struct StateTransitions { pub event: Event, pub guard: Option, pub action: Option, - pub entry: Option, - pub exit: Option, pub out_state: OutputState, } @@ -50,33 +48,6 @@ impl parse::Parse for StateTransitions { } } } - - // Possible extry function - let entry = if input.parse::().is_ok() { - let is_async = input.parse::().is_ok(); - let entry_function: Ident = input.parse()?; - Some(EntryIdent { - ident: entry_function, - state: in_states.clone(), - is_async, - }) - } else { - None - }; - let exit = if input.parse::]>().is_ok() { - let is_async = input.parse::().is_ok(); - let exit_function: Ident = match input.parse() { - Ok(v) => v, - Err(e) => panic!("Could not parse exit token: {:?}", e), - }; - Some(EntryIdent { - ident: exit_function, - state: in_states.clone(), - is_async, - }) - } else { - None - }; // Event let event: Event = input.parse()?; @@ -109,8 +80,6 @@ impl parse::Parse for StateTransitions { guard, action, out_state, - entry, - exit, }) } }