Create a gist now

Instantly share code, notes, and snippets.

test_fsm.n
none
import-from "none.libc" printf
syntax-import "liminal.machine"
; declares a new state machine struct; all routines are compiled to machine
; language and the machine operates exclusively using function pointer tables
machine Flow
; a static predicate that always returns true
method skipmenu (ctx) :
bool <- (&this-struct)
true
; a bunch of events to be sent from outside
enum Event
start
exit
pause
gameover
loaded
frame
; a list of all states of the state machine
; also generates a "States" enum
states
main
boot
menu
load
init
; any additional code will be executed when the
; state is entered
run
printf "step!\n"
paused
printf "paused.\n"
unpaused
printf "unpaused.\n"
end
unload
quit
; a list of all transitions
transitions
; a transition without predicates happens immediately
main => boot
boot => menu
; transitions with predicates override transitions without.
; this one depends on skipmenu being true, which we defined earlier
boot => load
(self.skipmenu)
; a predicate number is interpreted as an event ID to check against
menu => quit
Event.exit
menu => load
Event.start
load => init
Event.loaded
init => run
run => run
Event.frame
run => end
Event.exit
Event.gameover
run => paused
Event.pause
paused => unpaused
Event.pause
unpaused => run
Event.frame
end => unload
unload => menu
; debug handler for all state machine changes
###method on-enter (self state) :
void <- (&this-struct this-struct.StateId)
;
escape
function (state)
print "on-enter:"
this-struct.State # state
state
; a small test
do-if (main-module?)
print "testing machine..."
; create a new instance
const flow : Flow
flow.reset ;
; reset and run until the first state that depends on an event (load)
flow.send 0
assert (flow.state == Flow.State.load)
; indicate that the game has been loaded; prints "step!"
flow.send Flow.Event.loaded
; we should now be in the run state
assert (flow.state == Flow.State.run)
; run a few frames; prints "step!" ten times
loop i (1 10)
flow.send Flow.Event.frame
; simulate pausing the game; prints "paused."
flow.send Flow.Event.pause
; we should now be in the paused state
assert (flow.state == Flow.State.paused)
; run a few frames; should print nothing
loop i (1 10)
flow.send Flow.Event.frame
; simulate unpausing the game; prints "unpaused."
flow.send Flow.Event.pause
; we should now be in the unpaused state, waiting for the next frame
assert (flow.state == Flow.State.unpaused)
; run a few frames; prints "step!" ten times
loop i (1 10)
flow.send Flow.Event.frame
assert (flow.state == Flow.State.run)
; exit the game; prints "unloaded."
flow.send Flow.Event.exit
; we should be back in the main menu
assert (flow.state == Flow.State.menu)
null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment