File Coverage

blib/lib/Marpa/PP/Value.pm
Criterion Covered Total %
statement 842 996 84.5
branch 235 354 66.3
condition 65 89 73.0
subroutine 33 39 84.6
pod 1 10 10.0
total 1176 1488 79.0


line stmt bran cond sub pod time code
1             # Copyright 2012 Jeffrey Kegler
2             # This file is part of Marpa::PP. Marpa::PP is free software: you can
3             # redistribute it and/or modify it under the terms of the GNU Lesser
4             # General Public License as published by the Free Software Foundation,
5             # either version 3 of the License, or (at your option) any later version.
6             #
7             # Marpa::PP is distributed in the hope that it will be useful,
8             # but WITHOUT ANY WARRANTY; without even the implied warranty of
9             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10             # Lesser General Public License for more details.
11             #
12             # You should have received a copy of the GNU Lesser
13             # General Public License along with Marpa::PP. If not, see
14             # http://www.gnu.org/licenses/.
15              
16             package Marpa::PP::Value;
17              
18 44     44   1340 use 5.010;
  44         162  
  44         2155  
19 44     44   283 use warnings;
  44         89  
  44         2009  
20 44     44   284 use strict;
  44         105  
  44         1847  
21 44     44   282 use integer;
  44         118  
  44         434  
22              
23 44     44   7326 use vars qw($VERSION $STRING_VERSION);
  44         149  
  44         11092  
24             $VERSION = '0.014000';
25             $STRING_VERSION = $VERSION;
26             {
27             ## no critic (BuiltinFunctions::ProhibitStringyEval)
28             ## no critic (ValuesAndExpressions::RequireConstantVersion)
29             $VERSION = eval $VERSION;
30             }
31              
32             package Marpa::PP::Internal::Value;
33              
34 44     44   333 use English qw( -no_match_vars );
  44         178  
  44         619  
35              
36 44     44   32282 no warnings qw(qw); ## no critic (TestingAndDebugging::ProhibitNoWarnings)
  44         99  
  44         5346  
37              
38             BEGIN {
39 44     44   202 my $structure = <<'END_OF_STRUCTURE';
40              
41             :package=Marpa::PP::Internal::Or_Node
42              
43             ID
44             TAG
45             ITEM
46             RULE_ID
47             POSITION
48             AND_NODE_IDS
49              
50             CYCLE { Can this Or node be part of a cycle? }
51              
52             INITIAL_RANK_REF
53              
54             =LAST_FIELD
55             END_OF_STRUCTURE
56 44         278 Marpa::PP::offset($structure);
57             } ## end BEGIN
58              
59             BEGIN {
60 44     44   112 my $structure = <<'END_OF_STRUCTURE';
61              
62             :package=Marpa::PP::Internal::And_Node
63              
64             ID
65             TAG
66             RULE_ID
67             TOKEN_NAME
68             VALUE_REF
69             VALUE_OPS
70              
71             { Fields before this (except ID)
72             are used in evaluate() }
73              
74             PREDECESSOR_ID
75             CAUSE_ID
76              
77             CAUSE_EARLEME
78              
79             INITIAL_RANK_REF
80             CONSTANT_RANK_REF
81             TOKEN_RANK_REF
82              
83             { These earleme positions will be needed for the callbacks: }
84              
85             START_EARLEME
86             END_EARLEME
87              
88             POSITION { This is only used for diagnostics, but
89             diagnostics are important. }
90              
91             =LAST_FIELD
92              
93             END_OF_STRUCTURE
94 44         201 Marpa::PP::offset($structure);
95             } ## end BEGIN
96              
97             BEGIN {
98 44     44   438 my $structure = <<'END_OF_STRUCTURE';
99              
100             :package=Marpa::PP::Internal::Iteration_Node
101              
102             OR_NODE { The or-node }
103              
104             CHOICES {
105             A list of remaining choices of and-node.
106             The current choice is first in the list.
107             }
108              
109             PARENT { Offset of the parent in the iterations stack }
110              
111             CAUSE_IX { Offset of the cause child, if any }
112             PREDECESSOR_IX { Offset of the predecessor child, if any }
113             { IX value is -1 if IX needs to be recalculated }
114              
115             CHILD_TYPE { Cause or Predecessor }
116              
117             RANK { Current rank }
118             CLEAN { Boolean -- true if rank does not need to
119             be recalculated }
120              
121             END_OF_STRUCTURE
122 44         259 Marpa::PP::offset($structure);
123             } ## end BEGIN
124              
125             BEGIN {
126 44     44   133 my $structure = <<'END_OF_STRUCTURE';
127              
128             :package=Marpa::PP::Internal::Task
129              
130             INITIALIZE
131             POPULATE_OR_NODE
132             POPULATE_DEPTH
133              
134             RANK_ALL
135              
136             ITERATE
137             FIX_TREE
138             STACK_INODE
139              
140             END_OF_STRUCTURE
141 44         217 Marpa::PP::offset($structure);
142             } ## end BEGIN
143              
144             BEGIN {
145 44     44   126 my $structure = <<'END_OF_STRUCTURE';
146              
147             :package=Marpa::PP::Internal::Op
148              
149             :{ These are the valuation-time ops }
150             ARGC
151             CALL
152             CONSTANT_RESULT
153             VIRTUAL_HEAD
154             VIRTUAL_KERNEL
155             VIRTUAL_TAIL
156              
157             END_OF_STRUCTURE
158 44         190 Marpa::PP::offset($structure);
159             } ## end BEGIN
160              
161             BEGIN {
162 44     44   116 my $structure = <<'END_OF_STRUCTURE';
163              
164             :package=Marpa::PP::Internal::Choice
165              
166             { These are the valuation-time ops }
167              
168             AND_NODE
169             RANK { *NOT* a rank ref }
170              
171             END_OF_STRUCTURE
172 44         179 Marpa::PP::offset($structure);
173             } ## end BEGIN
174              
175 44     44   652 use constant SKIP => -1;
  44         94  
  44         3562  
176              
177 44     44   300 use warnings;
  44         123  
  44         137258  
178              
179             # The internal parameter is slightly misnamed -- between
180             # calls it is the count of the *next* parse
181             sub Marpa::PP::Recognizer::parse_count {
182 9     9 0 116 my ($recce) = @_;
183 9         34 return $recce->[Marpa::PP::Internal::Recognizer::PARSE_COUNT] - 1;
184             }
185              
186             sub Marpa::PP::Recognizer::and_node_tag {
187 14066     14066 0 20984 my ( $recce, $and_node ) = @_;
188 14066         22245 my $or_nodes = $recce->[Marpa::PP::Internal::Recognizer::OR_NODES];
189 14066         20654 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
190 14066         18430 my $symbol_hash = $grammar->[Marpa::PP::Internal::Grammar::SYMBOL_HASH];
191 14066         39491 my $recce_c = $recce->[Marpa::PP::Internal::Recognizer::C];
192 14066         22412 my $origin_earleme =
193             $and_node->[Marpa::PP::Internal::And_Node::START_EARLEME];
194 14066         34126 my $current_earleme =
195             $and_node->[Marpa::PP::Internal::And_Node::END_EARLEME];
196 14066         23093 my $middle_earleme =
197             $and_node->[Marpa::PP::Internal::And_Node::CAUSE_EARLEME];
198 14066         24281 my $position = $and_node->[Marpa::PP::Internal::And_Node::POSITION] + 1;
199 14066         51419 my $rule = $and_node->[Marpa::PP::Internal::And_Node::RULE_ID];
200              
201 14066         46428 my $tag = 'R' # perltidy, v20090616 adds trailing whitespace here
202             . $rule . q{:}
203             . $position . q{@}
204             . $origin_earleme . q{-}
205             . $current_earleme;
206 14066         21858 my $cause_id = $and_node->[Marpa::PP::Internal::And_Node::CAUSE_ID];
207              
208 14066 100       27073 if ( defined $cause_id ) {
209 10591         15737 my $cause = $or_nodes->[$cause_id];
210 10591         19998 my $cause_rule = $cause->[Marpa::PP::Internal::Or_Node::RULE_ID];
211 10591         27170 $tag .= 'C' . $cause_rule;
212             }
213             else {
214 3475         7269 my $token_name =
215             $and_node->[Marpa::PP::Internal::And_Node::TOKEN_NAME];
216 3475         7609 my $symbol = $symbol_hash->{$token_name};
217 3475         6941 $tag .= 'S' . $symbol;
218             } ## end else [ if ( defined $cause_id ) ]
219 14066         18309 $tag .= q{@} . $middle_earleme;
220 14066         67851 return $tag;
221             } ## end sub Marpa::PP::Recognizer::and_node_tag
222              
223             sub Marpa::PP::Recognizer::or_node_tag {
224 237     237 0 442 my ( $recce, $or_node ) = @_;
225 237 50       827 die unless defined $or_node;
226 237         599 my $item = $or_node->[Marpa::PP::Internal::Or_Node::ITEM];
227 237         450 my $set = $item->[Marpa::PP::Internal::Earley_Item::SET];
228 237         781 my $origin = $item->[Marpa::PP::Internal::Earley_Item::ORIGIN];
229 237         579 my $rule = $or_node->[Marpa::PP::Internal::Or_Node::RULE_ID];
230 237         416 my $position = $or_node->[Marpa::PP::Internal::Or_Node::POSITION];
231 237         1416 return 'R' . $rule . q{:} . $position . q{@} . $origin . q{-} . $set;
232             } ## end sub Marpa::PP::Recognizer::or_node_tag
233              
234             sub Marpa::PP::Recognizer::show_and_nodes {
235 1     1 0 3 my ($recce) = @_;
236 1         3 my $and_nodes = $recce->[Marpa::PP::Internal::Recognizer::AND_NODES];
237 1         2 my @data = ();
238 1         4 for my $and_node ( @{$and_nodes} ) {
  1         3  
239 23         48 my $desc = $recce->and_node_tag($and_node);
240 23         153 my ( $rule, $position, $origin, $dot, $cause_type, $cause, $middle ) =
241             (
242             $desc =~ m{
243             \A R (\d+) [:] (\d+)
244             [@] (\d+) [-] (\d+) ([SC]) (\d+)
245             [@] (\d+) \z
246             }msx
247             );
248 23 100       135 push @data,
    100          
249             [
250             $origin, $dot, $rule, $position, $middle,
251             ( $cause_type eq 'C' ? $cause : -1 ),
252             ( $cause_type eq 'S' ? $cause : -1 ), $desc
253             ];
254             } ## end for my $and_node ( @{$and_nodes} )
255 23 50 100     53 my @tags = map { $_->[-1] } sort {
  81   100     464  
      100        
      66        
      66        
256 1         5 $a->[0] <=> $b->[0]
257             or $a->[1] <=> $b->[1]
258             or $a->[2] <=> $b->[2]
259             or $a->[3] <=> $b->[3]
260             or $a->[4] <=> $b->[4]
261             or $a->[5] <=> $b->[5]
262             or $a->[6] <=> $b->[6]
263             } @data;
264 1         9 my $result = ( join "\n", @tags ) . "\n";
265 1         21 return $result;
266             } ## end sub Marpa::PP::Recognizer::show_and_nodes
267              
268             sub Marpa::PP::Recognizer::show_or_nodes {
269 1     1 0 14 my ($recce) = @_;
270 1         4 my $or_nodes = $recce->[Marpa::PP::Internal::Recognizer::OR_NODES];
271 1         24 my @data = ();
272 1         2 for my $or_node ( @{$or_nodes} ) {
  1         4  
273 20         38 my $desc = $recce->or_node_tag($or_node);
274 20         88 my @elements =
275             ( $desc =~ /\A R (\d+) [:] (\d+) [@] (\d+) [-] (\d+) \z/msx );
276 20         87 push @data, [ @elements, $desc ];
277             } ## end for my $or_node ( @{$or_nodes} )
278 20 50 100     36 my @tags = map { $_->[-1] } sort {
  59   100     255  
279 1         7 $a->[2] <=> $b->[2]
280             or $a->[3] <=> $b->[3]
281             or $a->[0] <=> $b->[0]
282             or $a->[1] <=> $b->[1]
283             } @data;
284 1         7 my $result = ( join "\n", @tags ) . "\n";
285 1         27 return $result;
286             } ## end sub Marpa::PP::Recognizer::show_or_nodes
287              
288             sub Marpa::PP::brief_iteration_node {
289 0     0 0 0 my ($iteration_node) = @_;
290              
291 0         0 my $or_node =
292             $iteration_node->[Marpa::PP::Internal::Iteration_Node::OR_NODE];
293 0         0 my $or_node_id = $or_node->[Marpa::PP::Internal::Or_Node::ID];
294 0         0 my $and_node_ids = $or_node->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS];
295 0         0 my $text = "o$or_node_id";
296             DESCRIBE_CHOICES: {
297 0 0       0 if ( not defined $and_node_ids ) {
  0         0  
298 0         0 $text .= ' UNPOPULATED';
299 0         0 last DESCRIBE_CHOICES;
300             }
301 0         0 my $choices =
302             $iteration_node->[Marpa::PP::Internal::Iteration_Node::CHOICES];
303 0 0       0 if ( not defined $choices ) {
304 0         0 $text .= ' Choices not initialized';
305 0         0 last DESCRIBE_CHOICES;
306             }
307 0         0 my $choice = $choices->[0];
308 0 0       0 if ( defined $choice ) {
309 0         0 $text
310             .= " [$choice] == a"
311             . $choice->[Marpa::PP::Internal::Choice::AND_NODE]
312             ->[Marpa::PP::Internal::And_Node::ID];
313 0         0 last DESCRIBE_CHOICES;
314             } ## end if ( defined $choice )
315 0         0 $text .= "o$or_node_id has no choices left";
316             } ## end DESCRIBE_CHOICES:
317 0   0     0 my $parent_ix =
318             $iteration_node->[Marpa::PP::Internal::Iteration_Node::PARENT]
319             // q{-};
320 0         0 return "$text; p=$parent_ix";
321             } ## end sub Marpa::PP::brief_iteration_node
322              
323             sub Marpa::PP::show_rank_ref {
324 0     0 0 0 my ($rank_ref) = @_;
325 0 0       0 return 'undef' if not defined $rank_ref;
326 0 0       0 return 'SKIP' if $rank_ref == Marpa::PP::Internal::Value::SKIP;
327 0         0 return ${$rank_ref};
  0         0  
328             } ## end sub Marpa::PP::show_rank_ref
329              
330             sub Marpa::PP::Recognizer::show_iteration_node {
331 0     0 0 0 my ( $recce, $iteration_node, $verbose ) = @_;
332              
333 0         0 my $or_node =
334             $iteration_node->[Marpa::PP::Internal::Iteration_Node::OR_NODE];
335 0         0 my $or_node_id = $or_node->[Marpa::PP::Internal::Or_Node::ID];
336 0         0 my $or_node_tag = $or_node->[Marpa::PP::Internal::Or_Node::TAG];
337 0         0 my $text = "o$or_node_id $or_node_tag; ";
338 0         0 given (
339             $iteration_node->[Marpa::PP::Internal::Iteration_Node::CHILD_TYPE] )
340             {
341 0         0 when (Marpa::PP::Internal::And_Node::CAUSE_ID) {
342 0         0 $text .= 'cause '
343             }
344 0         0 when (Marpa::PP::Internal::And_Node::PREDECESSOR_ID) {
345 0         0 $text .= 'predecessor '
346             }
347 0         0 default {
348 0         0 $text .= '- '
349             }
350             } ## end given
351              
352 0 0 0     0 $text
      0        
      0        
      0        
353             .= 'pr='
354             . (
355             $iteration_node->[Marpa::PP::Internal::Iteration_Node::PREDECESSOR_IX]
356             // q{-} )
357             . q{;c=}
358             . ( $iteration_node->[Marpa::PP::Internal::Iteration_Node::CAUSE_IX]
359             // q{-} )
360             . q{;p=}
361             . ( $iteration_node->[Marpa::PP::Internal::Iteration_Node::PARENT]
362             // q{-} )
363             . q{; rank=}
364             . ( $iteration_node->[Marpa::PP::Internal::Iteration_Node::RANK]
365             // 'undef' )
366             . (
367             $iteration_node->[Marpa::PP::Internal::Iteration_Node::CLEAN]
368             ? q{}
369             : ' (dirty)'
370             ) . "\n";
371              
372 0         0 DESCRIBE_CHOICES: {
373 0         0 my $and_node_ids =
374             $or_node->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS];
375 0 0       0 if ( not defined $and_node_ids ) {
376 0         0 $text .= " UNPOPULATED\n";
377 0         0 last DESCRIBE_CHOICES;
378             }
379 0         0 my $choices =
380             $iteration_node->[Marpa::PP::Internal::Iteration_Node::CHOICES];
381 0 0       0 if ( not defined $choices ) {
382 0         0 $text .= " Choices not initialized\n";
383 0         0 last DESCRIBE_CHOICES;
384             }
385 0 0       0 if ( not scalar @{$choices} ) {
  0         0  
386 0         0 $text .= " has no choices left\n";
387 0         0 last DESCRIBE_CHOICES;
388             }
389 0         0 for my $choice_ix ( 0 .. $#{$choices} ) {
  0         0  
390 0         0 my $choice = $choices->[$choice_ix];
391 0         0 $text .= " o$or_node_id" . '[' . $choice_ix . '] ';
392 0         0 my $and_node = $choice->[Marpa::PP::Internal::Choice::AND_NODE];
393 0         0 my $and_node_tag =
394             $and_node->[Marpa::PP::Internal::And_Node::TAG];
395 0         0 my $and_node_id = $and_node->[Marpa::PP::Internal::And_Node::ID];
396 0         0 $text .= " ::= a$and_node_id $and_node_tag";
397 44     44   442 no integer;
  44         139  
  44         453  
398 0 0       0 if ($verbose) {
399 0         0 $text .= q{; rank=}
400             . $choice->[Marpa::PP::Internal::Choice::RANK];
401             }
402 0         0 $text .= "\n";
403 0 0       0 last CHOICE if not $verbose;
404             } ## end for my $choice_ix ( 0 .. $#{$choices} )
405             } ## end DESCRIBE_CHOICES:
406 0         0 return $text;
407             } ## end sub Marpa::PP::Recognizer::show_iteration_node
408              
409             sub Marpa::PP::Recognizer::show_iteration_stack {
410 0     0 0 0 my ( $recce, $verbose ) = @_;
411 0         0 my $iteration_stack =
412             $recce->[Marpa::PP::Internal::Recognizer::ITERATION_STACK];
413 0         0 my $text = q{};
414 0         0 for my $ix ( 0 .. $#{$iteration_stack} ) {
  0         0  
415 0         0 my $iteration_node = $iteration_stack->[$ix];
416 0         0 $text .= "$ix: "
417             . $recce->show_iteration_node( $iteration_node, $verbose );
418             }
419 0         0 return $text;
420             } ## end sub Marpa::PP::Recognizer::show_iteration_stack
421              
422             package Marpa::PP::Internal::Recognizer;
423             our $DEFAULT_ACTION_VALUE = \undef;
424              
425             package Marpa::PP::Internal::Value;
426              
427             sub Marpa::PP::Internal::Recognizer::set_null_values {
428 185     185   566 my ($recce) = @_;
429 185         375 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
430 185         414 my $trace_values =
431             $recce->[Marpa::PP::Internal::Recognizer::TRACE_VALUES];
432              
433 185         439 my $rules = $grammar->[Marpa::PP::Internal::Grammar::RULES];
434 185         453 my $symbols = $grammar->[Marpa::PP::Internal::Grammar::SYMBOLS];
435 185         362 my $default_null_value =
436             $grammar->[Marpa::PP::Internal::Grammar::DEFAULT_NULL_VALUE];
437              
438 185         331 my $null_values;
439 185         327 $#{$null_values} = $#{$symbols};
  185         1249  
  185         407  
440              
441 185         347 SYMBOL: for my $symbol ( @{$symbols} ) {
  185         521  
442 4296 100       10931 next SYMBOL if not $symbol->[Marpa::PP::Internal::Symbol::NULLING];
443              
444 578         676 my $null_value = undef;
445 578 100       1337 if ( $symbol->[Marpa::PP::Internal::Symbol::NULL_VALUE] ) {
446 18         38 $null_value =
447 18         20 ${ $symbol->[Marpa::PP::Internal::Symbol::NULL_VALUE] };
448             }
449             else {
450 560         706 $null_value = $default_null_value;
451             }
452 578 100       1468 next SYMBOL if not defined $null_value;
453              
454 103         152 my $symbol_id = $symbol->[Marpa::PP::Internal::Symbol::ID];
455 103         183 $null_values->[$symbol_id] = $null_value;
456              
457 103 50       320 if ($trace_values) {
458 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
459             'Setting null value for symbol ',
460             $symbol->[Marpa::PP::Internal::Symbol::NAME],
461             ' to ', Data::Dumper->new( [ \$null_value ] )->Terse(1)->Dump
462             or Marpa::PP::exception('Could not print to trace file');
463             } ## end if ($trace_values)
464              
465             } ## end for my $symbol ( @{$symbols} )
466              
467 185         885 return $null_values;
468              
469             } # set_null_values
470              
471             # Given the grammar and an action name, resolve it to a closure,
472             # or return undef
473             sub Marpa::PP::Internal::Recognizer::resolve_semantics {
474 5304     5304   13836 my ( $recce, $closure_name ) = @_;
475 5304         16382 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
476 5304         6734 my $closures = $recce->[Marpa::PP::Internal::Recognizer::CLOSURES];
477 5304         6783 my $trace_actions =
478             $recce->[Marpa::PP::Internal::Recognizer::TRACE_ACTIONS];
479              
480 5304 50       10508 Marpa::PP::exception(q{Trying to resolve 'undef' as closure name})
481             if not defined $closure_name;
482              
483 5304 100       26872 if ( my $closure = $closures->{$closure_name} ) {
484 3220 50       5797 if ($trace_actions) {
485 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
486             qq{Resolved "$closure_name" to explicit closure\n}
487             or Marpa::PP::exception('Could not print to trace file');
488             }
489              
490 3220         6418 return $closure;
491             } ## end if ( my $closure = $closures->{$closure_name} )
492              
493 2084         2211 my $fully_qualified_name;
494             DETERMINE_FULLY_QUALIFIED_NAME: {
495 2084 100       2200 if ( $closure_name =~ /([:][:])|[']/xms ) {
  2084         8915  
496 219         308 $fully_qualified_name = $closure_name;
497 219         6268 last DETERMINE_FULLY_QUALIFIED_NAME;
498             }
499 1865 100       4287 if (defined(
500             my $actions_package =
501             $grammar->[Marpa::PP::Internal::Grammar::ACTIONS]
502             )
503             )
504             {
505 214         485 $fully_qualified_name = $actions_package . q{::} . $closure_name;
506 214         341 last DETERMINE_FULLY_QUALIFIED_NAME;
507             } ## end if ( defined( my $actions_package = $grammar->[...]))
508              
509 1651 100       3828 if (defined(
510             my $action_object_class =
511             $grammar->[Marpa::PP::Internal::Grammar::ACTION_OBJECT]
512             )
513             )
514             {
515 5         12 $fully_qualified_name =
516             $action_object_class . q{::} . $closure_name;
517             } ## end if ( defined( my $action_object_class = $grammar->[...]))
518             } ## end DETERMINE_FULLY_QUALIFIED_NAME:
519              
520 2084 100       9544 return if not defined $fully_qualified_name;
521              
522 44     44   57597 no strict 'refs';
  44         106  
  44         2865  
523 438         596 my $closure = *{$fully_qualified_name}{'CODE'};
  438         2073  
524 44     44   272 use strict 'refs';
  44         269  
  44         134502  
525              
526 438 50       1092 if ($trace_actions) {
527 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0 0       0  
528             ( $closure ? 'Successful' : 'Failed' )
529             . qq{ resolution of "$closure_name" },
530             'to ', $fully_qualified_name, "\n"
531             or Marpa::PP::exception('Could not print to trace file');
532             } ## end if ($trace_actions)
533              
534 438         1295 return $closure;
535              
536             } ## end sub Marpa::PP::Internal::Recognizer::resolve_semantics
537              
538             sub Marpa::PP::Internal::Recognizer::set_actions {
539 235     235   498 my ($recce) = @_;
540 235         490 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
541              
542 235         3754 my ( $rules, $default_action, ) = @{$grammar}[
  235         740  
543             Marpa::PP::Internal::Grammar::RULES,
544             Marpa::PP::Internal::Grammar::DEFAULT_ACTION,
545             ];
546              
547 235         481 my $evaluator_rules = [];
548              
549 235         357 my $default_action_closure;
550 235 100       760 if ( defined $default_action ) {
551 169         607 $default_action_closure =
552             Marpa::PP::Internal::Recognizer::resolve_semantics( $recce,
553             $default_action );
554 169 50       583 Marpa::PP::exception(
555             "Could not resolve default action named '$default_action'")
556             if not $default_action_closure;
557             } ## end if ( defined $default_action )
558              
559 235         392 RULE: for my $rule ( @{$rules} ) {
  235         650  
560              
561 7666 100       19478 next RULE if not $rule->[Marpa::PP::Internal::Rule::USED];
562              
563 6335         11861 my $rule_id = $rule->[Marpa::PP::Internal::Rule::ID];
564 6335         14148 my $ops = $evaluator_rules->[$rule_id] = [];
565              
566 6335         22800 my $virtual_rhs = $rule->[Marpa::PP::Internal::Rule::VIRTUAL_RHS];
567 6335         8413 my $virtual_lhs = $rule->[Marpa::PP::Internal::Rule::VIRTUAL_LHS];
568              
569 6335 100       24044 if ($virtual_lhs) {
570 1237 100       1423 push @{$ops},
  1237         4051  
571             (
572             $virtual_rhs
573             ? Marpa::PP::Internal::Op::VIRTUAL_KERNEL
574             : Marpa::PP::Internal::Op::VIRTUAL_TAIL
575             ),
576             $rule->[Marpa::PP::Internal::Rule::REAL_SYMBOL_COUNT];
577 1237         4277 next RULE;
578             } ## end if ($virtual_lhs)
579              
580             # If we are here the LHS is real, not virtual
581              
582 5098 100       8513 if ($virtual_rhs) {
  4654 50       11983  
583 444         601 push @{$ops},
  444         1362  
584             Marpa::PP::Internal::Op::VIRTUAL_HEAD,
585             $rule->[Marpa::PP::Internal::Rule::REAL_SYMBOL_COUNT];
586             }
587              
588             # assignment instead of comparison is deliberate
589             elsif ( my $argc =
590             scalar @{ $rule->[Marpa::PP::Internal::Rule::RHS] } )
591             {
592 4654         5216 push @{$ops}, Marpa::PP::Internal::Op::ARGC, $argc;
  4654         11864  
593             }
594              
595 5098 100       24311 if ( my $action = $rule->[Marpa::PP::Internal::Rule::ACTION] ) {
596 3394         6509 my $closure =
597             Marpa::PP::Internal::Recognizer::resolve_semantics( $recce,
598             $action );
599              
600 3394 50       6603 Marpa::PP::exception(qq{Could not resolve action name: "$action"})
601             if not defined $closure;
602 3394         4364 push @{$ops}, Marpa::PP::Internal::Op::CALL, $closure;
  3394         5987  
603 3394         8596 next RULE;
604             } ## end if ( my $action = $rule->[Marpa::PP::Internal::Rule::ACTION...])
605              
606             # Try to resolve the LHS as a closure name,
607             # if it is not internal.
608             # If we can't resolve
609             # the LHS as a closure name, it's not
610             # a fatal error.
611 1704 50       4485 if ( my $action =
612             $rule->[Marpa::PP::Internal::Rule::LHS]
613             ->[Marpa::PP::Internal::Symbol::NAME] )
614             {
615 1704 100 66     7468 if ($action !~ /[\]] \z/xms
616             and defined(
617             my $closure =
618             Marpa::PP::Internal::Recognizer::resolve_semantics(
619             $recce, $action
620             )
621             )
622             )
623             {
624 23         29 push @{$ops}, Marpa::PP::Internal::Op::CALL, $closure;
  23         45  
625 23         58 next RULE;
626             } ## end if ( $action !~ /[\]] \z/xms and defined( my $closure...)[)
627             } ## end if ( my $action = $rule->[Marpa::PP::Internal::Rule::LHS...])
628              
629 1681 100       3148 if ( defined $default_action_closure ) {
630 484         604 push @{$ops}, Marpa::PP::Internal::Op::CALL,
  484         1006  
631             $default_action_closure;
632 484         1250 next RULE;
633             }
634              
635             # If there is no default action specified, the fallback
636             # is to return an undef
637 1197         1171 push @{$ops}, Marpa::PP::Internal::Op::CONSTANT_RESULT,
  1197         2960  
638             $Marpa::PP::Internal::Recognizer::DEFAULT_ACTION_VALUE;
639              
640             } ## end for my $rule ( @{$rules} )
641              
642 235         1328 return $evaluator_rules;
643              
644             } # set_actions
645              
646             # Returns false if no parse
647             sub do_rank_all {
648 22     22   43 my ( $recce, $depth_by_id ) = @_;
649 22         68 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
650 22         50 my $symbols = $grammar->[Marpa::PP::Internal::Grammar::SYMBOLS];
651 22         50 my $rules = $grammar->[Marpa::PP::Internal::Grammar::RULES];
652              
653 22         44 my $cycle_ranking_action =
654             $grammar->[Marpa::PP::Internal::Grammar::CYCLE_RANKING_ACTION];
655 22         29 my $cycle_closure;
656 22 50       68 if ( defined $cycle_ranking_action ) {
657 0         0 $cycle_closure =
658             Marpa::PP::Internal::Recognizer::resolve_semantics( $recce,
659             $cycle_ranking_action );
660 0 0       0 Marpa::PP::exception(
661             "Could not resolve cycle ranking action named '$cycle_ranking_action'"
662             ) if not $cycle_closure;
663             } ## end if ( defined $cycle_ranking_action )
664              
665             # Set up rank closures by symbol
666 22         50 my %ranking_closures_by_symbol = ();
667 22         43 SYMBOL: for my $symbol ( @{$symbols} ) {
  22         64  
668 908         1295 my $ranking_action =
669             $symbol->[Marpa::PP::Internal::Symbol::RANKING_ACTION];
670 908 50       1849 next SYMBOL if not defined $ranking_action;
671 0         0 my $ranking_closure =
672             Marpa::PP::Internal::Recognizer::resolve_semantics( $recce,
673             $ranking_action );
674 0         0 my $symbol_name = $symbol->[Marpa::PP::Internal::Symbol::NAME];
675 0 0       0 Marpa::PP::exception(
676             "Could not resolve ranking action for symbol.\n",
677             qq{ Symbol was "$symbol_name".},
678             qq{ Ranking action was "$ranking_action".}
679             ) if not defined $ranking_closure;
680 0         0 $ranking_closures_by_symbol{$symbol_name} = $ranking_closure;
681             } # end for my $symbol ( @{$symbols} )
682              
683             # Get closure used in ranking, by rule
684 22         64 my @ranking_closures_by_rule = ();
685 22         35 RULE: for my $rule ( @{$rules} ) {
  22         57  
686              
687 1536         2175 my $ranking_action =
688             $rule->[Marpa::PP::Internal::Rule::RANKING_ACTION];
689 1536         1646 my $ranking_closure;
690 1536         1650 my $cycle_rule = $rule->[Marpa::PP::Internal::Rule::CYCLE];
691              
692 1536 50 66     2844 Marpa::PP::exception(
693             "Rule which cycles has an explicit ranking action\n",
694             qq{ The ranking action is "$ranking_action"\n},
695             qq{ To solve this problem,\n},
696             qq{ Rewrite the grammar so that this rule does not cycle\n},
697             qq{ Or eliminate its ranking action.\n}
698             ) if $ranking_action and $cycle_rule;
699              
700 1536 100       2347 if ($ranking_action) {
701 36         95 $ranking_closure =
702             Marpa::PP::Internal::Recognizer::resolve_semantics( $recce,
703             $ranking_action );
704 36 50       236 Marpa::PP::exception(
705             "Ranking closure '$ranking_action' not found")
706             if not defined $ranking_closure;
707             } ## end if ($ranking_action)
708              
709 1536 50       2328 if ($cycle_rule) {
710 0         0 $ranking_closure = $cycle_closure;
711             }
712              
713 1536 100       3292 next RULE if not $ranking_closure;
714              
715             # If the RHS is empty ...
716             # Empty rules are never in cycles -- they are either
717             # unused (because of the CHAF rewrite) or the special
718             # null start rule.
719 36 100       41 if ( not scalar @{ $rule->[Marpa::PP::Internal::Rule::RHS] } ) {
  36         138  
720 16 50       40 Marpa::PP::exception(
721             "Ranking closure '$ranking_action' not found")
722             if not defined $ranking_closure;
723              
724 16         52 $ranking_closures_by_symbol{ $rule
725             ->[Marpa::PP::Internal::Rule::LHS]
726             ->[Marpa::PP::Internal::Symbol::NULL_ALIAS]
727             ->[Marpa::PP::Internal::Symbol::NAME] } =
728             $ranking_closure;
729             } ## end if ( not scalar @{ $rule->[Marpa::PP::Internal::Rule::RHS...]})
730              
731 36 100       201 next RULE if not $rule->[Marpa::PP::Internal::Rule::USED];
732              
733 16         43 $ranking_closures_by_rule[ $rule->[Marpa::PP::Internal::Rule::ID] ] =
734             $ranking_closure;
735              
736             } ## end for my $rule ( @{$rules} )
737              
738 22         62 my $and_nodes = $recce->[Marpa::PP::Internal::Recognizer::AND_NODES];
739 22         40 my $or_nodes = $recce->[Marpa::PP::Internal::Recognizer::OR_NODES];
740              
741 22         53 my @and_node_worklist = ();
742 22         38 AND_NODE: for my $and_node_id ( 0 .. $#{$and_nodes} ) {
  22         76  
743              
744 1118         1697 my $and_node = $and_nodes->[$and_node_id];
745 1118         1882 my $rule_id = $and_node->[Marpa::PP::Internal::And_Node::RULE_ID];
746 1118         1289 my $rule_closure = $ranking_closures_by_rule[$rule_id];
747 1118         1273 my $token_name =
748             $and_node->[Marpa::PP::Internal::And_Node::TOKEN_NAME];
749 1118         1036 my $token_closure;
750 1118 100       1971 if ($token_name) {
751 242         366 $token_closure = $ranking_closures_by_symbol{$token_name};
752             }
753              
754 1118         1071 my $token_rank_ref;
755             my $rule_rank_ref;
756              
757             # It is a feature of the ranking closures that they are always
758             # called once per instance, even if the result is never used.
759             # This sometimes makes for unnecessary calls,
760             # but it makes these closures predictable enough
761             # to allow their use for side effects.
762             EVALUATION:
763 1118         2866 for my $evaluation_data (
764             [ \$token_rank_ref, $token_closure ],
765             [ \$rule_rank_ref, $rule_closure ]
766             )
767             {
768 2236         2596 my ( $rank_ref_ref, $closure ) = @{$evaluation_data};
  2236         3363  
769 2236 100       5812 next EVALUATION if not defined $closure;
770              
771 125         155 my @warnings;
772             my $eval_ok;
773 0         0 my $rank_ref;
774 125         316 DO_EVAL: {
775 125         144 local $Marpa::PP::Internal::CONTEXT =
776             [ 'and-node', $and_node, $recce ];
777             local $SIG{__WARN__} =
778 125     0   882 sub { push @warnings, [ $_[0], ( caller 0 ) ]; };
  0         0  
779 125         196 $eval_ok = eval { $rank_ref = $closure->(); 1; };
  125         381  
  125         1273  
780             } ## end DO_EVAL:
781              
782 125         169 my $fatal_error;
783             CHECK_FOR_ERROR: {
784 125 50 50     514 if ( not $eval_ok or scalar @warnings ) {
  125         482  
785 0   0     0 $fatal_error = $EVAL_ERROR // 'Fatal Error';
786 0         0 last CHECK_FOR_ERROR;
787             }
788 125 50 66     538 if ( defined $rank_ref and not ref $rank_ref ) {
789 0         0 $fatal_error =
790             "Invalid return value from ranking closure: $rank_ref";
791             }
792             } ## end CHECK_FOR_ERROR:
793              
794 125 50       230 if ( defined $fatal_error ) {
795              
796 0         0 Marpa::PP::Internal::code_problems(
797             { fatal_error => $fatal_error,
798             grammar => $grammar,
799             eval_ok => $eval_ok,
800             warnings => \@warnings,
801             where => 'ranking and-node '
802             . $and_node->[Marpa::PP::Internal::And_Node::TAG],
803             }
804             );
805             } ## end if ( defined $fatal_error )
806              
807 125   100     291 ${$rank_ref_ref} = $rank_ref // Marpa::PP::Internal::Value::SKIP;
  125         328  
808              
809             } ## end for my $evaluation_data ( [ \$token_rank_ref, $token_closure...])
810              
811             # Set the token rank if there is a token.
812             # It is zero if there is no token, or
813             # if there is one with no closure.
814             # Note: token can never cause a cycle, but they
815             # can cause an and-node to be skipped.
816 1118 100       2860 if ($token_name) {
817 242   100     822 $and_node->[Marpa::PP::Internal::And_Node::TOKEN_RANK_REF] =
818             $token_rank_ref // \0;
819             }
820              
821             # See if we can set the rank for this node to a constant.
822 1118         1114 my $constant_rank_ref;
823             SET_CONSTANT_RANK: {
824              
825 1118 50 66     1159 if ( defined $token_rank_ref && !ref $token_rank_ref ) {
  1118         2545  
826 0         0 $constant_rank_ref = Marpa::PP::Internal::Value::SKIP;
827 0         0 last SET_CONSTANT_RANK;
828             }
829              
830             # If we have ranking closure for this rule, the rank
831             # is constant:
832             # 0 for a non-final node,
833             # the result of the closure for a final one
834 1118 100       1824 if ( defined $rule_rank_ref ) {
835 45 100       101 $constant_rank_ref =
836             $and_node->[Marpa::PP::Internal::And_Node::VALUE_OPS]
837             ? $rule_rank_ref
838             : \0;
839 45         74 last SET_CONSTANT_RANK;
840             } ## end if ( defined $rule_rank_ref )
841              
842             # It there is a token and no predecessor, the rank
843             # of this rule is a constant:
844             # 0 is there was not token symbol closure
845             # the result of that closure if there was one
846 1073 100 100     2767 if ( $token_name
847             and not defined
848             $and_node->[Marpa::PP::Internal::And_Node::PREDECESSOR_ID] )
849             {
850 150   100     487 $constant_rank_ref = $token_rank_ref // \0;
851             } ## end if ( $token_name and not defined $and_node->[...])
852              
853             } ## end SET_CONSTANT_RANK:
854              
855 1118 100       1910 if ( defined $constant_rank_ref ) {
856 195         331 $and_node->[Marpa::PP::Internal::And_Node::INITIAL_RANK_REF] =
857             $and_node->[Marpa::PP::Internal::And_Node::CONSTANT_RANK_REF]
858             = $constant_rank_ref;
859              
860 195         452 next AND_NODE;
861             } ## end if ( defined $constant_rank_ref )
862              
863             # If we are here there is (so far) no constant rank
864             # so we stack this and-node for depth-sensitive evaluation
865 923         1732 push @and_node_worklist, $and_node_id;
866              
867             } ## end for my $and_node_id ( 0 .. $#{$and_nodes} )
868              
869             # Now go through the and-nodes that require context to be ranked
870             # This loop assumes that all cycles has been taken care of
871             # with constant ranks
872 22         95 AND_NODE: while ( defined( my $and_node_id = pop @and_node_worklist ) ) {
873              
874 44     44   445 no integer;
  44         103  
  44         334  
875              
876 927         7030 my $and_node = $and_nodes->[$and_node_id];
877              
878             # Go to next if we have already ranked this and-node
879             next AND_NODE
880             if defined
881 927 100       1946 $and_node->[Marpa::PP::Internal::And_Node::INITIAL_RANK_REF];
882              
883             # The rank calculated so far from the
884             # children
885 925         1170 my $calculated_rank = 0;
886              
887 925         984 my $is_cycle = 0;
888 925         944 my $is_skip = 0;
889             OR_NODE:
890 925         1295 for my $field (
891             Marpa::PP::Internal::And_Node::PREDECESSOR_ID,
892             Marpa::PP::Internal::And_Node::CAUSE_ID,
893             )
894             {
895 1837         2400 my $or_node_id = $and_node->[$field];
896 1837 100       3836 next OR_NODE if not defined $or_node_id;
897              
898 1097         1483 my $or_node = $or_nodes->[$or_node_id];
899 1097 100       2938 if (defined(
900             my $or_node_initial_rank_ref =
901             $or_node
902             ->[Marpa::PP::Internal::Or_Node::INITIAL_RANK_REF]
903             )
904             )
905             {
906 99 50       218 if ( ref $or_node_initial_rank_ref ) {
907 99         104 $calculated_rank += ${$or_node_initial_rank_ref};
  99         135  
908 99         235 next OR_NODE;
909             }
910              
911             # At this point only possible value is skip
912 0         0 $and_node->[Marpa::PP::Internal::And_Node::INITIAL_RANK_REF] =
913             $and_node
914             ->[Marpa::PP::Internal::And_Node::CONSTANT_RANK_REF] =
915             Marpa::PP::Internal::Value::SKIP;
916              
917 0         0 next AND_NODE;
918             } ## end if ( defined( my $or_node_initial_rank_ref = $or_node...))
919 998         1344 my @ranks = ();
920 998         1231 my @unranked_and_nodes = ();
921 998         2004 CHILD_AND_NODE:
922 998         1049 for my $child_and_node_id (
923             @{ $or_node->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS] } )
924             {
925 1038         1680 my $rank_ref =
926             $and_nodes->[$child_and_node_id]
927             ->[Marpa::PP::Internal::And_Node::INITIAL_RANK_REF];
928 1038 100       1834 if ( not defined $rank_ref ) {
929 2         4 push @unranked_and_nodes, $child_and_node_id;
930              
931 2         6 next CHILD_AND_NODE;
932             }
933              
934             # Right now the only defined scalar value for a rank is
935             # Marpa::PP::Internal::Value::SKIP
936 1036 100       4767 next CHILD_AND_NODE if not ref $rank_ref;
937              
938 933         989 push @ranks, ${$rank_ref};
  933         2596  
939              
940             } ## end for my $child_and_node_id ( @{ $or_node->[...]})
941              
942             # If we have unranked child and nodes, those have to be
943             # ranked first. Schedule the work and move on.
944 998 100       2494 if ( scalar @unranked_and_nodes ) {
945              
946 2         3 push @and_node_worklist, $and_node_id, @unranked_and_nodes;
947 2         18 next AND_NODE;
948             }
949              
950             # If there were no non-skipped and-nodes, the
951             # parent and-node must also be skipped
952 996 100       13044 if ( not scalar @ranks ) {
953 103         271 $or_node->[Marpa::PP::Internal::Or_Node::INITIAL_RANK_REF] =
954             $and_node
955             ->[Marpa::PP::Internal::And_Node::INITIAL_RANK_REF] =
956             $and_node
957             ->[Marpa::PP::Internal::And_Node::CONSTANT_RANK_REF] =
958             Marpa::PP::Internal::Value::SKIP;
959              
960 103         412 next AND_NODE;
961             } ## end if ( not scalar @ranks )
962              
963 893         1717 my $or_calculated_rank = List::Util::max @ranks;
964 893         1972 $or_node->[Marpa::PP::Internal::Or_Node::INITIAL_RANK_REF] =
965             \$or_calculated_rank;
966 893         3207 $calculated_rank += $or_calculated_rank;
967              
968             } ## end for my $field ( ...)
969              
970 820         1248 my $token_rank_ref =
971             $and_node->[Marpa::PP::Internal::And_Node::TOKEN_RANK_REF];
972 820 100       1367 $calculated_rank += defined $token_rank_ref ? ${$token_rank_ref} : 0;
  63         84  
973 820         2882 $and_node->[Marpa::PP::Internal::And_Node::INITIAL_RANK_REF] =
974             \$calculated_rank;
975              
976             } ## end while ( defined( my $and_node_id = pop @and_node_worklist...))
977              
978 22         96 return;
979              
980             } ## end sub do_rank_all
981              
982             # Does not modify stack
983             sub Marpa::PP::Internal::Recognizer::evaluate {
984 2228     2228   4049 my ( $recce, $stack ) = @_;
985 2228         4927 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
986 2228   100     13084 my $trace_values = $recce->[Marpa::PP::Internal::Recognizer::TRACE_VALUES]
987             // 0;
988              
989 2228         5791 my $rules = $grammar->[Marpa::PP::Internal::Grammar::RULES];
990 2228         4660 my $action_object_class =
991             $grammar->[Marpa::PP::Internal::Grammar::ACTION_OBJECT];
992              
993 2228         4472 my $action_object_constructor;
994 2228 100       8018 if ( defined $action_object_class ) {
995 1         3 my $constructor_name = $action_object_class . q{::new};
996 1         3 my $closure =
997             Marpa::PP::Internal::Recognizer::resolve_semantics( $recce,
998             $constructor_name );
999 1 50       8 Marpa::PP::exception(
1000             qq{Could not find constructor "$constructor_name"})
1001             if not defined $closure;
1002 1         2 $action_object_constructor = $closure;
1003             } ## end if ( defined $action_object_class )
1004              
1005 2228         3320 my $action_object;
1006 2228 100       5251 if ($action_object_constructor) {
1007 1         2 my @warnings;
1008             my $eval_ok;
1009 0         0 my $fatal_error;
1010 1         3 DO_EVAL: {
1011 1         10 local $EVAL_ERROR = undef;
1012             local $SIG{__WARN__} = sub {
1013 0     0   0 push @warnings, [ $_[0], ( caller 0 ) ];
1014 1         15 };
1015              
1016 1         3 $eval_ok = eval {
1017 1         7 $action_object =
1018             $action_object_constructor->($action_object_class);
1019 1         7 1;
1020             };
1021 1         9 $fatal_error = $EVAL_ERROR;
1022             } ## end DO_EVAL:
1023              
1024 1 50 33     10 if ( not $eval_ok or @warnings ) {
1025 0         0 Marpa::PP::Internal::code_problems(
1026             { fatal_error => $fatal_error,
1027             grammar => $grammar,
1028             eval_ok => $eval_ok,
1029             warnings => \@warnings,
1030             where => 'constructing action object',
1031             }
1032             );
1033             } ## end if ( not $eval_ok or @warnings )
1034             } ## end if ($action_object_constructor)
1035              
1036 2228   100     9838 $action_object //= {};
1037              
1038 2228         9736 my @evaluation_stack = ();
1039 2228         5407 my @virtual_rule_stack = ();
1040 2228         3253 TREE_NODE: for my $and_node ( reverse @{$stack} ) {
  2228         5590  
1041              
1042 53361 50       124175 if ( $trace_values >= 3 ) {
1043 0         0 for my $i ( reverse 0 .. $#evaluation_stack ) {
1044 0 0       0 printf {$Marpa::PP::Internal::TRACE_FH} 'Stack position %3d:',
  0         0  
1045             $i
1046             or Marpa::PP::exception('print to trace handle failed');
1047 0 0       0 print {$Marpa::PP::Internal::TRACE_FH} q{ },
  0         0  
1048             Data::Dumper->new( [ $evaluation_stack[$i] ] )->Terse(1)
1049             ->Dump
1050             or Marpa::PP::exception('print to trace handle failed');
1051             } ## end for my $i ( reverse 0 .. $#evaluation_stack )
1052             } ## end if ( $trace_values >= 3 )
1053              
1054 53361         149108 my $value_ref = $and_node->[Marpa::PP::Internal::And_Node::VALUE_REF];
1055              
1056 53361 100       129792 if ( defined $value_ref ) {
1057              
1058 22616         38208 push @evaluation_stack, $value_ref;
1059              
1060 22616 100       53097 if ($trace_values) {
1061 14         24 my $token_name =
1062             $and_node->[Marpa::PP::Internal::And_Node::TOKEN_NAME];
1063              
1064 14 50       17 print {$Marpa::PP::Internal::TRACE_FH}
  14 50       105  
1065             'Pushed value from ',
1066             $and_node->[Marpa::PP::Internal::And_Node::TAG], ': ',
1067             ( $token_name ? qq{$token_name = } : q{} ),
1068             Data::Dumper->new( [$value_ref] )->Terse(1)->Dump
1069             or Marpa::PP::exception('print to trace handle failed');
1070             } ## end if ($trace_values)
1071              
1072             } # defined $value_ref
1073              
1074 53361         96882 my $ops = $and_node->[Marpa::PP::Internal::And_Node::VALUE_OPS];
1075              
1076 53361 100       132691 next TREE_NODE if not defined $ops;
1077              
1078 32973         65777 my $current_data = [];
1079 32973         50161 my $op_ix = 0;
1080 32973         41647 while ( $op_ix < scalar @{$ops} ) {
  87754         310901  
1081 54787         99895 given ( $ops->[ $op_ix++ ] ) {
1082              
1083 54787         98666 when (Marpa::PP::Internal::Op::ARGC) {
1084              
1085 20099         37736 my $argc = $ops->[ $op_ix++ ];
1086              
1087 20099 100       42818 if ($trace_values) {
1088 18         27 my $rule_id = $and_node
1089             ->[Marpa::PP::Internal::And_Node::RULE_ID];
1090 18         26 my $rule = $rules->[$rule_id];
1091 18 50       21 say {$Marpa::PP::Internal::TRACE_FH}
  18         69  
1092             'Popping ',
1093             $argc,
1094             ' values to evaluate ',
1095             $and_node->[Marpa::PP::Internal::And_Node::TAG],
1096             ', rule: ', Marpa::PP::brief_rule($rule)
1097             or Marpa::PP::exception(
1098             'Could not print to trace file');
1099             } ## end if ($trace_values)
1100              
1101             $current_data =
1102 20099         68661 [ map { ${$_} }
  28438         45584  
  28438         170854  
1103             ( splice @evaluation_stack, -$argc ) ];
1104              
1105             } ## end when (Marpa::PP::Internal::Op::ARGC)
1106              
1107 34688         74049 when (Marpa::PP::Internal::Op::VIRTUAL_HEAD) {
1108 1715         3964 my $real_symbol_count = $ops->[ $op_ix++ ];
1109              
1110 1715 50       3816 if ($trace_values) {
1111 0         0 my $rule_id = $and_node
1112             ->[Marpa::PP::Internal::And_Node::RULE_ID];
1113 0         0 my $rule = $rules->[$rule_id];
1114 0 0       0 say {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1115             'Head of Virtual Rule: ',
1116             $and_node->[Marpa::PP::Internal::And_Node::TAG],
1117             ', rule: ', Marpa::PP::brief_rule($rule),
1118             "\n",
1119             "Incrementing virtual rule by $real_symbol_count symbols\n",
1120             'Currently ',
1121             ( scalar @virtual_rule_stack ),
1122             ' rules; ', $virtual_rule_stack[-1], ' symbols;',
1123             or Marpa::PP::exception(
1124             'Could not print to trace file');
1125             } ## end if ($trace_values)
1126              
1127 1715         2227 $real_symbol_count += pop @virtual_rule_stack;
1128 13761         31452 $current_data =
1129 1715         26783 [ map { ${$_} }
  13761         13203  
1130             ( splice @evaluation_stack, -$real_symbol_count )
1131             ];
1132              
1133             } ## end when (Marpa::PP::Internal::Op::VIRTUAL_HEAD)
1134              
1135 32973         44621 when (Marpa::PP::Internal::Op::VIRTUAL_KERNEL) {
1136 7222         11005 my $real_symbol_count = $ops->[ $op_ix++ ];
1137 7222         18108 $virtual_rule_stack[-1] += $real_symbol_count;
1138              
1139 7222 50       21381 if ($trace_values) {
1140 0         0 my $rule_id = $and_node
1141             ->[Marpa::PP::Internal::And_Node::RULE_ID];
1142 0         0 my $rule = $rules->[$rule_id];
1143 0 0       0 say {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1144             'Virtual Rule: ',
1145             $and_node->[Marpa::PP::Internal::And_Node::TAG],
1146             ', rule: ', Marpa::PP::brief_rule($rule),
1147             "\nAdding $real_symbol_count",
1148             or Marpa::PP::exception(
1149             'Could not print to trace file');
1150             } ## end if ($trace_values)
1151              
1152             } ## end when (Marpa::PP::Internal::Op::VIRTUAL_KERNEL)
1153              
1154 25751         44091 when (Marpa::PP::Internal::Op::VIRTUAL_TAIL) {
1155 3937         13724 my $real_symbol_count = $ops->[ $op_ix++ ];
1156              
1157 3937 100       8638 if ($trace_values) {
1158 2         4 my $rule_id = $and_node
1159             ->[Marpa::PP::Internal::And_Node::RULE_ID];
1160 2         5 my $rule = $rules->[$rule_id];
1161 2 50       4 say {$Marpa::PP::Internal::TRACE_FH}
  2         11  
1162             'New Virtual Rule: ',
1163             $and_node->[Marpa::PP::Internal::And_Node::TAG],
1164             ', rule: ', Marpa::PP::brief_rule($rule),
1165             "\nReal symbol count is $real_symbol_count",
1166             or Marpa::PP::exception(
1167             'Could not print to trace file');
1168             } ## end if ($trace_values)
1169              
1170 3937         11591 push @virtual_rule_stack, $real_symbol_count;
1171              
1172             } ## end when (Marpa::PP::Internal::Op::VIRTUAL_TAIL)
1173              
1174 21814         30107 when (Marpa::PP::Internal::Op::CONSTANT_RESULT) {
1175 6573         11161 my $result = $ops->[ $op_ix++ ];
1176 6573 50       12877 if ($trace_values) {
1177 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1178             'Constant result: ',
1179             'Pushing 1 value on stack: ',
1180             Data::Dumper->new( [$result] )->Terse(1)->Dump
1181             or Marpa::PP::exception(
1182             'Could not print to trace file');
1183             } ## end if ($trace_values)
1184 6573         14604 push @evaluation_stack, $result;
1185             } ## end when (Marpa::PP::Internal::Op::CONSTANT_RESULT)
1186              
1187 15241         31939 when (Marpa::PP::Internal::Op::CALL) {
1188 15241         27369 my $closure = $ops->[ $op_ix++ ];
1189 15241         36198 my $rule_id =
1190             $and_node->[Marpa::PP::Internal::And_Node::RULE_ID];
1191 15241         33728 my $rule = $rules->[$rule_id];
1192 15241         25764 my $original_rule =
1193             $rule->[Marpa::PP::Internal::Rule::ORIGINAL_RULE];
1194 15241 100       45365 if ( $original_rule
1195             ->[Marpa::PP::Internal::Rule::DISCARD_SEPARATION] )
1196             {
1197 32         105 $current_data = [
1198 241         435 @{$current_data}[
1199 32         82 grep { not $_ % 2 } 0 .. $#{$current_data}
  32         80  
1200             ]
1201             ];
1202             } ## end if ( $original_rule->[...])
1203 15241         20910 my $result;
1204              
1205             my @warnings;
1206 0         0 my $eval_ok;
1207             DO_EVAL: {
1208 15241         26999 local $SIG{__WARN__} = sub {
1209 4     4   108 push @warnings, [ $_[0], ( caller 0 ) ];
1210 15241         135052 };
1211              
1212 15241         53551 $eval_ok = eval {
1213 15241         61967 $result =
1214             $closure->( $action_object,
1215 15241         41838 @{$current_data} );
1216 15237         961417 1;
1217             };
1218              
1219             } ## end DO_EVAL:
1220              
1221 15241 100 100     105306 if ( not $eval_ok or @warnings ) {
1222 6         16 my $fatal_error = $EVAL_ERROR;
1223 6         50 Marpa::PP::Internal::code_problems(
1224             { fatal_error => $fatal_error,
1225             grammar => $grammar,
1226             eval_ok => $eval_ok,
1227             warnings => \@warnings,
1228             where => 'computing value',
1229             long_where => 'Computing value for rule: '
1230             . Marpa::PP::brief_rule($rule),
1231             }
1232             );
1233             } ## end if ( not $eval_ok or @warnings )
1234              
1235 15235 100       51444 if ($trace_values) {
1236 18 50       21 print {$Marpa::PP::Internal::TRACE_FH}
  18         82  
1237             'Calculated and pushed value: ',
1238             Data::Dumper->new( [$result] )->Terse(1)->Dump
1239             or Marpa::PP::exception(
1240             'print to trace handle failed');
1241             } ## end if ($trace_values)
1242              
1243 15235         68272 push @evaluation_stack, \$result;
1244              
1245             } ## end when (Marpa::PP::Internal::Op::CALL)
1246              
1247 0         0 default {
1248 0         0 Marpa::PP::exception("Unknown evaluator Op: $_");
1249             }
1250              
1251             } ## end given
1252             } ## end while ( $op_ix < scalar @{$ops} )
1253              
1254             } # TREE_NODE
1255              
1256 2222         36492 return pop @evaluation_stack;
1257             } ## end sub Marpa::PP::Internal::Recognizer::evaluate
1258              
1259             # null parse is special case
1260             sub Marpa::PP::Internal::Recognizer::do_null_parse {
1261 18     18   35 my ( $recce, $start_rule ) = @_;
1262              
1263 18         37 my $start_symbol = $start_rule->[Marpa::PP::Internal::Rule::LHS];
1264              
1265             # Cannot increment the null parse
1266 18 50       60 return if $recce->[Marpa::PP::Internal::Recognizer::PARSE_COUNT]++;
1267 18         35 my $null_values = $recce->[Marpa::PP::Internal::Recognizer::NULL_VALUES];
1268 18         42 my $evaluator_rules =
1269             $recce->[Marpa::PP::Internal::Recognizer::EVALUATOR_RULES];
1270              
1271 18         32 my $start_symbol_id = $start_symbol->[Marpa::PP::Internal::Symbol::ID];
1272 18         30 my $start_rule_id = $start_rule->[Marpa::PP::Internal::Rule::ID];
1273              
1274 18         38 my $and_node = [];
1275 18         59 $#{$and_node} = Marpa::PP::Internal::And_Node::LAST_FIELD;
  18         82  
1276 18         54 $and_node->[Marpa::PP::Internal::And_Node::VALUE_REF] =
1277             \( $null_values->[$start_symbol_id] );
1278 18         48 $and_node->[Marpa::PP::Internal::And_Node::RULE_ID] =
1279             $start_rule->[Marpa::PP::Internal::Rule::ID];
1280 18         1155 $and_node->[Marpa::PP::Internal::And_Node::VALUE_OPS] =
1281             $evaluator_rules->[$start_rule_id];
1282              
1283 18         47 $and_node->[Marpa::PP::Internal::And_Node::POSITION] = 0;
1284 18         37 $and_node->[Marpa::PP::Internal::And_Node::START_EARLEME] = 0;
1285 18         35 $and_node->[Marpa::PP::Internal::And_Node::CAUSE_EARLEME] = 0;
1286 18         34 $and_node->[Marpa::PP::Internal::And_Node::END_EARLEME] = 0;
1287 18         36 $and_node->[Marpa::PP::Internal::And_Node::ID] = 0;
1288 18         45 my $symbol_name = $start_symbol->[Marpa::PP::Internal::Symbol::NAME];
1289 18         36 $and_node->[Marpa::PP::Internal::And_Node::TOKEN_NAME] = $symbol_name;
1290 18         74 $and_node->[Marpa::PP::Internal::And_Node::TAG] =
1291             Marpa::PP::Recognizer::and_node_tag( $recce, $and_node );
1292              
1293 18         51 $recce->[Marpa::PP::Internal::Recognizer::AND_NODES]->[0] = $and_node;
1294              
1295 18         129 return Marpa::PP::Internal::Recognizer::evaluate( $recce, [$and_node] );
1296              
1297             } ## end sub Marpa::PP::Internal::Recognizer::do_null_parse
1298              
1299             # Returns false if no parse
1300             sub Marpa::PP::Recognizer::value {
1301 2313     2313 1 110219 my ( $recce, @arg_hashes ) = @_;
1302              
1303 2313         7647 my $parse_set_arg = $recce->[Marpa::PP::Internal::Recognizer::END];
1304              
1305 2313         21625 my $trace_tasks = $recce->[Marpa::PP::Internal::Recognizer::TRACE_TASKS];
1306 2313         7447 local $Marpa::PP::Internal::TRACE_FH =
1307             $recce->[Marpa::PP::Internal::Recognizer::TRACE_FILE_HANDLE];
1308              
1309 2313         5164 my $and_nodes = $recce->[Marpa::PP::Internal::Recognizer::AND_NODES];
1310 2313         5518 my $or_nodes = $recce->[Marpa::PP::Internal::Recognizer::OR_NODES];
1311 2313         4493 my $ranking_method =
1312             $recce->[Marpa::PP::Internal::Recognizer::RANKING_METHOD];
1313              
1314 2313 50       11904 if ( $recce->[Marpa::PP::Internal::Recognizer::SINGLE_PARSE_MODE] ) {
1315 0         0 Marpa::PP::exception(
1316             qq{Arguments were passed directly to value() in a previous call\n},
1317             qq{Only one call to value() is allowed per recognizer when arguments are passed directly\n},
1318             qq{This is the second call to value()\n}
1319             );
1320             } ## end if ( $recce->[Marpa::PP::Internal::Recognizer::SINGLE_PARSE_MODE...])
1321              
1322 2313         8636 my $parse_count = $recce->[Marpa::PP::Internal::Recognizer::PARSE_COUNT];
1323 2313         3689 my $max_parses = $recce->[Marpa::PP::Internal::Recognizer::MAX_PARSES];
1324 2313 50 66     37506 if ( $max_parses and $parse_count > $max_parses ) {
1325 0         0 Marpa::PP::exception("Maximum parse count ($max_parses) exceeded");
1326             }
1327              
1328 2313         6390 for my $arg_hash (@arg_hashes) {
1329              
1330 7 50       38 if ( exists $arg_hash->{end} ) {
1331 0 0       0 if ($parse_count) {
1332 0         0 Marpa::PP::exception(
1333             q{Cannot change "end" after first parse result});
1334             }
1335 0         0 $recce->[Marpa::PP::Internal::Recognizer::SINGLE_PARSE_MODE] = 1;
1336 0         0 $parse_set_arg = $arg_hash->{end};
1337 0         0 delete $arg_hash->{end};
1338             } ## end if ( exists $arg_hash->{end} )
1339              
1340 7 50       30 if ( exists $arg_hash->{closures} ) {
1341 0 0       0 if ($parse_count) {
1342 0         0 Marpa::PP::exception(
1343             q{Cannot change "closures" after first parse result});
1344             }
1345 0         0 $recce->[Marpa::PP::Internal::Recognizer::SINGLE_PARSE_MODE] = 1;
1346 0         0 my $closures = $arg_hash->{closures};
1347 0         0 while ( my ( $action, $closure ) = each %{$closures} ) {
  0         0  
1348 0 0       0 Marpa::PP::exception(qq{Bad closure for action "$action"})
1349             if ref $closure ne 'CODE';
1350             }
1351 0         0 $recce->[Marpa::PP::Internal::Recognizer::CLOSURES] = $closures;
1352 0         0 delete $arg_hash->{closures};
1353             } ## end if ( exists $arg_hash->{closures} )
1354              
1355 7 50       34 if ( exists $arg_hash->{trace_actions} ) {
1356 0         0 $recce->[Marpa::PP::Internal::Recognizer::SINGLE_PARSE_MODE] = 1;
1357 0         0 $recce->[Marpa::PP::Internal::Recognizer::TRACE_ACTIONS] =
1358             $arg_hash->{trace_actions};
1359 0         0 delete $arg_hash->{trace_actions};
1360             } ## end if ( exists $arg_hash->{trace_actions} )
1361              
1362 7 100       44 if ( exists $arg_hash->{trace_values} ) {
1363 2         6 $recce->[Marpa::PP::Internal::Recognizer::SINGLE_PARSE_MODE] = 1;
1364 2         5 $recce->[Marpa::PP::Internal::Recognizer::TRACE_VALUES] =
1365             $arg_hash->{trace_values};
1366 2         7 delete $arg_hash->{trace_values};
1367             } ## end if ( exists $arg_hash->{trace_values} )
1368              
1369             # A typo made its way into the documentation, so now it's a
1370             # synonym.
1371 7         22 for my $trace_fh_alias (qw(trace_fh trace_file_handle)) {
1372 14 100       66 if ( exists $arg_hash->{$trace_fh_alias} ) {
1373 2         7 $recce->[Marpa::PP::Internal::Recognizer::TRACE_FILE_HANDLE] =
1374             $Marpa::PP::Internal::TRACE_FH =
1375             $arg_hash->{$trace_fh_alias};
1376 2         6 delete $arg_hash->{$trace_fh_alias};
1377             } ## end if ( exists $arg_hash->{$trace_fh_alias} )
1378             } ## end for my $trace_fh_alias (qw(trace_fh trace_file_handle))
1379              
1380 7         21 my @unknown_arg_names = keys %{$arg_hash};
  7         25  
1381 7 50       48 Marpa::PP::exception(
1382             'Unknown named argument(s) to Marpa::PP::Recognizer::value: ',
1383             ( join q{ }, @unknown_arg_names ) )
1384             if @unknown_arg_names;
1385              
1386             } ## end for my $arg_hash (@arg_hashes)
1387              
1388 2313         4316 my $grammar = $recce->[Marpa::PP::Internal::Recognizer::GRAMMAR];
1389 2313         5195 my $earley_sets = $recce->[Marpa::PP::Internal::Recognizer::EARLEY_SETS];
1390              
1391 2313         15824 my $furthest_earleme =
1392             $recce->[Marpa::PP::Internal::Recognizer::FURTHEST_EARLEME];
1393 2313         4649 my $last_completed_earleme =
1394             $recce->[Marpa::PP::Internal::Recognizer::LAST_COMPLETED_EARLEME];
1395 2313 50       15653 Marpa::PP::exception(
1396             "Attempt to evaluate incompletely recognized parse:\n",
1397             " Last token ends at location $furthest_earleme\n",
1398             " Recognition done only as far as location $last_completed_earleme\n"
1399             ) if $furthest_earleme > $last_completed_earleme;
1400              
1401 2313         8381 my $rules = $grammar->[Marpa::PP::Internal::Grammar::RULES];
1402 2313         5677 my $symbols = $grammar->[Marpa::PP::Internal::Grammar::SYMBOLS];
1403              
1404 2313   100     9716 my $current_parse_set = $parse_set_arg
1405             // $recce->[Marpa::PP::Internal::Recognizer::FURTHEST_EARLEME];
1406              
1407             # Look for the start item and start rule
1408 2313         5282 my $earley_set = $earley_sets->[$current_parse_set];
1409              
1410             # Perhaps this call should be moved.
1411             # The null values are currently a function of the grammar,
1412             # and should be constant for the life of a recognizer.
1413 2313   66     10187 my $null_values =
1414             $recce->[Marpa::PP::Internal::Recognizer::NULL_VALUES] //=
1415             Marpa::PP::Internal::Recognizer::set_null_values($recce);
1416              
1417 2313         5306 my @task_list;
1418             my $start_item;
1419 0         0 my $start_rule;
1420 2313 100       6111 if ($parse_count) {
1421 2078         8216 @task_list = ( [Marpa::PP::Internal::Task::ITERATE] );
1422             }
1423             else {
1424 235         436 my $start_state;
1425              
1426 235         5127 EARLEY_ITEM:
1427 235         358 for my $item (
1428             @{ $earley_set->[Marpa::PP::Internal::Earley_Set::ITEMS] } )
1429             {
1430 1521         2160 $start_state = $item->[Marpa::PP::Internal::Earley_Item::STATE];
1431 1521         2078 $start_rule =
1432             $start_state->[Marpa::PP::Internal::AHFA::START_RULE];
1433 1521 100       3987 next EARLEY_ITEM if not $start_rule;
1434 235         385 $start_item = $item;
1435 235         596 last EARLEY_ITEM;
1436             } ## end for my $item ( @{ $earley_set->[...]})
1437              
1438 235 50       750 return if not $start_rule;
1439              
1440 235         890 $recce->[Marpa::PP::Internal::Recognizer::EVALUATOR_RULES] =
1441             Marpa::PP::Internal::Recognizer::set_actions($recce);
1442              
1443 235 100       6744 return Marpa::PP::Internal::Recognizer::do_null_parse( $recce,
1444             $start_rule )
1445             if $start_rule->[Marpa::PP::Internal::Rule::LHS]
1446             ->[Marpa::PP::Internal::Symbol::NULLING];
1447              
1448 217         557 @task_list = ();
1449 217         646 push @task_list, [Marpa::PP::Internal::Task::INITIALIZE];
1450             } ## end else [ if ($parse_count) ]
1451              
1452 2295         8838 $recce->[Marpa::PP::Internal::Recognizer::PARSE_COUNT]++;
1453              
1454 2295         4614 my $evaluator_rules =
1455             $recce->[Marpa::PP::Internal::Recognizer::EVALUATOR_RULES];
1456 2295         3454 my $iteration_stack =
1457             $recce->[Marpa::PP::Internal::Recognizer::ITERATION_STACK];
1458              
1459 2295         3094 my $iteration_node_worklist;
1460 2295         4225 my @and_node_in_use = ();
1461 2295         8572 for my $iteration_node ( @{$iteration_stack} ) {
  2295         6211  
1462 44524         73661 my $choices =
1463             $iteration_node->[Marpa::PP::Internal::Iteration_Node::CHOICES];
1464 44524         71483 my $choice = $choices->[0];
1465 44524         76078 my $and_node = $choice->[Marpa::PP::Internal::Choice::AND_NODE];
1466 44524         85084 my $and_node_id = $and_node->[Marpa::PP::Internal::And_Node::ID];
1467 44524         132035 $and_node_in_use[$and_node_id] = 1;
1468             } ## end for my $iteration_node ( @{$iteration_stack} )
1469              
1470 2295         41430 TASK: while ( my $task = pop @task_list ) {
1471              
1472 103961         188109 my ( $task_type, @task_data ) = @{$task};
  103961         272870  
1473              
1474             # Create the unpopulated top or-node
1475 103961 100       287872 if ( $task_type == Marpa::PP::Internal::Task::INITIALIZE ) {
1476              
1477 217 50       843 if ($trace_tasks) {
1478 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1479             'Task: INITIALIZE; ',
1480             ( scalar @task_list ), " tasks pending\n"
1481             or Marpa::PP::exception('print to trace handle failed');
1482             } ## end if ($trace_tasks)
1483              
1484 217         621 my $start_rule_id = $start_rule->[Marpa::PP::Internal::Rule::ID];
1485              
1486 217         517 my $start_or_node = [];
1487 217         605 $start_or_node->[Marpa::PP::Internal::Or_Node::ID] = 0;
1488 217         422 $start_or_node->[Marpa::PP::Internal::Or_Node::ITEM] =
1489             $start_item;
1490 217         422 $start_or_node->[Marpa::PP::Internal::Or_Node::RULE_ID] =
1491             $start_rule_id;
1492              
1493             # Start or-node cannot cycle
1494 217         741 $start_or_node->[Marpa::PP::Internal::Or_Node::CYCLE] = 0;
1495 217         746 $start_or_node->[Marpa::PP::Internal::Or_Node::POSITION] =
1496 217         352 scalar @{ $start_rule->[Marpa::PP::Internal::Rule::RHS] };
1497             {
1498 217         352 my $start_or_node_tag =
  217         1034  
1499             $start_or_node->[Marpa::PP::Internal::Or_Node::TAG] =
1500             Marpa::PP::Recognizer::or_node_tag( $recce,
1501             $start_or_node );
1502 217         939 $recce->[Marpa::PP::Internal::Recognizer::OR_NODE_HASH]
1503             ->{$start_or_node_tag} = $start_or_node;
1504             }
1505              
1506             # Zero out the evaluation
1507 217         377 $#{$and_nodes} = -1;
  217         930  
1508 217         498 $#{$or_nodes} = -1;
  217         587  
1509 217         336 $#{$iteration_stack} = -1;
  217         639  
1510 217         531 $#and_node_in_use = -1;
1511              
1512             # Populate the start or-node
1513 217         513 $or_nodes->[0] = $start_or_node;
1514              
1515 217         479 my $start_iteration_node = [];
1516 217         511 $start_iteration_node
1517             ->[Marpa::PP::Internal::Iteration_Node::OR_NODE] =
1518             $start_or_node;
1519              
1520 217         424 @task_list = ();
1521 217         807 push @task_list, [Marpa::PP::Internal::Task::FIX_TREE],
1522             [
1523             Marpa::PP::Internal::Task::STACK_INODE,
1524             $start_iteration_node
1525             ];
1526              
1527 217 100       790 if ( $ranking_method eq 'constant' ) {
1528 22         54 push @task_list, [Marpa::PP::Internal::Task::RANK_ALL],;
1529             }
1530              
1531 217         992 push @task_list,
1532             [
1533             Marpa::PP::Internal::Task::POPULATE_DEPTH, 0,
1534             [$start_or_node]
1535             ],
1536             [
1537             Marpa::PP::Internal::Task::POPULATE_OR_NODE,
1538             $start_or_node
1539             ];
1540              
1541 217         1023 next TASK;
1542              
1543             } ## end if ( $task_type == Marpa::PP::Internal::Task::INITIALIZE)
1544              
1545             # Special processing for the top iteration node
1546 103744 100       266016 if ( $task_type == Marpa::PP::Internal::Task::ITERATE ) {
1547              
1548 2089 50       10440 if ($trace_tasks) {
1549 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1550             'Task: ITERATE; ',
1551             ( scalar @task_list ), " tasks pending\n"
1552             or Marpa::PP::exception('print to trace handle failed');
1553             } ## end if ($trace_tasks)
1554              
1555 2089         4124 $iteration_node_worklist = undef;
1556              
1557             # In this pass, we go up the iteration stack,
1558             # looking a node which we can iterate.
1559 2089         4443 my $iteration_node;
1560 34464         127412 ITERATION_NODE:
1561 2089         4529 while ( $iteration_node = pop @{$iteration_stack} ) {
1562              
1563 34379         100690 my $choices = $iteration_node
1564             ->[Marpa::PP::Internal::Iteration_Node::CHOICES];
1565              
1566             # Eliminate the current choice
1567 34379         56904 my $choice = $choices->[0];
1568 34379         61372 my $and_node =
1569             $choice->[Marpa::PP::Internal::Choice::AND_NODE];
1570 34379         61363 my $and_node_id =
1571             $and_node->[Marpa::PP::Internal::And_Node::ID];
1572 34379         77329 $and_node_in_use[$and_node_id] = undef;
1573 34379         48062 shift @{$choices};
  34379         74394  
1574              
1575             # Throw away choices until we find one that does not cycle
1576 34379         67470 CHOICE: while ( scalar @{$choices} ) {
  34388         91951  
1577 2013         5461 $choice = $choices->[0];
1578 2013         4324 $and_node =
1579             $choice->[Marpa::PP::Internal::Choice::AND_NODE];
1580 2013         3575 $and_node_id =
1581             $and_node->[Marpa::PP::Internal::And_Node::ID];
1582 2013 100       6013 last CHOICE if not $and_node_in_use[$and_node_id];
1583 9         17 shift @{$choices};
  9         21  
1584             } ## end while ( scalar @{$choices} )
1585              
1586             # Climb the parent links, marking the ranks
1587             # of the nodes "dirty", until we hit one this is
1588             # already dirty
1589 34379         89305 my $direct_parent = $iteration_node
1590             ->[Marpa::PP::Internal::Iteration_Node::PARENT];
1591             PARENT:
1592 34379         99495 for ( my $parent = $direct_parent; defined $parent; ) {
1593 59957         118579 my $parent_node = $iteration_stack->[$parent];
1594             last PARENT
1595 59957 100       200883 if not $parent_node
1596             ->[Marpa::PP::Internal::Iteration_Node::CLEAN];
1597 27778         44936 $parent_node->[Marpa::PP::Internal::Iteration_Node::CLEAN]
1598             = 0;
1599 27778         67327 $parent = $parent_node
1600             ->[Marpa::PP::Internal::Iteration_Node::PARENT];
1601             } ## end for ( my $parent = $direct_parent; defined $parent; )
1602              
1603             # This or-node is already populated,
1604             # or it would not have been put
1605             # onto the iteration stack
1606 34379         67859 $choices = $iteration_node
1607             ->[Marpa::PP::Internal::Iteration_Node::CHOICES];
1608              
1609 34379 100       43005 if ( not scalar @{$choices} ) {
  34379         95125  
1610              
1611             # For the node just popped off the stack
1612             # unset the pointer to it in its parent
1613 32375 100       86111 if ( defined $direct_parent ) {
1614              
1615             #<<< cycles on perltidy version 20090616
1616 32302         57106 my $child_type = $iteration_node->[
1617             Marpa::PP::Internal::Iteration_Node::CHILD_TYPE ];
1618             #>>>
1619             #
1620 32302 100       87598 $iteration_stack->[$direct_parent]->[
1621             $child_type
1622             == Marpa::PP::Internal::And_Node::PREDECESSOR_ID
1623             ? Marpa::PP::Internal::Iteration_Node::PREDECESSOR_IX
1624             : Marpa::PP::Internal::Iteration_Node::CAUSE_IX
1625             ]
1626             = undef;
1627             } ## end if ( defined $direct_parent )
1628 32375         143750 next ITERATION_NODE;
1629             } ## end if ( not scalar @{$choices} )
1630              
1631             # Dirty the iteration node and put it back
1632             # on the stack
1633             $iteration_node
1634 2004         3824 ->[Marpa::PP::Internal::Iteration_Node::PREDECESSOR_IX] =
1635             undef;
1636 2004         3116 $iteration_node
1637             ->[Marpa::PP::Internal::Iteration_Node::CAUSE_IX] = undef;
1638 2004         3124 $iteration_node->[Marpa::PP::Internal::Iteration_Node::CLEAN]
1639             = 0;
1640 2004         5864 push @{$iteration_stack}, $iteration_node;
  2004         4178  
1641              
1642 2004         15284 $choice = $choices->[0];
1643 2004         3459 $and_node = $choice->[Marpa::PP::Internal::Choice::AND_NODE];
1644 2004         3195 $and_node_id = $and_node->[Marpa::PP::Internal::And_Node::ID];
1645 2004         3160 $and_node_in_use[$and_node_id] = 1;
1646              
1647 2004         4235 last ITERATION_NODE;
1648              
1649             } ## end while ( $iteration_node = pop @{$iteration_stack} )
1650              
1651             # If we hit the top of the stack without finding any node
1652             # to iterate, that is it for parsing.
1653 2089 100       6647 return if not defined $iteration_node;
1654              
1655 2004         7413 push @task_list, [Marpa::PP::Internal::Task::FIX_TREE];
1656              
1657 2004         9683 next TASK;
1658              
1659             } ## end if ( $task_type == Marpa::PP::Internal::Task::ITERATE)
1660              
1661             # This task is set up to rerun itself until explicitly exited
1662             FIX_TREE_LOOP:
1663 101655         279611 while ( $task_type == Marpa::PP::Internal::Task::FIX_TREE ) {
1664              
1665             # If the work list is undefined, initialize it to the entire stack
1666 96703   100     285807 $iteration_node_worklist //= [ 0 .. $#{$iteration_stack} ];
  2217         14623  
1667 96703 100       147877 next TASK if not scalar @{$iteration_node_worklist};
  96703         320858  
1668 94493         212147 my $working_node_ix = $iteration_node_worklist->[-1];
1669              
1670 94493 50       231530 if ($trace_tasks) {
1671 0         0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1672             q{Task: FIX_TREE; },
1673 0 0       0 ( scalar @{$iteration_node_worklist} ),
1674             " current iteration node #$working_node_ix; ",
1675             ( scalar @task_list ), " tasks pending\n"
1676             or Marpa::PP::exception('print to trace handle failed');
1677             } ## end if ($trace_tasks)
1678              
1679             # We are done fixing the tree is the worklist is empty
1680              
1681 94493         175996 my $working_node = $iteration_stack->[$working_node_ix];
1682 94493         151980 my $choices =
1683             $working_node->[Marpa::PP::Internal::Iteration_Node::CHOICES];
1684 94493         193458 my $choice = $choices->[0];
1685 94493         144567 my $working_and_node =
1686             $choice->[Marpa::PP::Internal::Choice::AND_NODE];
1687              
1688             FIELD:
1689 94493         220782 for my $field ( Marpa::PP::Internal::Iteration_Node::CAUSE_IX,
1690             Marpa::PP::Internal::Iteration_Node::PREDECESSOR_IX
1691             )
1692             {
1693 168302         281026 my $ix = $working_node->[$field];
1694 168302 100       570935 next FIELD if defined $ix;
1695 94389 100       224623 my $and_node_field =
1696             $field
1697             == Marpa::PP::Internal::Iteration_Node::PREDECESSOR_IX
1698             ? Marpa::PP::Internal::And_Node::PREDECESSOR_ID
1699             : Marpa::PP::Internal::And_Node::CAUSE_ID;
1700              
1701 94389         187434 my $or_node_id = $working_and_node->[$and_node_field];
1702 94389 100       231218 if ( not defined $or_node_id ) {
1703 53341         117283 $working_node->[$field] = -999_999_999;
1704 53341         185607 next FIELD;
1705             }
1706              
1707 41048         107119 my $new_iteration_node = [];
1708 41048         99423 $new_iteration_node
1709             ->[Marpa::PP::Internal::Iteration_Node::OR_NODE] =
1710             $or_nodes->[$or_node_id];
1711 41048         83272 $new_iteration_node
1712             ->[Marpa::PP::Internal::Iteration_Node::PARENT] =
1713             $working_node_ix;
1714 41048         81557 $new_iteration_node
1715             ->[Marpa::PP::Internal::Iteration_Node::CHILD_TYPE] =
1716             $and_node_field;
1717              
1718             # Restack the current task, adding a task to create
1719             # the child iteration node
1720 41048         108837 push @task_list, $task,
1721             [
1722             Marpa::PP::Internal::Task::STACK_INODE,
1723             $new_iteration_node
1724             ];
1725 41048         210456 next TASK;
1726             } ## end for my $field ( ...)
1727              
1728 53445         157749 $working_node->[Marpa::PP::Internal::Iteration_Node::CLEAN] = 1;
1729 53445         64413 pop @{$iteration_node_worklist};
  53445         100652  
1730 53445         196015 next FIX_TREE_LOOP;
1731              
1732             } ## end while ( $task_type == Marpa::PP::Internal::Task::FIX_TREE)
1733              
1734 58397 100       149381 if ( $task_type == Marpa::PP::Internal::Task::POPULATE_OR_NODE ) {
1735              
1736 13140         48586 my $work_or_node = $task_data[0];
1737              
1738 13140 50       24767 if ($trace_tasks) {
1739 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
1740             'Task: POPULATE_OR_NODE o',
1741             $work_or_node->[Marpa::PP::Internal::Or_Node::ID],
1742             q{; }, ( scalar @task_list ), " tasks pending\n"
1743             or Marpa::PP::exception('print to trace handle failed');
1744             } ## end if ($trace_tasks)
1745              
1746 13140         33305 my $work_node_name =
1747             $work_or_node->[Marpa::PP::Internal::Or_Node::TAG];
1748              
1749             # SET Should be the same for all items
1750 13140         21300 my $or_node_item =
1751             $work_or_node->[Marpa::PP::Internal::Or_Node::ITEM];
1752              
1753 13140         30411 my $work_set =
1754             $or_node_item->[Marpa::PP::Internal::Earley_Item::SET];
1755 13140         19910 my $work_node_origin =
1756             $or_node_item->[Marpa::PP::Internal::Earley_Item::ORIGIN];
1757              
1758 13140         18622 my $work_rule_id =
1759             $work_or_node->[Marpa::PP::Internal::Or_Node::RULE_ID];
1760 13140         25948 my $work_rule = $rules->[$work_rule_id];
1761 13140         19197 my $work_position =
1762             $work_or_node->[Marpa::PP::Internal::Or_Node::POSITION] - 1;
1763 13140         26689 my $work_symbol =
1764             $work_rule->[Marpa::PP::Internal::Rule::RHS]
1765             ->[$work_position];
1766 13140         28290 my $work_symbol_name =
1767             $work_symbol->[Marpa::PP::Internal::Symbol::NAME];
1768              
1769             {
1770              
1771 13140         16638 my $item = $or_node_item;
  13140         16200  
1772 13140         17559 my $or_sapling_set = $work_set;
1773              
1774 13140 100       47233 my $leo_links =
1775             defined
1776             $item->[Marpa::PP::Internal::Earley_Item::IS_LEO_EXPANDED]
1777             ? []
1778             : $item->[Marpa::PP::Internal::Earley_Item::LEO_LINKS];
1779 13140   100     40314 $leo_links //= [];
1780              
1781             # If this is a Leo completion, translate the Leo links
1782 13140         15903 for my $leo_link ( @{$leo_links} ) {
  13140         54049  
1783              
1784 1255         2749 my ( $leo_item, $cause ) = @{$leo_link};
  1255         4094  
1785              
1786 1255         2821 my $next_leo_item = $leo_item
1787             ->[Marpa::PP::Internal::Leo_Item::PREDECESSOR];
1788 1255         2383 my $leo_symbol_name = $leo_item
1789             ->[Marpa::PP::Internal::Leo_Item::LEO_POSTDOT_SYMBOL];
1790 1255         2149 my $leo_base_item =
1791             $leo_item->[Marpa::PP::Internal::Leo_Item::BASE];
1792              
1793 1255         14405 my $next_links = [ [ $leo_base_item, $cause, ] ];
1794              
1795 1255         1651 LEO_ITEM: for ( ;; ) {
1796              
1797 2779 100       14683 if ( not $next_leo_item ) {
1798              
1799             # die join " ", __FILE__, __LINE__, "next link cnt", (scalar @{$next_links})
1800             # if scalar @{$next_links} != 1;
1801              
1802             #<<< perltidy cycles as of version 20090616
1803 1255         3109 push @{ $item
  1255         2615  
1804             ->[Marpa::PP::Internal::Earley_Item::LINKS
1805             ] },
1806 1255         1587 @{$next_links};
1807             #<<<
1808              
1809             # Now that the Leo links are translated, mark the
1810             # Earley item accordingly
1811 1255         2129 $item->[Marpa::PP::Internal::Earley_Item::IS_LEO_EXPANDED] = 1;
1812              
1813 1255         6962 last LEO_ITEM;
1814              
1815             } ## end if ( not $next_leo_item )
1816              
1817 1524         7018 my ( undef, $base_to_state ) =
1818 1524         2832 @{ $leo_base_item
1819             ->[ Marpa::PP::Internal::Earley_Item::STATE ]
1820             ->[Marpa::PP::Internal::AHFA::TRANSITION]
1821             ->{$leo_symbol_name} };
1822 1524         3055 my $origin = $next_leo_item
1823             ->[Marpa::PP::Internal::Leo_Item::SET];
1824              
1825 1524         6631 my $name = sprintf
1826             'S%d@%d-%d',
1827             $base_to_state->[Marpa::PP::Internal::AHFA::ID],
1828             $origin,
1829             $or_sapling_set;
1830 1524         3988 my $hash_key = join q{:},
1831             $base_to_state->[Marpa::PP::Internal::AHFA::ID],
1832             $origin;
1833 1524         4156 my $earley_hash =
1834             $earley_sets->[$or_sapling_set]
1835             ->[Marpa::PP::Internal::Earley_Set::HASH];
1836              
1837 1524         3587 my $target_item = $earley_hash->{$hash_key};
1838 1524 100       4284 if ( not defined $target_item ) {
1839 1306         2850 $target_item = [];
1840 1306         5202 $target_item
1841             ->[Marpa::PP::Internal::Earley_Item::ID] =
1842             $recce->[
1843             Marpa::PP::Internal::Recognizer::NEXT_EARLEY_ITEM_ID
1844             ]++;
1845 1306         4164 $target_item
1846             ->[Marpa::PP::Internal::Earley_Item::ORIGIN] =
1847             $origin;
1848 1306         2019 $target_item
1849             ->[Marpa::PP::Internal::Earley_Item::STATE] =
1850             $base_to_state;
1851 1306         4084 $target_item
1852             ->[Marpa::PP::Internal::Earley_Item::LINKS] =
1853             [];
1854 1306         5367 $target_item
1855             ->[Marpa::PP::Internal::Earley_Item::SET] =
1856             $or_sapling_set;
1857 1306         4659 $earley_hash->{$hash_key} = $target_item;
1858 1306         1858 push @{ $earley_sets->[$or_sapling_set]
  1306         3818  
1859             ->[Marpa::PP::Internal::Earley_Set::ITEMS]
1860             }, $target_item;
1861             } ## end if ( not defined $target_item )
1862              
1863 1524         2346 push @{ $target_item
  1524         3069  
1864             ->[Marpa::PP::Internal::Earley_Item::LINKS] },
1865 1524         2371 @{$next_links};
1866              
1867 1524         2096 $leo_item = $next_leo_item;
1868 1524         2755 $next_leo_item = $leo_item
1869             ->[Marpa::PP::Internal::Leo_Item::PREDECESSOR];
1870 1524         2196 $leo_base_item =
1871             $leo_item->[Marpa::PP::Internal::Leo_Item::BASE];
1872 1524         5155 $leo_symbol_name =
1873             $leo_item->[Marpa::PP::Internal::Leo_Item::LEO_POSTDOT_SYMBOL];
1874              
1875 1524         9142 $next_links = [ [ $leo_base_item, $target_item, $leo_symbol_name ] ];
1876              
1877             } ## end for ( ;; )
1878             } ## end for my $leo_link ( @{$leo_links} )
1879              
1880             }
1881              
1882 13140         21307 my @link_worklist;
1883              
1884             CREATE_LINK_WORKLIST: {
1885              
1886             # Several Earley items may be the source of the same or-node,
1887             # but the or-node only keeps track of one. This is sufficient,
1888             # because the Earley item is tracked by the or-node only for its
1889             # links, and the links for every Earley item which is the source
1890             # of the same or-node must be the same. There's more about this
1891             # in the libmarpa docs.
1892              
1893             # link worklist item is $predecessor, $cause, $token_name, $value_ref
1894              
1895             # All predecessors apply to a
1896             # nulling work symbol.
1897              
1898 13140 100       14001 if ( $work_symbol->[Marpa::PP::Internal::Symbol::NULLING] ) {
  13140         46939  
1899 996         1754 my $nulling_symbol_id =
1900             $work_symbol->[Marpa::PP::Internal::Symbol::ID];
1901 996         1705 my $value_ref = \$null_values->[$nulling_symbol_id];
1902 996         3385 @link_worklist =
1903             [ $or_node_item, undef, $work_symbol_name, $value_ref ];
1904 996         2448 last CREATE_LINK_WORKLIST;
1905             } ## end if ( $work_symbol->[...])
1906              
1907             # Collect links for or node items
1908             # into link work items
1909             @link_worklist =
1910 12144         13537 @{ $or_node_item->[Marpa::PP::Internal::Earley_Item::LINKS] };
  12144         73087  
1911              
1912             } ## end CREATE_LINK_WORKLIST:
1913              
1914             # The and node data is put into the hash, only to be taken out immediately,
1915             # but in the process the very important step of eliminating duplicates
1916             # is accomplished.
1917 13140         48797 my %and_node_data = ();
1918              
1919 13140         37505 LINK_WORK_ITEM: for my $link_work_item (@link_worklist) {
1920              
1921 14994         45962 my ( $predecessor, $cause, $symbol_name, $value_ref ) =
1922 14994         20116 @{$link_work_item};
1923              
1924             # next LINK_WORK_ITEM if $symbol_name ne $work_symbol_name;
1925              
1926 14994         22992 my $cause_earleme = $work_node_origin;
1927 14994         18733 my $predecessor_id;
1928             my $predecessor_name;
1929              
1930 14994 100       54852 if ( $work_position > 0 ) {
1931              
1932 4597         8105 $cause_earleme =
1933             $predecessor->[Marpa::PP::Internal::Earley_Item::SET];
1934              
1935 4597         27216 $predecessor_name =
1936             "R$work_rule_id:$work_position" . q{@}
1937             . $predecessor
1938             ->[Marpa::PP::Internal::Earley_Item::ORIGIN] . q{-}
1939             . $cause_earleme;
1940              
1941 4597         17066 FIND_PREDECESSOR: {
1942 4597         5238 my $predecessor_or_node =
1943             $recce
1944             ->[Marpa::PP::Internal::Recognizer::OR_NODE_HASH]
1945             ->{$predecessor_name};
1946 4597 100       10184 if ($predecessor_or_node) {
1947 1084         1515 $predecessor_id = $predecessor_or_node
1948             ->[Marpa::PP::Internal::Or_Node::ID];
1949              
1950 1084         2039 last FIND_PREDECESSOR;
1951              
1952             } ## end if ($predecessor_or_node)
1953              
1954 3513         5559 $predecessor_or_node = [];
1955 3513         8061 $predecessor_or_node
1956             ->[Marpa::PP::Internal::Or_Node::TAG] =
1957             $predecessor_name;
1958 3513         10207 $recce
1959             ->[Marpa::PP::Internal::Recognizer::OR_NODE_HASH]
1960             ->{$predecessor_name} = $predecessor_or_node;
1961 3513         6269 $predecessor_or_node
1962             ->[Marpa::PP::Internal::Or_Node::RULE_ID] =
1963             $work_rule_id;
1964              
1965             # nulling nodes are never part of cycles
1966             # thanks to the CHAF rewrite
1967 3513   100     13460 $predecessor_or_node
1968             ->[Marpa::PP::Internal::Or_Node::CYCLE] =
1969             $work_rule
1970             ->[Marpa::PP::Internal::Rule::VIRTUAL_CYCLE]
1971             && $cause_earleme != $work_node_origin;
1972 3513         7053 $predecessor_or_node
1973             ->[Marpa::PP::Internal::Or_Node::POSITION] =
1974             $work_position;
1975 3513         4741 $predecessor_or_node
1976             ->[Marpa::PP::Internal::Or_Node::ITEM] =
1977             $predecessor;
1978 3513         7689 $predecessor_id =
1979 3513         3899 ( push @{$or_nodes}, $predecessor_or_node ) - 1;
1980              
1981 3513 50       8401 Marpa::PP::exception(
1982             "Too many or-nodes for evaluator: $predecessor_id"
1983             )
1984             if $predecessor_id
1985             & ~(Marpa::PP::Internal::N_FORMAT_MAX);
1986 3513         11391 $predecessor_or_node
1987             ->[Marpa::PP::Internal::Or_Node::ID] =
1988             $predecessor_id;
1989              
1990             } ## end FIND_PREDECESSOR:
1991              
1992             } ## end if ( $work_position > 0 )
1993              
1994 14994         16745 my $cause_id;
1995              
1996 14994 100       54806 if ( defined $cause ) {
1997              
1998 11536         20362 my $cause_symbol_id =
1999             $work_symbol->[Marpa::PP::Internal::Symbol::ID];
2000              
2001 11536         25253 my $state =
2002             $cause->[Marpa::PP::Internal::Earley_Item::STATE];
2003              
2004 11536         13996 for my $cause_rule (
  11536         36692  
2005             @{ $state
2006             ->[Marpa::PP::Internal::AHFA::COMPLETE_RULES]
2007             ->[$cause_symbol_id]
2008             }
2009             )
2010             {
2011              
2012 11596         21219 my $cause_rule_id =
2013             $cause_rule->[Marpa::PP::Internal::Rule::ID];
2014              
2015 11596         59756 my $cause_name =
2016             "R$cause_rule_id:"
2017 11596         22854 . (scalar @{ $cause_rule->[Marpa::PP::Internal::Rule::RHS] })
2018             . q{@}
2019             . $cause->[Marpa::PP::Internal::Earley_Item::ORIGIN]
2020             . q{-}
2021             . $cause->[Marpa::PP::Internal::Earley_Item::SET];
2022              
2023 11596         30828 FIND_CAUSE: {
2024 11596         15915 my $cause_or_node =
2025             $recce->[
2026             Marpa::PP::Internal::Recognizer::OR_NODE_HASH]
2027             ->{$cause_name};
2028 11596 100       65896 if ($cause_or_node) {
2029 2186         3161 $cause_id = $cause_or_node
2030             ->[Marpa::PP::Internal::Or_Node::ID];
2031 2186         4321 last FIND_CAUSE;
2032             } ## end if ($cause_or_node)
2033              
2034 9410         19425 $cause_or_node = [];
2035 9410         28415 $cause_or_node
2036             ->[Marpa::PP::Internal::Or_Node::TAG] =
2037             $cause_name;
2038 9410         34687 $recce->[
2039             Marpa::PP::Internal::Recognizer::OR_NODE_HASH]
2040             ->{$cause_name} = $cause_or_node;
2041 9410         19459 $cause_or_node
2042             ->[Marpa::PP::Internal::Or_Node::RULE_ID] =
2043             $cause_rule_id;
2044              
2045             # nulling nodes are never part of cycles
2046             # thanks to the CHAF rewrite
2047 9410   66     35208 $cause_or_node
2048             ->[Marpa::PP::Internal::Or_Node::CYCLE] =
2049             $cause_rule
2050             ->[Marpa::PP::Internal::Rule::VIRTUAL_CYCLE]
2051             && $cause_earleme != $work_set;
2052 9410         33543 $cause_or_node
2053             ->[Marpa::PP::Internal::Or_Node::POSITION] =
2054 9410         17023 scalar @{ $cause_rule
2055             ->[Marpa::PP::Internal::Rule::RHS] };
2056 9410         17220 $cause_or_node ->[Marpa::PP::Internal::Or_Node::ITEM] =
2057             $cause;
2058 9410         23805 $cause_id =
2059 9410         10341 ( push @{$or_nodes}, $cause_or_node ) - 1;
2060              
2061 9410 50       25015 Marpa::PP::exception(
2062             "Too many or-nodes for evaluator: $cause_id")
2063             if $cause_id
2064             & ~(Marpa::PP::Internal::N_FORMAT_MAX);
2065 9410         19730 $cause_or_node->[Marpa::PP::Internal::Or_Node::ID]
2066             = $cause_id;
2067              
2068             } ## end FIND_CAUSE:
2069              
2070 11596         32751 my $and_node = [];
2071             #<<< cycles in perltidy as of 5 Jul 2010
2072 11596         30615 $and_node
2073             ->[Marpa::PP::Internal::And_Node::PREDECESSOR_ID
2074             ] = $predecessor_id;
2075             #>>>
2076 11596         35467 $and_node
2077             ->[Marpa::PP::Internal::And_Node::CAUSE_EARLEME] =
2078             $cause_earleme;
2079 11596         35651 $and_node->[Marpa::PP::Internal::And_Node::CAUSE_ID] =
2080             $cause_id;
2081              
2082             $and_node_data{
2083 11596   100     141222 join q{:},
2084             ( $predecessor_id // q{} ),
2085             $cause_id
2086             }
2087             = $and_node;
2088              
2089             } ## end for
2090              
2091 11536         44686 next LINK_WORK_ITEM;
2092              
2093             } # if cause
2094              
2095 3458         5859 my $and_node = [];
2096 3458         13719 $and_node->[Marpa::PP::Internal::And_Node::PREDECESSOR_ID] =
2097             $predecessor_id;
2098 3458         16734 $and_node->[Marpa::PP::Internal::And_Node::CAUSE_EARLEME] =
2099             $cause_earleme;
2100 3458         7289 $and_node->[Marpa::PP::Internal::And_Node::TOKEN_NAME] =
2101             $symbol_name;
2102 3458         4798 $and_node->[Marpa::PP::Internal::And_Node::VALUE_REF] =
2103             $value_ref;
2104              
2105             $and_node_data{
2106 3458   100     27077 join q{:}, ( $predecessor_id // q{} ),
2107             q{}, $symbol_name
2108             }
2109             = $and_node;
2110              
2111             } ## end for
2112              
2113 14025         52783 my @child_and_nodes =
2114 13140         40707 map { $and_node_data{$_} } sort keys %and_node_data;
2115              
2116 13140         32773 for my $and_node (@child_and_nodes) {
2117              
2118 14025         31387 $and_node->[Marpa::PP::Internal::And_Node::RULE_ID] =
2119             $work_rule_id;
2120              
2121 14025         84488 $and_node->[Marpa::PP::Internal::And_Node::VALUE_OPS] =
2122             $work_position
2123 14025 100       24986 == $#{ $work_rule->[Marpa::PP::Internal::Rule::RHS] }
2124             ? $evaluator_rules
2125             ->[ $work_rule->[Marpa::PP::Internal::Rule::ID] ]
2126             : undef;
2127              
2128 14025         42685 $and_node->[Marpa::PP::Internal::And_Node::POSITION] =
2129             $work_position;
2130 14025         27759 $and_node->[Marpa::PP::Internal::And_Node::START_EARLEME] =
2131             $work_node_origin;
2132 14025         25367 $and_node->[Marpa::PP::Internal::And_Node::END_EARLEME] =
2133             $work_set;
2134 14025         21344 my $id = ( push @{$and_nodes}, $and_node ) - 1;
  14025         34445  
2135 14025 50       41433 Marpa::PP::exception("Too many and-nodes for evaluator: $id")
2136             if $id & ~(Marpa::PP::Internal::N_FORMAT_MAX);
2137 14025         22561 $and_node->[Marpa::PP::Internal::And_Node::ID] = $id;
2138 14025         49461 $and_node->[Marpa::PP::Internal::And_Node::TAG] =
2139             Marpa::PP::Recognizer::and_node_tag( $recce, $and_node );
2140              
2141             } ## end for my $and_node (@child_and_nodes)
2142              
2143             # Populate the or-node, now that we have ID's for all the and-nodes
2144 14025         84365 $work_or_node->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS] =
2145 13140         44557 [ map { $_->[Marpa::PP::Internal::And_Node::ID] }
2146             @child_and_nodes ];
2147              
2148 13140         102398 next TASK;
2149             } ## end if ( $task_type == ...)
2150              
2151 45257 100       118450 if ( $task_type == Marpa::PP::Internal::Task::STACK_INODE ) {
2152              
2153 41271         62295 my $work_iteration_node = $task_data[0];
2154 41271         85059 my $or_node = $work_iteration_node
2155             ->[Marpa::PP::Internal::Iteration_Node::OR_NODE];
2156              
2157 41271 50       90226 if ($trace_tasks) {
2158 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
2159             'Task: STACK_INODE o',
2160             $or_node->[Marpa::PP::Internal::Or_Node::ID],
2161             q{; }, ( scalar @task_list ), " tasks pending\n"
2162             or Marpa::PP::exception('print to trace handle failed');
2163             } ## end if ($trace_tasks)
2164              
2165 41271         92281 my $and_node_ids =
2166             $or_node->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS];
2167              
2168             # If the or-node is not populated,
2169             # restack this task, and stack a task to populate the
2170             # or-node on top of it.
2171 41271 50       114252 if ( not defined $and_node_ids ) {
2172 0         0 push @task_list, $task,
2173             [ Marpa::PP::Internal::Task::POPULATE_OR_NODE, $or_node ];
2174 0         0 next TASK;
2175             }
2176              
2177 41271         68064 my $choices = $work_iteration_node
2178             ->[Marpa::PP::Internal::Iteration_Node::CHOICES];
2179              
2180             # At this point we know the iteration node is populated, so if we don't
2181             # have the choices list initialized, we can do so now.
2182 41271 100       115894 if ( not defined $choices ) {
2183              
2184 41265 100       105784 if ( $ranking_method eq 'constant' ) {
2185 44     44   467713 no integer;
  44         160  
  44         391  
2186 302         453 my @choices = ();
2187 302         314 AND_NODE: for my $and_node_id ( @{$and_node_ids} ) {
  302         561  
2188 356         508 my $and_node = $and_nodes->[$and_node_id];
2189 356         469 my $new_choice = [];
2190 356         638 $new_choice->[Marpa::PP::Internal::Choice::AND_NODE] =
2191             $and_node;
2192              
2193             #<<< cycles on perltidy 20090616
2194 356         473 my $rank_ref = $and_node->[
2195             Marpa::PP::Internal::And_Node::INITIAL_RANK_REF ];
2196             #>>>
2197 356 50       687 die "Undefined rank for a$and_node_id"
2198             if not defined $rank_ref;
2199 356 100       750 next AND_NODE if not ref $rank_ref;
2200 352         592 $new_choice->[Marpa::PP::Internal::Choice::RANK] =
2201 352         354 ${$rank_ref};
2202 352         968 push @choices, $new_choice;
2203             } ## end for my $and_node_id ( @{$and_node_ids} )
2204             ## no critic (BuiltinFunctions::ProhibitReverseSortBlock)
2205             $choices = [
2206 54         242 sort {
2207 302         963 $b->[Marpa::PP::Internal::Choice::RANK]
2208             <=> $a->[Marpa::PP::Internal::Choice::RANK]
2209             } @choices
2210             ];
2211             } ## end if ( $ranking_method eq 'constant' )
2212             else {
2213 43006         265275 $choices =
2214 40963         64795 [ map { [ $and_nodes->[$_], 0 ] } @{$and_node_ids} ];
  40963         86999  
2215             }
2216 41265         102354 $work_iteration_node
2217             ->[Marpa::PP::Internal::Iteration_Node::CHOICES] =
2218             $choices;
2219              
2220             } ## end if ( not defined $choices )
2221              
2222             # Due to skipping, even an initialized set of choices
2223             # may be empty. If it is, throw away the stack and iterate.
2224 41271 100       48007 if ( not scalar @{$choices} ) {
  41271         112689  
2225              
2226 4         14 @task_list = ( [Marpa::PP::Internal::Task::ITERATE] );
2227 4         20 next TASK;
2228             }
2229              
2230             # Make our choice and set RANK
2231 41267         81237 my $choice = $choices->[0];
2232              
2233             # Rank is left until later to be initialized
2234              
2235 41267         71580 my $and_node = $choice->[Marpa::PP::Internal::Choice::AND_NODE];
2236 41267         70752 my $and_node_id = $and_node->[Marpa::PP::Internal::And_Node::ID];
2237 41267         53209 my $next_iteration_stack_ix = scalar @{$iteration_stack};
  41267         67112  
2238              
2239             # Check if we are about to cycle.
2240 41267 100       140291 if ( $and_node_in_use[$and_node_id] ) {
2241              
2242             # If there is another choice, increment choice and restack
2243             # this task ...
2244             #
2245             # This iteration node is not yet on the stack, so we
2246             # don't need to do anything with the pointers.
2247 13 100       27 if ( scalar @{$choices} > 1 ) {
  13         44  
2248 6         10 shift @{$choices};
  6         56  
2249 6         18 push @task_list, $task;
2250 6         28 next TASK;
2251             }
2252              
2253             # Otherwise, throw away all pending tasks and
2254             # iterate
2255 7         410 @task_list = ( [Marpa::PP::Internal::Task::ITERATE] );
2256 7         43 next TASK;
2257             } ## end if ( $and_node_in_use[$and_node_id] )
2258 41254         69491 $and_node_in_use[$and_node_id] = 1;
2259              
2260             # Tell the parent that the new iteration node is its child.
2261 41254 100       125044 if (defined(
2262             my $child_type =
2263             $work_iteration_node
2264             ->[Marpa::PP::Internal::Iteration_Node::CHILD_TYPE]
2265             )
2266             )
2267             {
2268 41041         79940 my $parent_ix = $work_iteration_node
2269             ->[Marpa::PP::Internal::Iteration_Node::PARENT];
2270 41041         137450 $iteration_stack->[$parent_ix]->[
2271             $child_type
2272             == Marpa::PP::Internal::And_Node::PREDECESSOR_ID
2273             ? Marpa::PP::Internal::Iteration_Node::PREDECESSOR_IX
2274             : Marpa::PP::Internal::Iteration_Node::CAUSE_IX
2275             ]
2276 41041 100       46842 = scalar @{$iteration_stack};
2277             } ## end if ( defined( my $child_type = $work_iteration_node->...))
2278              
2279             # If we are keeping an iteration node worklist,
2280             # add this node to it.
2281 41041         64336 defined $iteration_node_worklist
2282 41041         97424 and push @{$iteration_node_worklist},
2283 41254 100       138695 scalar @{$iteration_stack};
2284              
2285 41254         75035 push @{$iteration_stack}, $work_iteration_node;
  41254         85062  
2286              
2287 41254         294566 next TASK;
2288              
2289             } ## end if ( $task_type == Marpa::PP::Internal::Task::STACK_INODE)
2290              
2291 3986 100       7457 if ( $task_type == Marpa::PP::Internal::Task::RANK_ALL ) {
2292              
2293 22 50       68 if ($trace_tasks) {
2294 0 0       0 print {$Marpa::PP::Internal::TRACE_FH} 'Task: RANK_ALL; ',
  0         0  
2295             ( scalar @task_list ), " tasks pending\n"
2296             or Marpa::PP::exception('print to trace handle failed');
2297             }
2298              
2299 22         89 do_rank_all($recce);
2300              
2301 22         208 next TASK;
2302             } ## end if ( $task_type == Marpa::PP::Internal::Task::RANK_ALL)
2303              
2304             # This task is for pre-populating the entire and-node and or-node
2305             # space one "depth level" at a time. It is used when ranking is
2306             # being done, because to rank you need to make a pre-pass through
2307             # the entire and-node and or-node space.
2308             #
2309             # As a side effect, depths are calculated for all the and-nodes.
2310 3964 50       8739 if ( $task_type == Marpa::PP::Internal::Task::POPULATE_DEPTH ) {
2311 3964         6314 my ( $depth, $or_node_list ) = @task_data;
2312              
2313 3964 50       9331 if ($trace_tasks) {
2314 0 0       0 print {$Marpa::PP::Internal::TRACE_FH}
  0         0  
2315             'Task: POPULATE_DEPTH; ',
2316             ( scalar @task_list ), " tasks pending\n"
2317             or Marpa::PP::exception('print to trace handle failed');
2318             } ## end if ($trace_tasks)
2319              
2320             # We can assume all or-nodes in the list are populated
2321              
2322 3964         6096 my %or_nodes_at_next_depth = ();
2323              
2324             # Assign a depth to all the and-node children which
2325             # do not already have one assigned.
2326 3964         4827 for my $and_node_id (
  13140         67885  
2327 13140         13567 map { @{ $_->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS] } }
  3964         10389  
2328             @{$or_node_list} )
2329             {
2330 14025         22252 my $and_node = $and_nodes->[$and_node_id];
2331             FIELD:
2332 14025         24188 for my $field (
2333             Marpa::PP::Internal::And_Node::PREDECESSOR_ID,
2334             Marpa::PP::Internal::And_Node::CAUSE_ID
2335             )
2336             {
2337 28050         54560 my $child_or_node_id = $and_node->[$field];
2338 28050 100       79415 next FIELD if not defined $child_or_node_id;
2339              
2340 14758         24213 my $next_depth_or_node = $or_nodes->[$child_or_node_id];
2341              
2342             # Push onto list only if child or-node
2343             # is not already populated
2344 14758 100       112378 $next_depth_or_node
2345             ->[Marpa::PP::Internal::Or_Node::AND_NODE_IDS]
2346             or $or_nodes_at_next_depth{$next_depth_or_node} =
2347             $next_depth_or_node;
2348              
2349             } ## end for my $field ( ...)
2350              
2351             } ## end for my $and_node_id ( map { @{ $_->[...]}})
2352              
2353             # No or-nodes at next depth?
2354             # Great, we are done!
2355 12923         32128 my @or_nodes_at_next_depth =
2356 3964         19117 map { $or_nodes_at_next_depth{$_} }
2357             sort keys %or_nodes_at_next_depth;
2358 3964 100       15182 next TASK if not scalar @or_nodes_at_next_depth;
2359              
2360 12923         32946 push @task_list,
2361             [
2362             Marpa::PP::Internal::Task::POPULATE_DEPTH, $depth + 1,
2363             \@or_nodes_at_next_depth
2364             ],
2365 3747         12466 map { [ Marpa::PP::Internal::Task::POPULATE_OR_NODE, $_ ] }
2366             @or_nodes_at_next_depth;
2367              
2368 3747         33801 next TASK;
2369              
2370             } ## end if ( $task_type == Marpa::PP::Internal::Task::POPULATE_DEPTH)
2371              
2372             Marpa::PP::internal_error(
2373 0         0 "Internal error: Unknown task type: $task_type");
2374              
2375             } ## end while ( my $task = pop @task_list )
2376              
2377 53403         131794 my @stack = map {
2378 2210         8216 $_->[Marpa::PP::Internal::Iteration_Node::CHOICES]->[0]
2379             ->[Marpa::PP::Internal::Choice::AND_NODE]
2380 2210         4480 } @{$iteration_stack};
2381              
2382 2210         13601 return Marpa::PP::Internal::Recognizer::evaluate( $recce, \@stack );
2383              
2384             } ## end sub Marpa::PP::Recognizer::value
2385              
2386             1;