File Coverage

blib/lib/OpenGL/QEng/Parser.pm
Criterion Covered Total %
statement 6 148 4.0
branch 0 70 0.0
condition 0 16 0.0
subroutine 2 35 5.7
pod 0 17 0.0
total 8 286 2.8


line stmt bran cond sub pod time code
1             ### $Id: Parser.pm 424 2008-08-19 16:27:43Z duncan $
2             ####------------------------------------------
3              
4             ## @file
5             # Define Parser for Quests map language
6             #
7             ## @class Parser
8             # Parse map and game state files
9             #
10              
11              
12             package OpenGL::QEng::Parser;
13              
14 2     2   13 use base Exporter;
  2         2  
  2         940  
15             @EXPORT_OK = qw(records tokens make_lexer
16             head tail hpop iterator_to_stream
17             nothing End_of_Input lookfor
18             alternate concatenate star list_of
19             T two_part
20             );
21             %EXPORT_TAGS = ('all' => \@EXPORT_OK);
22              
23             #------------------------------------------------------------
24             sub records {
25 0     0 0   my ($input,$terminator) = @_;
26 0 0         $terminator = quotemeta($/) unless defined $terminator;
27              
28 0           my @records;
29 0           my @newrecs = split /$terminator/, $input;
30             # use split /($terminator)/ to keep terminators
31              
32 0           my $fullr;
33 0           while (@newrecs) {
34 0           my $rec = shift @newrecs;
35 0 0         next if (substr($rec,0,1) eq '#');
36 0 0         next if ($rec =~ /^\s*$/);
37              
38 0           while (substr($rec,-1,1) eq '\\') { # combine broken records
39 0           chop $rec;
40 0 0         if (my $r = shift @newrecs) {
41 0 0         $r = '\\' if (substr($r,0,1) eq '#');
42 0           $rec .= $r;
43             }
44             }
45 0           $fullr .= $rec.' ';
46             }
47 0           push @records, $fullr;
48 0 0   0     sub { if (@records) {shift(@records)} else {return undef} };
  0            
  0            
  0            
49             }
50              
51             #------------------------------------------------------------
52             sub tokens {
53 0     0 0   my ($input,$label,$pattern,$maketoken) = @_;
54 0   0 0     $maketoken ||= sub { [$_[1], $_[0]] };
  0            
55 0           my @tokens;
56 0           my $buf = '';
57 0     0     my $split = sub { split /($pattern)/, $_[0] };
  0            
58             sub {
59 0   0 0     while (@tokens == 0 && defined $buf) {
60 0           my $i = $input->();
61 0 0         if (ref $i) {
62 0           my ($sep, $tok) = $split->($buf);
63 0 0         $tok = $maketoken->($tok,$label) if defined $tok;
64             {
65 2     2   11 no warnings 'uninitialized';
  2         2  
  2         2623  
  0            
66 0           push @tokens, grep $_ ne '', $sep, $tok, $i;
67             }
68 0           $buf = '';
69 0           last;
70             }
71 0 0         $buf .= $i if defined $i;
72 0           my @newtoks = $split->($buf);
73 0   0       while (@newtoks > 2 || @newtoks && !defined $i) {
      0        
74 0           push @tokens, shift(@newtoks);
75 0 0         push @tokens, $maketoken->(shift(@newtoks), $label) if @newtoks;
76             }
77 0           $buf = join '', @newtoks;
78 0 0         undef $buf if !defined $i;
79 0           @tokens = grep $_ ne '', @tokens;
80             }
81 0           shift @tokens;
82 0           };
83             }
84              
85             #------------------------------------------------------------
86             sub make_lexer {
87 0     0 0   my $lexer = shift;
88 0           while (@_) {
89 0           my $args = shift;
90 0           $lexer = tokens($lexer, @$args);
91             }
92 0           $lexer;
93             }
94              
95             #------------------------------------------------------------
96             sub tail {
97 0 0   0 0   if (ref($_[0][1]) eq 'CODE') {
98 0           $_[0][1] = $_[0][1]->();
99             }
100 0           $_[0][1];
101             }
102              
103             #------------------------------------------------------------
104             sub head {
105 0     0 0   $_[0][0];
106             }
107             #------------------------------------------------------------
108             sub hpop {
109 0     0 0   my $h = head($_[0]);
110 0           $_[0] = tail($_[0]);
111 0           $h;
112             }
113              
114             #------------------------------------------------------------
115             sub iterator_to_stream {
116 0     0 0   my ($it) = @_;
117 0           my $v = $it->();
118 0 0         return unless defined $v;
119 0     0     [$v, sub {iterator_to_stream($it)}];
  0            
120             }
121              
122             #------------------------------------------------------------
123             sub nothing {
124 0     0 0   my $input = shift;
125 0           return (undef, $input);
126             }
127              
128             #------------------------------------------------------------
129             sub End_of_Input {
130 0     0 0   my $input = shift;
131 0 0         defined($input) ? () : (undef, undef);
132             }
133              
134             #------------------------------------------------------------
135             sub aref_str {
136 0     0 0   my ($aref) = @_;
137 0 0 0       (defined $aref && ref($aref) eq 'ARRAY')
138             ? join ',', @$aref
139             : '';
140             }
141              
142             #------------------------------------------------------------
143             sub lookfor {
144 0     0 0   my $wanted = shift;
145 0   0 0     my $value = shift || sub { $_[0][1] };
  0            
146 0           my $u = shift;
147 0 0         $wanted = [$wanted] unless ref $wanted;
148             sub {
149 0     0     my $input = shift;
150 0 0         return unless defined $input;
151 0           my $next = head($input);
152 0           for my $i (0 .. $#$wanted) {
153 0 0         next unless defined $wanted->[$i];
154 0 0         return unless $wanted->[$i] eq $next->[$i];
155             }
156 0           my $wanted_value = $value->($next, $u);
157 0 0         print STDERR "lf: got $wanted_value\n" if defined $ENV{DEBUG_TOKEN};
158 0           return ($wanted_value, tail($input));
159 0           };
160             }
161              
162             #------------------------------------------------------------
163             sub concatenate {
164 0     0 0   my @p = @_;
165 0 0         return \¬hing if @p == 0;
166 0 0         return $p[0] if @p == 1;
167             sub {
168 0     0     my $input = shift;
169 0           my $v;
170             my @values;
171 0           for (@p) {
172 0           $i++;
173 0 0         if (($v, $input) = $_->($input)) {
174 0           push @values, $v;
175             } else {
176 0           return;
177             }
178             }
179 0           return (\@values, $input);
180 0           };
181             }
182              
183             #------------------------------------------------------------
184             sub alternate {
185 0     0 0   my @p = @_;
186 0 0   0     return sub { return () } if @p == 0;
  0            
187 0 0         return $p[0] if @p == 1;
188             sub {
189 0     0     my $input = shift;
190 0           my ($v, $newinput);
191 0           for (@p) {
192 0 0         if (($v, $newinput) = $_->($input)) {
193 0           return ($v, $newinput);
194             }
195             }
196 0           return;
197 0           };
198             }
199              
200             #------------------------------------------------------------
201             sub two_part {
202 0     0 0   my ($p0,$p1) = @_;
203 0 0   0     return sub { return () } unless @_ == 2;
  0            
204             sub {
205 0     0     my $input = shift;
206 0           my ($v0, $ni0, $v1, $ni1);
207              
208 0 0         if (($v0, $ni0) = $p0->($input)) {
209 0 0         if (($v1, $ni1) = $p1->($ni0)) {
210 0           return ([$v0,$v1], $ni1);
211             }
212             }
213 0           return;
214 0           };
215             }
216              
217             #------------------------------------------------------------
218             sub star {
219 0     0 0   my $p = shift;
220 0           my $p_star;
221 0     0     $p_star = T(alternate(T(concatenate($p, sub { $p_star->(@_) }),
  0            
222 0 0         sub{my ($f,$r) = @_; defined $r ? [$f,@$r] : [$f]},),
223             #sub{[@_]},),
224             \¬hing),
225             sub{
226             #use Data::Dumper;
227             #print STDERR "star() returning :",(map{Dumper($_).' '} @_),"\n";
228 0     0     [@_];
229 0           } );
230             }
231              
232             #------------------------------------------------------------
233             sub list_of {
234 0     0 0   my ($element, $separator) = @_;
235 0 0         $separator = lookfor('COMMA') unless defined $separator;
236             T(concatenate(star(two_part($element, $separator)),
237             alternate(concatenate($element, \¬hing), \¬hing)),
238             sub{
239 0 0   0     return [@_] unless defined $_[0];
240 0           my @out;
241 0 0         if (ref($_[0]) eq 'ARRAY') {
242 0           @out = @{$_[0]};
  0            
243             } else {
244 0           push @out, $_[0];
245             }
246 0 0         push @out, $_[1] if defined $_[1];
247 0           [@out];
248 0           });
249             }
250              
251             #------------------------------------------------------------
252             sub T {
253 0     0 0   my ($parser, $transform) = @_;
254             return sub {
255 0     0     my $input = shift;
256 0 0         if (my ($value, $newinput) = $parser->($input)) {
257 0           $value = $transform->(@$value);
258 0           return ($value, $newinput);
259             } else {
260 0           return;
261             }
262 0           };
263             }
264              
265             #-----------------------------------------------------------------------------
266             1;
267              
268             __END__