Skip to content

Commit

Permalink
Implement multiple entry/exit actions handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dziegel committed Feb 5, 2025
1 parent 762fb47 commit f699285
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 67 deletions.
2 changes: 2 additions & 0 deletions generator/src/generator/Instance.egl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#pragma once

#include <array>

// Override the following defines according to your needs if you are not using cpp_event_framework:

#ifndef [%=statemachine.name%]_GET_INSTANCE_EVENT_ID
Expand Down
4 changes: 2 additions & 2 deletions generator/src/generator/InstanceHandler.egl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ static [%=statemachine.name%]::[%=statemachine.transition_type%] [%=state.scoped

[%
if (not state.all_events.isEmpty()) {
var unique_id = new Tuple();
unique_id.id = 0;
var unique_id = new Tuple();
unique_id.id = 0;
%]
switch([%=statemachine.name%]_GET_INSTANCE_EVENT_ID(event))
{
Expand Down
16 changes: 15 additions & 1 deletion generator/src/generator/InstanceState.egl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,21 @@
%]
// State [%=state.readable_scoped_name%]
[%=handlerTemplate.process()%]
const [%=statemachine.name%]::[%=state.state_type%] [%=statemachine.name%]::[%=state.variable_name%]("[%=state.readable_scoped_name%]", &[%=state.scoped_name%]Handler, [%=state.parent_variable_pointer%], [%=state.initial_variable_pointer%], [%=state.entry_pointer%], [%=state.exit_pointer%]);
[%
if (state.entry_var != "{}") {
%]
static const auto [%=state.entry_var%] = std::to_array<[%=statemachine.name%]::[%=statemachine.state_entry_exit_type%]>({[%=state.entry_pointers%]});
[%
}
%]
[%
if (state.exit_var != "{}") {
%]
static const auto [%=state.exit_var%] = std::to_array<[%=statemachine.name%]::[%=statemachine.state_entry_exit_type%]>({[%=state.exit_pointers%]});
[%
}
%]
const [%=statemachine.name%]::[%=state.state_type%] [%=statemachine.name%]::[%=state.variable_name%]("[%=state.readable_scoped_name%]", &[%=state.scoped_name%]Handler, [%=state.parent_variable_pointer%], [%=state.initial_variable_pointer%], [%=state.entry_var%], [%=state.exit_var%]);
[%
if (state.region.isDefined()) {
var regionTemplate : Template = TemplateFactory.load("InstanceRegion.egl");
Expand Down
59 changes: 39 additions & 20 deletions generator/src/generator/Transformations.egl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ operation Tuple transformStatemachine() {
self.transition_type = "Transition";
self.transition_action_type = "ActionType";
self.state_type = "State";
self.state_entry_exit_type = "State::EntryExitType";
self.history_state_type = "HistoryState";
self.event_type = "Event";
self.impl_type = "Impl";
Expand All @@ -21,6 +22,22 @@ operation Tuple transformStatemachine() {
self.all_entry_exit = self.all_entry_exit.sortBy(e | e);
}

operation List splitEntries() : List {
var result = new List();
for (entry in self) {
if (entry.matches(".*,.*")) {
result.addAll(entry.split(","));
} else {
result.add(entry);
}
}
return result;
}

operation String splitEntries() : List {
return self.split(",");
}

operation Tuple regionCollectStates(statemachine : Tuple, parent_state : Tuple) {
self.states = self.states.sortBy(s | s.name);

Expand Down Expand Up @@ -79,27 +96,41 @@ operation Tuple stateTransform(statemachine : Tuple, region : Tuple, parent_stat
}

// Entry action
self.entry_pointer = "nullptr";
self.entry_var = "{}";
if (self.entry.isDefined()) {
self.entry_var = statemachine.name + "_" + self.name + "_entry";

if (self.entry == "") {
(sm.name + ": Empty entry function in state " + self.name).errln();
}
self.entry_pointer = "&" + statemachine.name + "::" + "Impl::" + self.entry;
if (not statemachine.all_entry_exit.includes(self.entry)) {
statemachine.all_entry_exit.add(self.entry);

var entry_pointers_list = new List();
for (entry in self.entry.splitEntries()) {
entry_pointers_list.add("&" + statemachine.name + "::" + "Impl::" + entry);
if (not statemachine.all_entry_exit.includes(entry)) {
statemachine.all_entry_exit.add(entry);
}
}
self.entry_pointers = entry_pointers_list.concat(", ");
}

// Exit action
self.exit_pointer = "nullptr";
self.exit_var = "{}";
if (self.exit.isDefined()) {
self.exit_var = statemachine.name + "_" + self.name + "_exit";

if (self.exit == "") {
(sm.name + ": Empty exit function in state " + self.name).errln();
}
self.exit_pointer = "&" + statemachine.name + "::" + "Impl::" + self.exit;
if (not statemachine.all_entry_exit.includes(self.exit)) {
statemachine.all_entry_exit.add(self.exit);

var exit_pointers_list = new List();
for (ex in self.exit.splitEntries()) {
exit_pointers_list.add("&" + statemachine.name + "::" + "Impl::" + ex);
if (not statemachine.all_entry_exit.includes(ex)) {
statemachine.all_entry_exit.add(ex);
}
}
self.exit_pointers = exit_pointers_list.concat(", ");
}

// Initial state
Expand Down Expand Up @@ -144,18 +175,6 @@ operation Tuple stateTransform(statemachine : Tuple, region : Tuple, parent_stat
}
}

operation List splitEntries() : List {
var result = new List();
for (entry in self) {
if (entry.matches(".*,.*")) {
result.addAll(entry.split(","));
} else {
result.add(entry);
}
}
return result;
}

operation Tuple transitionTransform(statemachine : Tuple, state : Tuple, trigger: String, all_actions: List) {
self.trans_conditional = new List();
self.trans_unconditional = new List();
Expand Down
60 changes: 42 additions & 18 deletions test/XmiFsmImpl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ void XmiFsmImpl::Test()
assert(fsm_.CurrentState() == &XmiTest::kState_1State_4State_5);
assert(state3_on_exit_called_);
state3_on_exit_called_ = false;
assert(state4_on_entry_called_);
state4_on_entry_called_ = false;
assert(state4_on_entry1_called_);
state4_on_entry1_called_ = false;
assert(state4_on_entry2_called_);
state4_on_entry2_called_ = false;
CheckAllFalse();

// Transition in history compartment
Expand All @@ -93,17 +95,21 @@ void XmiFsmImpl::Test()
// Step out of history compartment
fsm_.React(Transition_8::MakeShared());
assert(fsm_.CurrentState() == &XmiTest::kState_1State_2);
assert(state4_on_exit_called_);
state4_on_exit_called_ = false;
assert(state4_on_exit1_called_);
state4_on_exit1_called_ = false;
assert(state4_on_exit2_called_);
state4_on_exit2_called_ = false;
assert(state2_on_entry_called_);
state2_on_entry_called_ = false;
CheckAllFalse();

// Reenter history compartment, history must be preserved
fsm_.React(Transition_6::MakeShared());
assert(fsm_.CurrentState() == &XmiTest::kState_1State_4StateWithSameName);
assert(state4_on_entry_called_);
state4_on_entry_called_ = false;
assert(state4_on_entry1_called_);
state4_on_entry1_called_ = false;
assert(state4_on_entry2_called_);
state4_on_entry2_called_ = false;
CheckAllFalse();

// Choice: No guards return true
Expand All @@ -124,8 +130,10 @@ void XmiFsmImpl::Test()
choice_action3_called_ = false;
assert(state3_on_entry_called_);
state3_on_entry_called_ = false;
assert(state4_on_exit_called_);
state4_on_exit_called_ = false;
assert(state4_on_exit1_called_);
state4_on_exit1_called_ = false;
assert(state4_on_exit2_called_);
state4_on_exit2_called_ = false;
assert(comma_action_called_);
comma_action_called_ = false;
CheckAllFalse();
Expand All @@ -135,8 +143,10 @@ void XmiFsmImpl::Test()
assert(fsm_.CurrentState() == &XmiTest::kState_1State_4StateWithSameName);
assert(state3_on_exit_called_);
state3_on_exit_called_ = false;
assert(state4_on_entry_called_);
state4_on_entry_called_ = false;
assert(state4_on_entry1_called_);
state4_on_entry1_called_ = false;
assert(state4_on_entry2_called_);
state4_on_entry2_called_ = false;
CheckAllFalse();

// Choice: Two guards return true
Expand Down Expand Up @@ -172,8 +182,10 @@ void XmiFsmImpl::Test()
choice_action4_called_ = false;
assert(state2_on_entry_called_);
state2_on_entry_called_ = false;
assert(state4_on_exit_called_);
state4_on_exit_called_ = false;
assert(state4_on_exit1_called_);
state4_on_exit1_called_ = false;
assert(state4_on_exit2_called_);
state4_on_exit2_called_ = false;
assert(comma_action_called_);
comma_action_called_ = false;
CheckAllFalse();
Expand All @@ -197,8 +209,10 @@ void XmiFsmImpl::CheckAllFalse() const
assert(state2_on_entry_called_ == false);
assert(state3_on_entry_called_ == false);
assert(state3_on_exit_called_ == false);
assert(state4_on_entry_called_ == false);
assert(state4_on_exit_called_ == false);
assert(state4_on_entry1_called_ == false);
assert(state4_on_entry2_called_ == false);
assert(state4_on_exit1_called_ == false);
assert(state4_on_exit2_called_ == false);
}

void XmiFsmImpl::UnhandledEvent()
Expand Down Expand Up @@ -293,13 +307,23 @@ void XmiFsmImpl::State3OnExit()
std::cout << std::source_location::current().function_name() << "\n";
state3_on_exit_called_ = true;
}
void XmiFsmImpl::State4OnEntry()
void XmiFsmImpl::State4OnEntry1()
{
std::cout << std::source_location::current().function_name() << "\n";
state4_on_entry_called_ = true;
state4_on_entry1_called_ = true;
}
void XmiFsmImpl::State4OnExit()
void XmiFsmImpl::State4OnEntry2()
{
std::cout << std::source_location::current().function_name() << "\n";
state4_on_exit_called_ = true;
state4_on_entry2_called_ = true;
}
void XmiFsmImpl::State4OnExit1()
{
std::cout << std::source_location::current().function_name() << "\n";
state4_on_exit1_called_ = true;
}
void XmiFsmImpl::State4OnExit2()
{
std::cout << std::source_location::current().function_name() << "\n";
state4_on_exit2_called_ = true;
}
12 changes: 8 additions & 4 deletions test/XmiFsmImpl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ private:
void State3OnEntry() override;
bool state3_on_exit_called_ = false;
void State3OnExit() override;
bool state4_on_entry_called_ = false;
void State4OnEntry() override;
bool state4_on_exit_called_ = false;
void State4OnExit() override;
bool state4_on_entry1_called_ = false;
void State4OnEntry1() override;
bool state4_on_entry2_called_ = false;
void State4OnEntry2() override;
bool state4_on_exit1_called_ = false;
void State4OnExit1() override;
bool state4_on_exit2_called_ = false;
void State4OnExit2() override;

void CheckAllFalse() const;
};
2 changes: 1 addition & 1 deletion test/generated/IScXmlTestImpl.hxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Statemachine ScXmlTest implementation interface
// Generated: 17.10.24, 21:37
// Generated: 05.02.25, 22:41

#pragma once

Expand Down
8 changes: 5 additions & 3 deletions test/generated/IXmiTestImpl.hxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Statemachine XmiTest implementation interface
// Generated: 17.10.24, 21:37
// Generated: 05.02.25, 22:34

#pragma once

Expand Down Expand Up @@ -30,6 +30,8 @@ class IXmiTestImpl
virtual void State2OnEntry() = 0;
virtual void State3OnEntry() = 0;
virtual void State3OnExit() = 0;
virtual void State4OnEntry() = 0;
virtual void State4OnExit() = 0;
virtual void State4OnEntry1() = 0;
virtual void State4OnEntry2() = 0;
virtual void State4OnExit1() = 0;
virtual void State4OnExit2() = 0;
};
2 changes: 1 addition & 1 deletion test/generated/ScXmlTestDeclaration.hxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Statemachine ScXmlTest declaration
// Generated: 17.10.24, 21:37
// Generated: 05.02.25, 22:41

#pragma once

Expand Down
22 changes: 15 additions & 7 deletions test/generated/ScXmlTestInstance.hxx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Statemachine ScXmlTest instance
// Generated: 17.10.24, 21:37
// Generated: 05.02.25, 22:41

#pragma once

#include <array>

// Override the following defines according to your needs if you are not using cpp_event_framework:

#ifndef ScXmlTest_GET_INSTANCE_EVENT_ID
Expand All @@ -22,7 +24,8 @@ static ScXmlTest::Transition State_1Handler(ScXmlTest::ImplPtr impl, ScXmlTest::
(void) event; // No outgoing transitions
return ScXmlTest::UnhandledEvent();
}
const ScXmlTest::State ScXmlTest::kState_1("State_1", &State_1Handler, nullptr, &ScXmlTest::kState_1State_2, &ScXmlTest::Impl::State1OnEntry, nullptr);
static const auto ScXmlTest_State_1_entry = std::to_array<ScXmlTest::State::EntryExitType>({&ScXmlTest::Impl::State1OnEntry});
const ScXmlTest::State ScXmlTest::kState_1("State_1", &State_1Handler, nullptr, &ScXmlTest::kState_1State_2, ScXmlTest_State_1_entry, {});

// State State_1::State_2
static ScXmlTest::Transition State_1State_2Handler(ScXmlTest::ImplPtr impl, ScXmlTest::Event event)
Expand Down Expand Up @@ -53,7 +56,8 @@ static ScXmlTest::Transition State_1State_2Handler(ScXmlTest::ImplPtr impl, ScXm
}
return ScXmlTest::UnhandledEvent();
}
const ScXmlTest::State ScXmlTest::kState_1State_2("State_1::State_2", &State_1State_2Handler, &ScXmlTest::kState_1, nullptr, &ScXmlTest::Impl::State2OnEntry, nullptr);
static const auto ScXmlTest_State_2_entry = std::to_array<ScXmlTest::State::EntryExitType>({&ScXmlTest::Impl::State2OnEntry});
const ScXmlTest::State ScXmlTest::kState_1State_2("State_1::State_2", &State_1State_2Handler, &ScXmlTest::kState_1, nullptr, ScXmlTest_State_2_entry, {});

// State State_1::State_3
static ScXmlTest::Transition State_1State_3Handler(ScXmlTest::ImplPtr impl, ScXmlTest::Event event)
Expand All @@ -71,7 +75,9 @@ static ScXmlTest::Transition State_1State_3Handler(ScXmlTest::ImplPtr impl, ScXm
}
return ScXmlTest::UnhandledEvent();
}
const ScXmlTest::State ScXmlTest::kState_1State_3("State_1::State_3", &State_1State_3Handler, &ScXmlTest::kState_1, nullptr, &ScXmlTest::Impl::State3OnEntry, &ScXmlTest::Impl::State3OnExit);
static const auto ScXmlTest_State_3_entry = std::to_array<ScXmlTest::State::EntryExitType>({&ScXmlTest::Impl::State3OnEntry});
static const auto ScXmlTest_State_3_exit = std::to_array<ScXmlTest::State::EntryExitType>({&ScXmlTest::Impl::State3OnExit});
const ScXmlTest::State ScXmlTest::kState_1State_3("State_1::State_3", &State_1State_3Handler, &ScXmlTest::kState_1, nullptr, ScXmlTest_State_3_entry, ScXmlTest_State_3_exit);

// State State_1::State_4
static ScXmlTest::Transition State_1State_4Handler(ScXmlTest::ImplPtr impl, ScXmlTest::Event event)
Expand All @@ -89,7 +95,9 @@ static ScXmlTest::Transition State_1State_4Handler(ScXmlTest::ImplPtr impl, ScXm
}
return ScXmlTest::UnhandledEvent();
}
const ScXmlTest::HistoryState ScXmlTest::kState_1State_4("State_1::State_4", &State_1State_4Handler, &ScXmlTest::kState_1, &ScXmlTest::kState_1State_4State_5, &ScXmlTest::Impl::State4OnEntry, &ScXmlTest::Impl::State4OnExit);
static const auto ScXmlTest_State_4_entry = std::to_array<ScXmlTest::State::EntryExitType>({&ScXmlTest::Impl::State4OnEntry});
static const auto ScXmlTest_State_4_exit = std::to_array<ScXmlTest::State::EntryExitType>({&ScXmlTest::Impl::State4OnExit});
const ScXmlTest::HistoryState ScXmlTest::kState_1State_4("State_1::State_4", &State_1State_4Handler, &ScXmlTest::kState_1, &ScXmlTest::kState_1State_4State_5, ScXmlTest_State_4_entry, ScXmlTest_State_4_exit);

// State State_1::State_4::State_5
static ScXmlTest::Transition State_1State_4State_5Handler(ScXmlTest::ImplPtr impl, ScXmlTest::Event event)
Expand All @@ -107,7 +115,7 @@ static ScXmlTest::Transition State_1State_4State_5Handler(ScXmlTest::ImplPtr imp
}
return ScXmlTest::UnhandledEvent();
}
const ScXmlTest::State ScXmlTest::kState_1State_4State_5("State_1::State_4::State_5", &State_1State_4State_5Handler, &ScXmlTest::kState_1State_4, nullptr, nullptr, nullptr);
const ScXmlTest::State ScXmlTest::kState_1State_4State_5("State_1::State_4::State_5", &State_1State_4State_5Handler, &ScXmlTest::kState_1State_4, nullptr, {}, {});

// State State_1::State_4::State_6
static ScXmlTest::Transition State_1State_4State_6Handler(ScXmlTest::ImplPtr impl, ScXmlTest::Event event)
Expand All @@ -125,4 +133,4 @@ static ScXmlTest::Transition State_1State_4State_6Handler(ScXmlTest::ImplPtr imp
}
return ScXmlTest::UnhandledEvent();
}
const ScXmlTest::State ScXmlTest::kState_1State_4State_6("State_1::State_4::State_6", &State_1State_4State_6Handler, &ScXmlTest::kState_1State_4, nullptr, nullptr, nullptr);
const ScXmlTest::State ScXmlTest::kState_1State_4State_6("State_1::State_4::State_6", &State_1State_4State_6Handler, &ScXmlTest::kState_1State_4, nullptr, {}, {});
2 changes: 1 addition & 1 deletion test/generated/XmiTestDeclaration.hxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Statemachine XmiTest declaration
// Generated: 17.10.24, 21:37
// Generated: 05.02.25, 22:34

#pragma once

Expand Down
Loading

0 comments on commit f699285

Please # to comment.