File Coverage

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


line stmt bran cond sub pod time code
1             #
2             # RCS ID
3             # $Id: Statemap.pm,v 1.3 2008/02/07 16:54:51 fperrad Exp $
4             #
5              
6 1     1   6645 use strict;
  1         1  
  1         35  
7 1     1   5 use warnings;
  1         2  
  1         43  
8              
9             package DFA::Statemap;
10              
11 1     1   4 use vars qw($VERSION);
  1         5  
  1         180  
12             $VERSION = '1.00';
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   4 use Carp;
  1         2  
  1         1112  
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
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           $self->{_state} = undef;
108 0           $self->{_previous_state} = undef;
109 0           $self->{_state_stack} = [];
110 0           $self->{_transition} = undef;
111 0           $self->{_debug_flag} = undef;
112 0           $self->{_debug_stream} = \*STDERR;
113 0           return $self
114             }
115              
116             =head2 getDebugFlag
117              
118             Returns the debug flag's current setting.
119              
120             =cut
121              
122             sub getDebugFlag {
123 0     0     my $self = shift;
124 0           return $self->{_debug_flag};
125             }
126              
127             =head2 setDebugFlag
128              
129             Sets the debug flag.
130             A true value means debugging is on and false means off.
131              
132             =cut
133              
134             sub setDebugFlag {
135 0     0     my $self = shift;
136 0           my ($flag) = @_;
137 0           $self->{_debug_flag} = $flag;
138             }
139              
140             =head2 getDebugStream
141              
142             Returns the stream to which debug output is written.
143              
144             =cut
145              
146             sub getDebugStream {
147 0     0     my $self = shift;
148 0           return $self->{_debug_stream};
149             }
150              
151             =head2 setDebugStream
152              
153             Sets the debug output stream.
154              
155             =cut
156              
157             sub setDebugStream {
158 0     0     my $self = shift;
159 0           my ($stream) = @_;
160 0           $self->{_debug_stream} = $stream;
161             }
162              
163             =head2 getState
164              
165             Returns the current state.
166              
167             =cut
168              
169             sub getState {
170 0     0     my $self = shift;
171 0 0         confess "StateUndefinedException\n"
172             unless (defined $self->{_state});
173 0           return $self->{_state};
174             }
175              
176             =head2 isInTransition
177              
178             Is this state machine already inside a transition?
179              
180             True if state is undefined.
181              
182             =cut
183              
184             sub isInTransition {
185 0     0     my $self = shift;
186 0           return !defined($self->{_state});
187             }
188              
189             =head2 getTransition
190              
191             Returns the current transition's name.
192              
193             Used only for debugging purposes.
194              
195             =cut
196              
197             sub getTransition {
198 0     0     my $self = shift;
199 0           return $self->{_transition};
200             }
201              
202             =head2 clearState
203              
204             Clears the current state.
205              
206             =cut
207              
208             sub clearState {
209 0     0     my $self = shift;
210 0           $self->{_previous_state} = $self->{_state};
211 0           $self->{_state} = undef;
212             }
213              
214             =head2 getPreviousState
215              
216             Returns the state which a transition left.
217              
218             May be B.
219              
220             =cut
221              
222             sub getPreviousState {
223 0     0     my $self = shift;
224 0           return $self->{_previous_state};
225             }
226              
227             =head2 setState
228              
229             Sets the current state to the specified state.
230              
231             =cut
232              
233             sub setState {
234 0     0     my $self = shift;
235 0           my ($state) = @_;
236 0 0         if ($self->{_debug_flag}) {
237 0 0         confess "undefined state.\n"
238             unless (defined $state);
239 0 0 0       confess "$state is not a Statemap::State.\n"
240             unless (ref $state and $state->isa('DFA::Statemap::State'));
241             }
242             else {
243 0 0         croak "undefined state.\n"
244             unless (defined $state);
245 0 0 0       croak "$state is not a Statemap::State.\n"
246             unless (ref $state and $state->isa('DFA::Statemap::State'));
247             }
248 0           $self->{_state} = $state;
249 0 0         if ($self->{_debug_flag}) {
250 0           my $fh = $self->{_debug_stream};
251 0           print $fh "NEW STATE : ", $self->{_state}->getName(), "\n";
252             }
253             }
254              
255             =head2 isStateStackEmpty
256              
257             Returns true if the state stack is empty and false otherwise.
258              
259             =cut
260              
261             sub isStateStackEmpty {
262 0     0     my $self = shift;
263 0           return scalar(@{$self->{_state_stack}}) == 0;
  0            
264             }
265              
266             =head2 getStateStackDepth
267              
268             Returns the state stack's depth.
269              
270             =cut
271              
272             sub getStateStackDepth {
273 0     0     my $self = shift;
274 0           return scalar(@{$self->{_state_stack}});
  0            
275             }
276              
277             =head2 pushState
278              
279             Push the current state on top of the state stack
280             and make the specified state the current state.
281              
282             =cut
283              
284             sub pushState {
285 0     0     my $self = shift;
286 0           my ($state) = @_;
287 0 0         if ($self->{_debug_flag}) {
288 0 0         confess "undefined state\n"
289             unless (defined $state);
290 0 0 0       confess "$state is not a State\n"
291             unless (ref $state and $state->isa('DFA::Statemap::State'));
292             }
293             else {
294 0 0         croak "undefined state\n"
295             unless (defined $state);
296 0 0 0       croak "$state is not a State\n"
297             unless (ref $state and $state->isa('DFA::Statemap::State'));
298             }
299 0 0         if (defined $self->{_state}) {
300 0           push @{$self->{_state_stack}}, $self->{_state};
  0            
301             }
302 0           $self->{_state} = $state;
303 0 0         if ($self->{_debug_flag}) {
304 0           my $fh = $self->{_debug_stream};
305 0           print $fh "PUSH TO STATE: ", $self->{_state}->getName(), "\n";
306             }
307             }
308              
309             =head2 popState
310              
311             Make the state on top of the state stack the current state.
312              
313             =cut
314              
315             sub popState {
316 0     0     my $self = shift;
317 0 0         if (scalar(@{$self->{_state_stack}}) == 0) {
  0            
318 0 0         if ($self->{_debug_flag}) {
319 0           my $fh = $self->{_debug_stream};
320 0           print $fh "POPPING ON EMPTY STATE STACK.\n";
321 0           confess "empty state stack.\n"
322             }
323             else {
324 0           croak "empty state stack.\n"
325             }
326             }
327             else {
328 0           $self->{_state} = pop @{$self->{_state_stack}};
  0            
329 0 0         if ($self->{_debug_flag}) {
330 0           my $fh = $self->{_debug_stream};
331 0           print $fh "POP TO STATE : ", $self->{_state}->getName(), "\n";
332             }
333             }
334             }
335              
336             =head2 emptyStateStack
337              
338             Remove all states from the state stack.
339              
340             =cut
341              
342             sub emptyStateStack {
343 0     0     my $self = shift;
344 0           $self->{_state_stack} = [];
345             }
346              
347             =head1 LICENSE
348              
349             The contents of this file are subject to the Mozilla Public
350             License Version 1.1 (the "License"); you may not use this file
351             except in compliance with the License. You may obtain a copy of
352             the License at http://www.mozilla.org/MPL/
353              
354             Software distributed under the License is distributed on an "AS
355             IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
356             implied. See the License for the specific language governing
357             rights and limitations under the License.
358              
359             =head1 AUTHORS
360              
361             The Original Code is State Machine Compiler (SMC).
362              
363             The Initial Developer of the Original Code is Charles W. Rapp.
364              
365             Port to Perl by Francois Perrad, francois.perrad@gadz.org
366              
367             Copyright 2004-2008, Francois Perrad.
368             All Rights Reserved.
369              
370             Contributor(s):
371              
372             =head1 HISTORY
373              
374             This module was previously named StateMachine::Statemap.
375              
376             =head1 SEE ALSO
377              
378             L
379              
380             =cut