Guards and Action Effects¶
Guards and actions form the computational layer of Extended Finite State Machines (EFSM). Guards evaluate predicates over events and context variables, while actions execute side effects and mutate context state.
1. Pure Guard Predicates¶
Guards are side-effect-free boolean functions. In the fsmc execution model, guards receive references to the triggering event, the active state, and the user context struct.
A guard is a pure boolean predicate:
$\(\text{Guard}: (\text{Event}, \text{State}, \text{Context}) \to \{\text{true}, \text{false}\}\)$
If the predicate evaluates to false, the transition is rejected (guard_rejected) and the state machine remains in the source state.
2. Compile-Time Boolean Algebra & Composite Guards¶
During compilation, the GuardSimplificationPass analyzes and reduces composite boolean guard trees algebraically:
- Double negation elimination:
not(not A) => A - Neutral elements:
A and true => A,A or false => A - Dominant elements:
A and false => false,A or true => true
3. Automatic Resolved EFSM Expressions¶
In formal models (SysML v2, Cameo, SCXML), guard expressions such as [batteryLevel >= 20.0 and isGpsLocked] and actions such as do waypointIndex += 1; are automatically parsed, type-checked, and emitted directly without requiring manual stub implementations:
// Automatically emitted resolved guard in generated C++ header
struct Guard_batteryLevel_gte_20 {
template <typename Event, typename State, typename Context>
[[nodiscard]] constexpr bool operator()(const Event& /*evt*/, const State& /*state*/, const Context& ctx) const noexcept {
return ctx.batteryLevel >= 20.0 && ctx.isGpsLocked;
}
};
// Automatically emitted resolved action in generated C++ header
struct Action_increment_waypoint {
template <typename Event, typename SrcState, typename DstState, typename Context>
constexpr void operator()(const Event& /*evt*/, SrcState& /*src*/, DstState& /*dst*/, Context& ctx) const noexcept {
ctx.waypointIndex += 1;
}
};
4. Choice and Junction Inlining (ChoiceInliningPass)¶
When models contain intermediate decision points (<<choice>> or <<junction>>), the middle-end optimizer inlines the decision trees directly into flat composite transitions.
For example, a transition path StateA -> ChoiceNode -> StateB with incoming guard G1 and outgoing guard G2 is transformed into a direct edge StateA -> StateB guarded by fsm::and_<G1, G2> and executing the combined actions A1 and A2. This eliminates intermediate state allocations and enables direct branch resolution.