File Coverage

blib/lib/DFA/Statemap.pm
Criterion Covered Total %
statement 12 104 11.5
branch 0 34 0.0
condition 0 18 0.0
subroutine 4 23 17.3
pod n/a
total 16 179 8.9


line stmt bran cond sub pod time code
1             #
2             # RCS ID
3             # Id: Statemap.pm,v 1.5 2009/11/24 20:42:39 cwrapp Exp
4             #
5              
6 1     1   3602 use strict;
  1         1  
  1         24  
7 1     1   3 use warnings;
  1         1  
  1         29  
8              
9             package DFA::Statemap;
10              
11 1     1   3 use vars qw($VERSION);
  1         2  
  1         135  
12             $VERSION = '1.01';
13              
14             =head1 NAME
15              
16             DFA::Statemap
17              
18             =head1 DESCRIPTION
19              
20             This is the SMC (State Machine Compiler) runtime for target language Perl.
21              
22             See L.
23              
24             This namespace contains two class :
25              
26             =over 8
27              
28             =item State
29              
30             the base State class
31              
32             =item FSMContext
33              
34             the Finite State Machine Context class
35              
36             =back
37              
38             =cut
39              
40             package DFA::Statemap::State;
41              
42             =head1 DFA::Statemap::State
43              
44             =head2 new
45              
46             Constructor.
47              
48             =cut
49              
50             sub new {
51 0     0     my $proto = shift;
52 0   0       my $class = ref($proto) || $proto;
53 0           my ($name, $id) = @_;
54 0           my $self = {};
55 0           bless($self, $class);
56 0           $self->{_name} = $name;
57 0           $self->{_id} = $id;
58 0           return $self
59             }
60              
61             =head2 getName
62              
63             Returns the state's printable name.
64              
65             =cut
66              
67             sub getName {
68 0     0     my $self = shift;
69 0           return $self->{_name};
70             }
71              
72             =head2 getId
73              
74             Returns the state's unique identifier.
75              
76             =cut
77              
78             sub getId {
79 0     0     my $self = shift;
80 0           return $self->{_id};
81             }
82              
83             package DFA::Statemap::FSMContext;
84              
85 1     1   3 use Carp;
  1         1  
  1         746  
86              
87             =head1 DFA::Statemap::FSMContext
88              
89             The user can derive FSM contexts from this class and interface
90             to them with the methods of this class.
91              
92             The finite state machine needs to be initialized to the starting
93             state of the FSM. This must be done manually in the constructor
94             of the derived class.
95              
96             =head2 new ( $init_state )
97              
98             Default constructor.
99              
100             =cut
101              
102             sub new {
103 0     0     my $proto = shift;
104 0   0       my $class = ref($proto) || $proto;
105 0           my $self = {};
106 0           bless($self, $class);
107 0           my ($init_state) = @_;
108 0           $self->{_state} = $init_state;
109 0           $self->{_previous_state} = undef;
110 0           $self->{_state_stack} = [];
111 0           $self->{_transition} = undef;
112 0           $self->{_debug_flag} = undef;
113 0           $self->{_debug_stream} = \*STDERR;
114 0           return $self
115             }
116              
117             =head2 getDebugFlag
118              
119             Returns the debug flag's current setting.
120              
121             =cut
122              
123             sub getDebugFlag {
124 0     0     my $self = shift;
125 0           return $self->{_debug_flag};
126             }
127              
128             =head2 setDebugFlag
129              
130             Sets the debug flag.
131             A true value means debugging is on and false means off.
132              
133             =cut
134              
135             sub setDebugFlag {
136 0     0     my $self = shift;
137 0           my ($flag) = @_;
138 0           $self->{_debug_flag} = $flag;
139             }
140              
141             =head2 getDebugStream
142              
143             Returns the stream to which debug output is written.
144              
145             =cut
146              
147             sub getDebugStream {
148 0     0     my $self = shift;
149 0           return $self->{_debug_stream};
150             }
151              
152             =head2 setDebugStream
153              
154             Sets the debug output stream.
155              
156             =cut
157              
158             sub setDebugStream {
159 0     0     my $self = shift;
160 0           my ($stream) = @_;
161 0           $self->{_debug_stream} = $stream;
162             }
163              
164             =head2 getState
165              
166             Returns the current state.
167              
168             =cut
169              
170             sub getState {
171 0     0     my $self = shift;
172             confess "StateUndefinedException\n"
173 0 0         unless (defined $self->{_state});
174 0           return $self->{_state};
175             }
176              
177             =head2 isInTransition
178              
179             Is this state machine already inside a transition?
180              
181             True if state is undefined.
182              
183             =cut
184              
185             sub isInTransition {
186 0     0     my $self = shift;
187 0           return !defined($self->{_state});
188             }
189              
190             =head2 getTransition
191              
192             Returns the current transition's name.
193              
194             Used only for debugging purposes.
195              
196             =cut
197              
198             sub getTransition {
199 0     0     my $self = shift;
200 0           return $self->{_transition};
201             }
202              
203             =head2 clearState
204              
205             Clears the current state.
206              
207             =cut
208              
209             sub clearState {
210 0     0     my $self = shift;
211 0           $self->{_previous_state} = $self->{_state};
212 0           $self->{_state} = undef;
213             }
214              
215             =head2 getPreviousState
216              
217             Returns the state which a transition left.
218              
219             May be B.
220              
221             =cut
222              
223             sub getPreviousState {
224 0     0     my $self = shift;
225 0           return $self->{_previous_state};
226             }
227              
228             =head2 setState
229              
230             Sets the current state to the specified state.
231              
232             =cut
233              
234             sub setState {
235 0     0     my $self = shift;
236 0           my ($state) = @_;
237 0 0         if ($self->{_debug_flag}) {
238 0 0         confess "undefined state.\n"
239             unless (defined $state);
240 0 0 0       confess "$state is not a Statemap::State.\n"
241             unless (ref $state and $state->isa('DFA::Statemap::State'));
242             }
243             else {
244 0 0         croak "undefined state.\n"
245             unless (defined $state);
246 0 0 0       croak "$state is not a Statemap::State.\n"
247             unless (ref $state and $state->isa('DFA::Statemap::State'));
248             }
249 0           $self->{_state} = $state;
250 0 0         if ($self->{_debug_flag}) {
251 0           my $fh = $self->{_debug_stream};
252 0           print $fh "ENTER STATE : ", $self->{_state}->getName(), "\n";
253             }
254             }
255              
256             =head2 isStateStackEmpty
257              
258             Returns true if the state stack is empty and false otherwise.
259              
260             =cut
261              
262             sub isStateStackEmpty {
263 0     0     my $self = shift;
264 0           return scalar(@{$self->{_state_stack}}) == 0;
  0            
265             }
266              
267             =head2 getStateStackDepth
268              
269             Returns the state stack's depth.
270              
271             =cut
272              
273             sub getStateStackDepth {
274 0     0     my $self = shift;
275 0           return scalar(@{$self->{_state_stack}});
  0            
276             }
277              
278             =head2 pushState
279              
280             Push the current state on top of the state stack
281             and make the specified state the current state.
282              
283             =cut
284              
285             sub pushState {
286 0     0     my $self = shift;
287 0           my ($state) = @_;
288 0 0         if ($self->{_debug_flag}) {
289 0 0         confess "undefined state\n"
290             unless (defined $state);
291 0 0 0       confess "$state is not a State\n"
292             unless (ref $state and $state->isa('DFA::Statemap::State'));
293             }
294             else {
295 0 0         croak "undefined state\n"
296             unless (defined $state);
297 0 0 0       croak "$state is not a State\n"
298             unless (ref $state and $state->isa('DFA::Statemap::State'));
299             }
300 0 0         if (defined $self->{_state}) {
301 0           push @{$self->{_state_stack}}, $self->{_state};
  0            
302             }
303 0           $self->{_state} = $state;
304 0 0         if ($self->{_debug_flag}) {
305 0           my $fh = $self->{_debug_stream};
306 0           print $fh "PUSH TO STATE : ", $self->{_state}->getName(), "\n";
307             }
308             }
309              
310             =head2 popState
311              
312             Make the state on top of the state stack the current state.
313              
314             =cut
315              
316             sub popState {
317 0     0     my $self = shift;
318 0 0         if (scalar(@{$self->{_state_stack}}) == 0) {
  0            
319 0 0         if ($self->{_debug_flag}) {
320 0           my $fh = $self->{_debug_stream};
321 0           print $fh "POPPING ON EMPTY STATE STACK.\n";
322 0           confess "empty state stack.\n"
323             }
324             else {
325 0           croak "empty state stack.\n"
326             }
327             }
328             else {
329 0           $self->{_state} = pop @{$self->{_state_stack}};
  0            
330 0 0         if ($self->{_debug_flag}) {
331 0           my $fh = $self->{_debug_stream};
332 0           print $fh "POP TO STATE : ", $self->{_state}->getName(), "\n";
333             }
334             }
335             }
336              
337             =head2 emptyStateStack
338              
339             Remove all states from the state stack.
340              
341             =cut
342              
343             sub emptyStateStack {
344 0     0     my $self = shift;
345 0           $self->{_state_stack} = [];
346             }
347              
348             =head1 LICENSE
349              
350             The contents of this file are subject to the Mozilla Public
351             License Version 1.1 (the "License"); you may not use this file
352             except in compliance with the License. You may obtain a copy of
353             the License at http://www.mozilla.org/MPL/
354              
355             Software distributed under the License is distributed on an "AS
356             IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
357             implied. See the License for the specific language governing
358             rights and limitations under the License.
359              
360             =head1 AUTHORS
361              
362             The Original Code is State Machine Compiler (SMC).
363              
364             The Initial Developer of the Original Code is Charles W. Rapp.
365              
366             Port to Perl by Francois Perrad, francois.perrad@gadz.org
367              
368             Copyright 2004-2009, Francois Perrad.
369             All Rights Reserved.
370              
371             Contributor(s):
372              
373             =head1 HISTORY
374              
375             This module was previously named StateMachine::Statemap.
376              
377             =head1 SEE ALSO
378              
379             L
380              
381             =cut