1POE::NFA(3) User Contributed Perl Documentation POE::NFA(3)
2
3
4
6 POE::NFA - an event-driven state machine (nondeterministic finite
7 automaton)
8
10 use POE::Kernel;
11 use POE::NFA;
12 use POE::Wheel::ReadLine;
13
14 # Spawn an NFA and enter its initial state.
15 POE::NFA->spawn(
16 inline_states => {
17 initial => {
18 setup => \&setup_stuff,
19 },
20 state_login => {
21 on_entry => \&login_prompt,
22 on_input => \&save_login,
23 },
24 state_password => {
25 on_entry => \&password_prompt,
26 on_input => \&check_password,
27 },
28 state_cmd => {
29 on_entry => \&command_prompt,
30 on_input => \&handle_command,
31 },
32 },
33 )->goto_state(initial => "setup");
34
35 POE::Kernel->run();
36 exit;
37
38 sub setup_stuff {
39 $_[RUNSTATE]{io} = POE::Wheel::ReadLine->new(
40 InputEvent => 'on_input',
41 );
42 $_[MACHINE]->goto_state(state_login => "on_entry");
43 }
44
45 sub login_prompt { $_[RUNSTATE]{io}->get('Login: '); }
46
47 sub save_login {
48 $_[RUNSTATE]{login} = $_[ARG0];
49 $_[MACHINE]->goto_state(state_password => "on_entry");
50 }
51
52 sub password_prompt { $_[RUNSTATE]{io}->get('Password: '); }
53
54 sub check_password {
55 if ($_[RUNSTATE]{login} eq $_[ARG0]) {
56 $_[MACHINE]->goto_state(state_cmd => "on_entry");
57 }
58 else {
59 $_[MACHINE]->goto_state(state_login => "on_entry");
60 }
61 }
62
63 sub command_prompt { $_[RUNSTATE]{io}->get('Cmd: '); }
64
65 sub handle_command {
66 $_[RUNSTATE]{io}->put(" <<$_[ARG0]>>");
67 if ($_[ARG0] =~ /^(?:quit|stop|exit|halt|bye)$/i) {
68 $_[RUNSTATE]{io}->put('Bye!');
69 $_[MACHINE]->stop();
70 }
71 else {
72 $_[MACHINE]->goto_state(state_cmd => "on_entry");
73 }
74 }
75
77 POE::NFA implements a different kind of POE session: A non-
78 deterministic finite automaton. Let's break that down.
79
80 A finite automaton is a state machine with a bounded number of states
81 and transitions. Technically, POE::NFA objects may modify themselves
82 at run time, so they aren't really "finite". Run-time modification
83 isn't currently supported by the API, so plausible deniability is
84 maintained!
85
86 Deterministic state machines are ones where all possible transitions
87 are known at compile time. POE::NFA is "non-deterministic" because
88 transitions may change based on run-time conditions.
89
90 But more simply, POE::NFA is like POE::Session but with banks of event
91 handlers that may be swapped according to the session's run-time state.
92 Consider the SYNOPSIS example, which has "on_entry" and "on_input"
93 handlers that do different things depending on the run-time state.
94 POE::Wheel::ReadLine throws "on_input", but different things happen
95 depending whether the session is in its "login", "password" or
96 "command" state.
97
98 POE::NFA borrows heavily from POE::Session, so this document will only
99 discuss the differences. Please see POE::Session for things which are
100 similar.
101
103 This document mainly focuses on the differences from POE::Session.
104
105 get_current_state
106 Each machine state has a name. get_current_state() returns the name of
107 the machine's current state. get_current_state() is mainly used to
108 retrieve the state of some other machine. It's easier (and faster) to
109 use $_[STATE] in a machine's own event handlers.
110
111 get_runstate
112 get_runstate() returns the machine's current runstate. Runstates are
113 equivalent to POE::Session HEAPs, so this method does pretty much the
114 same as POE::Session's get_heap(). It's easier (and faster) to use
115 $_[RUNSTATE] in a machine's own event handlers, however.
116
117 spawn STATE_NAME => HANDLERS_HASHREF[, ...]
118 spawn() is POE::NFA's constructor. The name reflects the idea that new
119 state machines are spawned like threads or processes rather than
120 instantiated like objects.
121
122 The machine itself is defined as a list of state names and hashes that
123 map events to handlers within each state.
124
125 my %states = (
126 state_1 => {
127 event_1 => \&handler_1,
128 event_2 => \&handler_2,
129 },
130 state_2 => {
131 event_1 => \&handler_3,
132 event_2 => \&handler_4,
133 },
134 );
135
136 A single event may be handled by many states. The proper handler will
137 be called depending on the machine's current state. For example, if
138 "event_1" is dispatched while the machine is in "state_2", then
139 handler_3() will be called to handle the event. The state -> event ->
140 handler map looks like this:
141
142 $machine{state_2}{event_1} = \&handler_3;
143
144 Instead of "inline_states", "object_states" or "package_states" may be
145 used. These map the events of a state to an object or package method
146 respectively.
147
148 object_states => {
149 state_1 => [
150 $object_1 => [qw(event_1 event_2)],
151 ],
152 state_2 => [
153 $object_2 => {
154 event_1 => method_1,
155 event_2 => method_2,
156 }
157 ]
158 }
159
160 In the example above, in the case of "event_1" coming in while the
161 machine is in "state_1", method "event_1" will be called on $object_1.
162 If the machine is in "state_2", method "method_1" will be called on
163 $object_2.
164
165 "package_states" is very similar, but instead of using an $object, you
166 pass in a "Package::Name"
167
168 The "runstate" parameter allows "RUNSTATE" to be initialized
169 differently at instantiation time. "RUNSTATE", like heaps, are usually
170 anonymous hashrefs, but "runstate" may set them to be array references
171 or even objects.
172
173 State transitions are not necessarily executed immediately by default.
174 Rather, they are placed in POEs event queue behind any currently
175 pending events. Enabling the "immediate" option causes state
176 transitions to occur immediately, regardless of any queued events.
177
178 goto_state NEW_STATE[, ENTRY_EVENT[, EVENT_ARGS]]
179 goto_state() puts the machine into a new state. If an ENTRY_EVENT is
180 specified, then that event will be dispatched after the machine enters
181 the new state. EVENT_ARGS, if included, will be passed to the entry
182 event's handler via "ARG0..$#_".
183
184 # Switch to the next state.
185 $_[MACHINE]->goto_state( 'next_state' );
186
187 # Switch to the next state, and call a specific entry point.
188 $_[MACHINE]->goto_state( 'next_state', 'entry_event' );
189
190 # Switch to the next state; call an entry point with some values.
191 $_[MACHINE]->goto_state( 'next_state', 'entry_event', @parameters );
192
193 stop
194 stop() forces a machine to stop. The machine will also stop gracefully
195 if it runs out of things to do, just like POE::Session.
196
197 stop() is heavy-handed. It will force resources to be cleaned up.
198 However, circular references in the machine's "RUNSTATE" are not POE's
199 responsibility and may cause memory leaks.
200
201 $_[MACHINE]->stop();
202
203 call_state RETURN_EVENT, NEW_STATE[, ENTRY_EVENT[, EVENT_ARGS]]
204 call_state() is similar to goto_state(), but it pushes the current
205 state on a stack. At some later point, a handler can call
206 return_state() to pop the call stack and return the machine to its old
207 state. At that point, a "RETURN_EVENT" will be posted to notify the
208 old state of the return.
209
210 $machine->call_state( 'return_here', 'new_state', 'entry_event' );
211
212 As with goto_state(), "ENTRY_EVENT" is the event that will be emitted
213 once the machine enters its new state. "ENTRY_ARGS" are parameters
214 passed to the "ENTRY_EVENT" handler via "ARG0..$#_".
215
216 return_state [RETURN_ARGS]
217 return_state() returns to the most recent state in which call_state()
218 was invoked. If the preceding call_state() included a return event
219 then its handler will be invoked along with some optional
220 "RETURN_ARGS". The "RETURN_ARGS" will be passed to the return handler
221 via "ARG0..$#_".
222
223 $_[MACHINE]->return_state( 'success', @success_values );
224
225 Methods that match POE::Session
226 The following methods behave identically to the ones in POE::Session.
227
228 ID
229 option
230 postback
231 callback
232
233 About new() and create()
234 POE::NFA's constructor is spawn(), not new() or create().
235
237 POE::NFA's predefined event fields are the same as POE::Session's with
238 the following three exceptions.
239
240 MACHINE
241 "MACHINE" is equivalent to Session's "SESSION" field. It holds a
242 reference to the current state machine, and is useful for calling its
243 methods.
244
245 See POE::Session's "SESSION" field for more information.
246
247 $_[MACHINE]->goto_state( $next_state, $next_state_entry_event );
248
249 RUNSTATE
250 "RUNSTATE" is equivalent to Session's "HEAP" field. It holds an
251 anonymous hash reference which POE is guaranteed not to touch. Data
252 stored in "RUNSTATE" will persist between handler invocations.
253
254 STATE
255 "STATE" contains the name of the machine's current state. It is not
256 equivalent to anything from POE::Session.
257
258 EVENT
259 "EVENT" is equivalent to Session's "STATE" field. It holds the name of
260 the event which invoked the current handler. See POE::Session's
261 "STATE" field for more information.
262
264 POE::NFA defines four events of its own. These events are used
265 internally and may not be overridden by application code.
266
267 See POE::Session's "PREDEFINED EVENT NAMES" section for more
268 information about other predefined events.
269
270 The events are: "poe_nfa_goto_state", "poe_nfa_push_state",
271 "poe_nfa_pop_state", "poe_nfa_stop".
272
273 Yes, all the internal events begin with "poe_nfa_". More may be
274 forthcoming, but they will always begin the same way. Therefore please
275 do not define events beginning with "poe_nfa_".
276
278 Many of POE::NFA's features are taken directly from POE::Session.
279 Please see POE::Session for more information.
280
281 The SEE ALSO section in POE contains a table of contents covering the
282 entire POE distribution.
283
285 See POE::Session's documentation.
286
287 POE::NFA is not as feature-complete as POE::Session. Your feedback is
288 appreciated.
289
291 Please see POE for more information about authors and contributors.
292
293
294
295perl v5.38.0 2023-07-21 POE::NFA(3)