Module statemachine
A finite state machine implementation in Lua.
State machines are defined as a class from a config table, and then instantiated with a context table. The class validates and copies the config once, and instances are cheap to create.
Example:
local StateMachine = require "statemachine" -- Step 1: Create a class (validates config, copies states — done once) local DoorLock = StateMachine({ initial_state = "locked", states = { locked = { enter = function(self, ctx, from) end, -- Note: from is nil when first started! leave = function(self, ctx, to) end, step = function(self, ctx) end, -- return seconds, or nil for no stepping transitions = { -- The callback is also a guard: return true to allow, or nil+err to block. unlocked = function(self, ctx, to) if not ctx.has_key then return nil, "key required to unlock" end return true end, }, }, unlocked = { enter = function(self, ctx, from) end, leave = function(self, ctx, to) end, step = function(self, ctx) end, transitions = { locked = function(self, ctx, to) return true end, }, }, }, }) -- Step 2: Create instances (cheap — just stores ctx and enters initial state) local door1 = DoorLock({ count = 0, has_key = true }) local door2 = DoorLock({ count = 0 }) -- Step 3: Transition (returns nil+err if guard blocks, raises on missing path) local ok, err = door1:transition_to("unlocked") -- ok = true local ok, err = door2:transition_to("unlocked") -- ok = nil, err = "key required to unlock"
Info:
- Copyright: Copyright (c) 2026-2026 Thijs Schreijer
- License: MIT, see LICENSE.md.
- Author: Thijs Schreijer
Functions
| SMClass ([ctx={}]) | Create a new instance from this class. |
| SMInstance:get_context () | Get the shared context table. |
| SMInstance:get_current_state () | Get the current state name. |
| SMInstance:has_transition_to (state) | Check if a transition path to the given state exists from the current state. |
| SMInstance:step () | Invoke the current state's step callback and return its result. |
Functions
- SMClass ([ctx={}])
-
Create a new instance from this class.
Parameters:
- ctx table the shared context table (default {})
Returns:
- SMInstance a new state machine instance
-
any
the return value of the initial state's
entercallback, ortrueif it returned nothing (typically this is the number of seconds after which to call the step callback, but it can be used for any purpose).
- SMInstance:get_context ()
-
Get the shared context table.
Returns:
-
table
the context table
- SMInstance:get_current_state ()
-
Get the current state name.
Returns:
-
string
the current state name
- SMInstance:has_transition_to (state)
-
Check if a transition path to the given state exists from the current state.
This is a static check; it does not invoke the transition callback/guard.
Use
transition_toto perform the actual (guarded) transition.Parameters:
- state string the target state name
Returns:
-
boolean
true if a transition path exists
- SMInstance:step ()
-
Invoke the current state's step callback and return its result.
The step callback is intended for time-driven behaviour such as timeouts
and retries. By convention it returns the number of seconds the caller
should wait before calling step again, or
nilwhen no further stepping is needed.When step calls
transition_tointernally it shouldreturnthe result, so that the new state's requested delay (from itsentercallback) is propagated back to the caller.Returns:
-
number or nil
seconds until the next call, or nil if not needed