File Coverage

blib/lib/Marpa/R3/SLR.pm
Criterion Covered Total %
statement 468 583 80.2
branch 92 156 58.9
condition 24 49 48.9
subroutine 57 70 81.4
pod 0 1 0.0
total 641 859 74.6


line stmt bran cond sub pod time code
1             # Marpa::R3 is Copyright (C) 2018, Jeffrey Kegler.
2             #
3             # This module is free software; you can redistribute it and/or modify it
4             # under the same terms as Perl 5.10.1. For more details, see the full text
5             # of the licenses in the directory LICENSES.
6             #
7             # This program is distributed in the hope that it will be
8             # useful, but it is provided "as is" and without any express
9             # or implied warranties. For details, see the full text of
10             # of the licenses in the directory LICENSES.
11              
12             package Marpa::R3::Recognizer;
13              
14 101     101   2231 use 5.010001;
  101         404  
15 101     101   602 use strict;
  101         236  
  101         2581  
16 101     101   605 use warnings;
  101         263  
  101         3994  
17              
18 101     101   641 use vars qw($VERSION $STRING_VERSION);
  101         218  
  101         8893  
19             $VERSION = '4.001_052';
20             $STRING_VERSION = $VERSION;
21             ## no critic(BuiltinFunctions::ProhibitStringyEval)
22             $VERSION = eval $VERSION;
23             ## use critic
24              
25             package Marpa::R3::Internal_R;
26              
27 101     101   737 use Scalar::Util qw(blessed tainted);
  101         257  
  101         7935  
28 101     101   742 use English qw( -no_match_vars );
  101         253  
  101         811  
29              
30             our $PACKAGE = 'Marpa::R3::Recognizer';
31              
32             # Given a scanless
33             # recognizer and a symbol,
34             # return the start earley set
35             # and length
36             # of the last such symbol completed,
37             # undef if there was none.
38             sub Marpa::R3::Recognizer::last_completed {
39 86     86   861 my ( $slr, $symbol_name ) = @_;
40 86         501 my ($start, $length) = $slr->call_by_tag(
41             ('@' . __FILE__ . ':' . __LINE__),
42             <<'END_OF_LUA', 'i', $symbol_name);
43             local slr, xsy_name = ...
44             local xsyid = slr.slg:symbol_by_name(xsy_name)
45             if not xsyid then
46             _M.userX(
47             "last_completed(%q): no symbol with that name",
48             xsy_name)
49             end
50             return slr:last_completed(xsyid)
51             END_OF_LUA
52 86 100       296 return if not defined $start;
53 74         287 return $start, $length;
54             } ## end sub Marpa::R3::Recognizer::last_completed
55              
56             # Given a scanless recognizer and
57             # and two earley sets, return the input string
58             sub Marpa::R3::Recognizer::g1_literal {
59 1635     1635   4012 my ( $slr, $g1_start, $g1_count ) = @_;
60              
61 1635         4354 my ($literal) = $slr->call_by_tag(
62             ('@' . __FILE__ . ':' . __LINE__),
63             <<'END_OF_LUA', 'ii', $g1_start, $g1_count);
64             local slr, g1_start, g1_count = ...
65             return slr:g1_literal(g1_start, g1_count)
66             END_OF_LUA
67              
68 1635         7821 return $literal;
69              
70             } ## end sub Marpa::R3::Recognizer::g1_literal
71              
72             # Substring in terms of locations in the input stream
73             # This is the one users will be most interested in.
74             sub Marpa::R3::Recognizer::literal {
75 95     95   664 my ( $slr, $block_id, $offset, $length ) = @_;
76 95         250 my ($literal) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
77             <<'END_OF_LUA', 'iii', $block_id, $offset, $length );
78             local slr, block_id_arg, offset_arg, length_arg = ...
79             local block_id, offset, eoread
80             = slr:block_check_range(block_id_arg, offset_arg, length_arg)
81             if not block_id then
82             -- if block == nil, offset is error message
83             error(offset)
84             end
85             return slr:literal(block_id, offset, eoread-offset)
86             END_OF_LUA
87 95         335 return $literal;
88             }
89              
90             sub Marpa::R3::Internal::meta_recce {
91 288     288 0 851 my ($hash_args) = @_;
92 288         925 state $meta_grammar = Marpa::R3::Internal::meta_grammar();
93 288         1368 $hash_args->{grammar} = $meta_grammar;
94 288         2170 my $self = Marpa::R3::Recognizer->new($hash_args);
95 288         1542 return $self;
96             } ## end sub Marpa::R3::Internal::meta_recce
97              
98             # Set those common args which are at the Perl level.
99             sub perl_common_set {
100 1204     1204   2916 my ( $slr, $flat_args ) = @_;
101 1204 100       3988 if ( my $value = $flat_args->{'trace_file_handle'} ) {
102 10         22 $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE] = $value;
103             }
104 1204         3307 my $trace_file_handle =
105             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
106 1204         2410 delete $flat_args->{'trace_file_handle'};
107 1204         2743 return $flat_args;
108             }
109              
110             sub gen_app_event_handler {
111 6046     6046   13121 my ($slr) = @_;
112 6046         10748 my $event_handlers =
113             $slr->[Marpa::R3::Internal_R::EVENT_HANDLERS];
114             return sub {
115 1333     1333   3807 my ( $event_type, $event_name, @data ) = @_;
116 1333         2737 my $current_event =
117             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT];
118 1333 50       2997 if ($current_event) {
119 0         0 Marpa::R3::exception(
120             qq{Attempt to throw call one event handler inside another\n},
121             qq{ This is not allowed\n},
122             qq{ The currently active handler is for a "$current_event" event\n},
123             qq{ The attempted handler call is for a "$event_name" event\n}
124             );
125             }
126 1333         2716 my $handler = $event_handlers->{$event_name};
127 1333 100       2857 if ( not $handler ) {
128 725         1326 $handler = $event_handlers->{"'default"};
129             }
130 1333 50       2754 if ( not $handler ) {
131 0         0 Marpa::R3::exception(
132             qq{'No event handler for event "$event_name"\n});
133             }
134 1333 50       3872 if ( ref $handler ne 'CODE' ) {
135 0         0 my $ref_type = ref $handler;
136 0         0 Marpa::R3::exception(
137             qq{Bad event handler for event "$event_name"\n},
138             qq{ Handler is a ref to $ref_type\n},
139             qq{ A handler should be a ref to code\n}
140             );
141             }
142 1333         2780 $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] = $event_name;
143 1333   50     4058 my $retour = $handler->( $slr, $event_name, @data ) // 'ok';
144              
145             RETOUR_CHECK: {
146 1333 100       11049 if ($retour eq 'ok') {
  1333         3162  
147 644 50       1375 if ($event_type eq 'before lexeme') {
148 0         0 Marpa::R3::exception(
149             qq{Bad return from event handler for event "$event_name"\n},
150             qq{ Event type was "$event_type"\n},
151             qq{ Return from handler was "$retour"\n},
152             qq{ A handler of type "$event_type" must return "pause"\n},
153             );
154             }
155 644         1304 last RETOUR_CHECK;
156             }
157 689 50       1570 last RETOUR_CHECK if $retour eq 'pause';
158 0         0 Marpa::R3::exception(
159             qq{Bad return from event handler for event "$event_name"\n},
160             qq{ Event type was "$event_type"\n},
161             qq{ Return from handler was "$retour"\n},
162             qq{ Handler must return "ok" or "pause"\n},
163             );
164             }
165 1333         2296 $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] = undef;
166 1333         3941 return 'ok', $retour;
167 6046         59370 };
168             }
169              
170             sub gen_codepoint_event_handler {
171 1691     1691   3787 my ($slr) = @_;
172 1691         3187 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
173 1691         2921 my $character_class_table =
174             $slg->[Marpa::R3::Internal_G::CHARACTER_CLASS_TABLE];
175              
176             return sub {
177 5408     5408   10210 my ( $codepoint, $trace_terminals ) = @_;
178 5408         18786 my $character = pack( 'U', $codepoint );
179 5408         22917 my $is_graphic = ( $character =~ m/[[:graph:]]+/ );
180              
181 5408         9278 my @symbols;
182 5408         7631 for my $entry ( @{$character_class_table} ) {
  5408         11757  
183              
184 223961         319726 my ( $symbol_id, $re ) = @{$entry};
  223961         373345  
185              
186             # say STDERR "Codepoint %x vs $re\n";
187              
188 223961 100       879230 if ( $character =~ $re ) {
189              
190 25330 100       54530 if ( $trace_terminals >= 2 ) {
191 18         203 my $trace_file_handle =
192             $slr
193             ->[ Marpa::R3::Internal_R::TRACE_FILE_HANDLE ];
194 18         52 my $char_desc = character_describe( $slr, $codepoint );
195 18 50       36 say {$trace_file_handle}
  18         108  
196             qq{Registering character $char_desc as symbol $symbol_id: },
197             $slg->l0_symbol_display_form($symbol_id)
198             or Marpa::R3::exception("Could not say(): $ERRNO");
199             } ## end if ( $trace_terminals >= 2 )
200              
201 25330         52848 push @symbols, $symbol_id;
202              
203             } ## end if ( $character =~ $re )
204             } ## end for my $entry ( @{$character_class_table} )
205              
206 5408         17169 my $coro_arg = { symbols => \@symbols };
207 5408 100       15589 $coro_arg->{is_graphic} = 'true' if $is_graphic;
208 5408         14981 return 'ok', $coro_arg;
209 1691         10931 };
210             }
211              
212             sub Marpa::R3::Recognizer::new {
213 1193     1193   247949 my ( $class, @args ) = @_;
214              
215 1193         3009 my $slr = [];
216 1193         2847 bless $slr, $class;
217              
218             # Set recognizer args to default
219             # Lua equivalent is set below
220              
221 1193         5216 my ( $flat_args, $error_message ) = Marpa::R3::flatten_hash_args( \@args );
222 1193 50       4092 Marpa::R3::exception( sprintf $error_message, '$slr->new' )
223             if not $flat_args;
224 1193         4043 $flat_args = perl_common_set( $slr, $flat_args );
225              
226 1193         2711 my $slg = $flat_args->{grammar};
227 1193 50       3303 Marpa::R3::exception(
228             qq{Marpa::R3::Recognizer::new() called without a "grammar" argument} )
229             if not defined $slg;
230 1193         2897 $slr->[Marpa::R3::Internal_R::SLG] = $slg;
231 1193         2533 delete $flat_args->{grammar};
232              
233 1193   100     5358 my $event_handlers = $flat_args->{event_handlers} // {};
234 1193         2852 $slr->[Marpa::R3::Internal_R::EVENT_HANDLERS] = $event_handlers;
235 1193 50       4017 if ( ref $event_handlers ne 'HASH' ) {
236 0         0 my $ref_type = ref $event_handlers;
237 0         0 Marpa::R3::exception(
238             qq{'event_handlers' named argument to new() is $ref_type\n},
239             " It should be a ref to a hash\n",
240             " whose keys are event names and\n",
241             " whose values are code refs\n"
242             );
243             }
244 1193         2315 delete $flat_args->{event_handlers};
245              
246 1193         2398 my $slg_class = 'Marpa::R3::Grammar';
247 1193 50 33     12980 if ( not blessed $slg or not $slg->isa($slg_class) ) {
248 0         0 my $ref_type = ref $slg;
249 0 0       0 my $desc = $ref_type ? "a ref to $ref_type" : 'not a ref';
250 0         0 Marpa::R3::exception(
251             qq{'grammar' named argument to new() is $desc\n},
252             " It should be a ref to $slg_class\n"
253             );
254             } ## end if ( not blessed $slg or not $slg->isa($slg_class) )
255              
256 1193   66     7217 $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE] //=
257             $slg->[Marpa::R3::Internal_G::TRACE_FILE_HANDLE];
258              
259 1193         2495 my $trace_file_handle =
260             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
261              
262 1193         2266 my $lua = $slg->[Marpa::R3::Internal_G::L];
263 1193         2408 $slr->[Marpa::R3::Internal_R::L] = $lua;
264              
265             my ( $regix ) = $slg->coro_by_tag(
266             ( '@' . __FILE__ . ':' . __LINE__ ),
267             {
268             signature => 's',
269             args => [$flat_args],
270             handlers => {
271             perl_undef => sub {
272 2386     2386   11009 return 'sig', [ 'S', undef ];
273             },
274             trace => sub {
275 8     8   21 my ($msg) = @_;
276 8         15 say {$trace_file_handle} $msg;
  8         32  
277 8         56 return 'ok';
278             },
279 1193         10724 event => gen_app_event_handler($slr),
280             }
281             },
282             <<'END_OF_LUA');
283             local slg, flat_args = ...
284             _M.wrap(function ()
285             local slr = slg:slr_new(flat_args)
286             return 'ok', slr.regix
287             end)
288             END_OF_LUA
289              
290 1193         22261 $slr->[Marpa::R3::Internal_R::REGIX] = $regix;
291              
292             $slr->coro_by_tag(
293             ( '@' . __FILE__ . ':' . __LINE__ ),
294             {
295             signature => 's',
296             args => [$flat_args],
297             handlers => {
298             trace => sub {
299 0     0   0 my ($msg) = @_;
300 0         0 say {$trace_file_handle} $msg;
  0         0  
301 0         0 return 'ok';
302             },
303 1193         8589 event => gen_app_event_handler($slr),
304             }
305             },
306             <<'END_OF_LUA');
307             local slr, flat_args = ...
308             _M.wrap(function ()
309             slr:convert_libmarpa_events()
310             return 'ok'
311             end)
312             END_OF_LUA
313              
314 1193         16034 return $slr;
315             } ## end sub Marpa::R3::Recognizer::new
316              
317             sub Marpa::R3::Recognizer::DESTROY {
318             # say STDERR "In Marpa::R3::Recognizer::DESTROY before test";
319 1186     1186   162633 my $slr = shift;
320 1186         2794 my $lua = $slr->[Marpa::R3::Internal_R::L];
321              
322             # If we are destroying the Perl interpreter, then all the Marpa
323             # objects will be destroyed, including Marpa's Lua interpreter.
324             # We do not need to worry about cleaning up the
325             # recognizer is an orderly manner, because the Lua interpreter
326             # containing the recognizer will be destroyed.
327             # In fact, the Lua interpreter may already have been destroyed,
328             # so this test is necessary to avoid a warning message.
329 1186 50       3615 return if not $lua;
330             # say STDERR "In Marpa::R3::Recognizer::DESTROY after test";
331              
332 1186         2871 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
333 1186         4870 $slr->call_by_tag(
334             ('@' . __FILE__ . ':' . __LINE__),
335             <<'END_OF_LUA', '');
336             local slr = ...
337             local regix = slr.regix
338             _M.unregister(_M.registry, regix)
339             END_OF_LUA
340             }
341              
342             sub Marpa::R3::Recognizer::set {
343 11     11   5073 my ( $slr, @args ) = @_;
344              
345 11         193 my ($flat_args, $error_message) = Marpa::R3::flatten_hash_args(\@args);
346 11 50       36 Marpa::R3::exception( sprintf $error_message, '$slr->set()' ) if not $flat_args;
347 11         31 $flat_args = perl_common_set($slr, $flat_args);
348 11         22 my $trace_file_handle =
349             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
350              
351             $slr->coro_by_tag(
352             ( '@' . __FILE__ . ':' . __LINE__ ),
353             {
354             signature => 's',
355             args => [ $flat_args ],
356             handlers => {
357             trace => sub {
358 2     2   5 my ($msg) = @_;
359 2         3 say {$trace_file_handle} $msg;
  2         8  
360 2         7 return 'ok';
361             }
362             }
363             },
364 11         114 <<'END_OF_LUA');
365             local slr, flat_args = ...
366             return _M.wrap(function ()
367             slr:common_set(flat_args)
368             end
369             )
370             END_OF_LUA
371 11         83 return;
372             } ## end sub Marpa::R3::Recognizer::set
373              
374             sub Marpa::R3::Recognizer::read {
375 1198     1198   16244 my ( $slr, $p_string, $start_pos, $length ) = @_;
376 1198 50       4028 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
377 0         0 Marpa::R3::exception(
378             "$slr->read() called from inside a handler\n",
379             " This is not allowed\n",
380             " The event was ",
381             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
382             "\n",
383             );
384             }
385 1198         2381 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
386              
387 1198         4392 my $block_id = $slr->block_new($p_string);
388 1197         5509 $slr->block_set($block_id);
389 1197         4518 $slr->block_move($start_pos, $length);
390 1197         3699 return $slr->block_read();
391             }
392              
393             sub Marpa::R3::Recognizer::resume {
394 549     549   4163 my ( $slr, $start_pos, $length ) = @_;
395 549 50       1362 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
396 0         0 Marpa::R3::exception(
397             "$slr->resume() called from inside a handler\n",
398             " This is not allowed\n",
399             " The event was ",
400             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
401             "\n",
402             );
403             }
404 549         941 my $trace_file_handle =
405             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
406 549   100     2264 $length //= -1;
407 549         1494 $slr->block_move( $start_pos, $length );
408 549         1226 return $slr->block_read();
409             }
410              
411             sub character_describe {
412 18     18   41 my ($slr, $codepoint) = @_;
413              
414 18         68 my ($desc) = $slr->call_by_tag(
415             ('@' . __FILE__ . ':' . __LINE__),
416             <<'END__OF_LUA', 'i', $codepoint );
417             local slr, codepoint = ...
418             return slr:character_describe(codepoint)
419             END__OF_LUA
420              
421 18         49 return $desc;
422             } ## end sub character_describe
423              
424             # This is a Marpa Grammar method, but is included in this
425             # file because internally it is all about the recognizer.
426             sub Marpa::R3::Grammar::parse {
427 2     2   32 my ( $slg, $input_ref, @more_args ) = @_;
428 2 50 33     23 if ( not defined $input_ref or ref $input_ref ne 'SCALAR' ) {
429 0         0 Marpa::R3::exception(
430             q{$slr->parse(): first argument must be a ref to string});
431             }
432 2         11 my @recce_args = ( { grammar => $slg } );
433 2 50       11 if ( grep { ref $_ ne 'HASH' } @more_args ) {
  0         0  
434 0         0 Marpa::R3::exception(
435             q{$slr->parse(): second and later arguments must be ref to HASH});
436             }
437 2         14 my $slr = Marpa::R3::Recognizer->new( @recce_args, @more_args,
438             );
439 2         9 my $input_length = ${$input_ref};
  2         7  
440 2         13 my $length_read = $slr->read($input_ref);
441 2 50       17 if ( $length_read != length $input_length ) {
442 0         0 die 'read in $slr->parse() ended prematurely', "\n",
443             " The input length is $input_length\n",
444             " The length read is $length_read\n",
445             " The cause may be an event\n",
446             " The $slr->parse() method does not allow parses to trigger events";
447             } ## end if ( $length_read != length $input_length )
448 2         25 my $slv = Marpa::R3::Valuer->new( { recognizer => $slr });
449 2         18 my $ambiguity_level = $slv->ambiguity_level();
450 2 50       12 if ( $ambiguity_level != 1 ) {
451 0         0 my $ambiguous_status = $slv->ambiguous();
452 0         0 Marpa::R3::exception( "Parse of the input is ambiguous\n",
453             $ambiguous_status );
454             }
455              
456 2         14 my $value_ref = $slv->value();
457 2 50       13 Marpa::R3::exception(
458             '$slr->parse() read the input, but there was no parse', "\n" )
459             if not $value_ref;
460              
461 2         14 return $value_ref;
462             } ## end sub Marpa::R3::Grammar::parse
463              
464             # Brief description of block/line/column for
465             # an L0 range
466             sub lc_brief {
467 0     0   0 my ( $slr, $pos, $block ) = @_;
468 0   0     0 my ($result) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
469             <<'END_OF_LUA', 'ii', $pos, ($block // -1));
470             local slr, pos, block = ...
471             if block < 0 then block = nil end
472             return slr:lc_brief(block, pos)
473             END_OF_LUA
474 0         0 return $result;
475             }
476              
477             # Brief description of block/line/column for
478             # an L0 range
479             sub lc_range_brief {
480 0     0   0 my ( $slr, $first_block, $first_pos, $last_block, $last_pos ) = @_;
481 0         0 my ($result) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
482             <<'END_OF_LUA', 'iiii', $first_block, $first_pos, $last_block, $last_pos );
483             local slr, block1, pos1, block2, pos2 = ...
484             return slr:lc_range_brief(block1, pos1, block2, pos2)
485             END_OF_LUA
486 0         0 return $result;
487              
488             }
489              
490             sub Marpa::R3::Recognizer::progress_show {
491 19     19   3133 my ( $slr, $start_ordinal, $end_ordinal ) = @_;
492 19         105 my ($text) = $slr->call_by_tag(
493             ( '@' . __FILE__ . ':' . __LINE__ ),
494             <<'END_OF_LUA', 'ii', $start_ordinal, $end_ordinal );
495             local slr, start_ordinal_arg, end_ordinal_arg = ...
496             return slr:progress_show(start_ordinal_arg, end_ordinal_arg )
497             END_OF_LUA
498 19         302 return $text;
499             }
500              
501             sub Marpa::R3::Recognizer::progress {
502 19     19   12517 my ( $slr, $ordinal_arg ) = @_;
503 19   100     87 my ($result) = $slr->call_by_tag(
504             ('@' . __FILE__ . ':' . __LINE__),
505             <<'END_OF_LUA', 'i>0', ($ordinal_arg // -1));
506             local slr, ordinal_arg = ...
507             return slr:progress(ordinal_arg)
508             END_OF_LUA
509 19         64 return $result;
510             }
511              
512             sub Marpa::R3::Recognizer::g1_progress_show {
513 0     0   0 my ( $slr, $start_ordinal, $end_ordinal ) = @_;
514 0         0 my ($text) = $slr->call_by_tag(
515             ( '@' . __FILE__ . ':' . __LINE__ ),
516             <<'END_OF_LUA', 'ii', $start_ordinal, $end_ordinal );
517             local slr, start_ordinal_arg, end_ordinal_arg = ...
518             return slr:g1_progress_show(start_ordinal_arg, end_ordinal_arg )
519             END_OF_LUA
520 0         0 return $text;
521             }
522              
523             sub Marpa::R3::Recognizer::g1_progress {
524 21     21   11234 my ( $slr, $ordinal_arg ) = @_;
525 21   50     84 my ($result) = $slr->call_by_tag(
526             ('@' . __FILE__ . ':' . __LINE__),
527             <<'END_OF_LUA', 'i>0', ($ordinal_arg // -1));
528             local slr, ordinal_arg = ...
529             return slr:g1_progress(ordinal_arg)
530             END_OF_LUA
531 21         315 return $result;
532             }
533              
534             sub Marpa::R3::Recognizer::terminals_expected {
535 35     35   1331 my ($slr) = @_;
536 35         152 my ($results) = $slr->call_by_tag(
537             ('@' . __FILE__ . ':' . __LINE__),
538             <<'END_OF_LUA', '');
539             local slr = ...
540             local slg = slr.slg
541             local g1g = slg.g1
542             local terminals_expected = slr.g1:terminals_expected()
543             local results = {}
544             for ix = 1, #terminals_expected do
545             local g1_symbol_id = terminals_expected[ix]
546             local xsy = g1g:_xsy(g1_symbol_id)
547             if xsy then
548             results[#results+1] = xsy.name
549             end
550             end
551             return results
552             END_OF_LUA
553              
554 35         162 return $results;
555             }
556              
557             sub Marpa::R3::Recognizer::exhausted {
558 18     18   345 my ($slr) = @_;
559 18         71 my ($is_exhausted) = $slr->call_by_tag(
560             ('@' . __FILE__ . ':' . __LINE__),
561             <<'END_OF_LUA', '');
562             local recce = ...
563             local is_exhausted = recce.g1:is_exhausted()
564             return is_exhausted
565             END_OF_LUA
566 18         62 return $is_exhausted;
567             }
568              
569             # Latest and current G1 location are the same
570             sub Marpa::R3::Recognizer::g1_pos {
571 173     173   1957 my ($slr) = @_;
572 173         465 my ($latest_earley_set) = $slr->call_by_tag(
573             ('@' . __FILE__ . ':' . __LINE__),
574             <<'END_OF_LUA', '');
575             local recce = ...
576             local latest_earley_set = recce.g1:latest_earley_set()
577             return latest_earley_set
578             END_OF_LUA
579 173         367 return $latest_earley_set;
580             }
581              
582             sub Marpa::R3::Recognizer::current_earleme {
583 0     0   0 my ($slr) = @_;
584 0         0 my ($current_earleme) = $slr->call_by_tag(
585             ('@' . __FILE__ . ':' . __LINE__),
586             <<'END_OF_LUA', '');
587             local recce = ...
588             local current_earleme = recce.g1:current_earleme()
589             return current_earleme
590             END_OF_LUA
591 0         0 return $current_earleme;
592             }
593              
594             # Not documented, I think
595             sub Marpa::R3::Recognizer::furthest_earleme {
596 0     0   0 my ($slr) = @_;
597 0         0 my ($furthest_earleme) = $slr->call_by_tag(
598             ('@' . __FILE__ . ':' . __LINE__),
599             <<'END_OF_LUA', '');
600             local recce = ...
601             local furthest_earleme = recce.g1:furthest_earleme()
602             return furthest_earleme
603             END_OF_LUA
604 0         0 return $furthest_earleme;
605             }
606              
607             sub Marpa::R3::Recognizer::earleme {
608 0     0   0 my ( $slr, $earley_set_id ) = @_;
609 0         0 my ($earleme) = $slr->call_by_tag(
610             ('@' . __FILE__ . ':' . __LINE__),
611             <<'END_OF_LUA', 'i', $earley_set_id);
612             local recce, earley_set_id = ...
613             local earleme = recce.g1:earleme(earley_set_id)
614             return earleme
615             END_OF_LUA
616 0         0 return $earleme;
617             }
618              
619             sub Marpa::R3::Recognizer::lexeme_alternative_literal {
620 62     62   326 my ( $slr, $symbol_name ) = @_;
621              
622 62 50       128 Marpa::R3::exception(
623             "slr->alternative_literal(): symbol name is undefined\n",
624             " The symbol name cannot be undefined\n"
625             ) if not defined $symbol_name;
626              
627 62         135 my ($ok) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
628             <<'END_OF_LUA', 's', $symbol_name);
629             local slr, symbol_name = ...
630             return slr:lexeme_alternative_literal(symbol_name)
631             END_OF_LUA
632 62 50       220 return 1 if $ok;
633 0         0 return;
634             }
635              
636             sub Marpa::R3::Recognizer::lexeme_alternative {
637 116     116   929 my ( $slr, $symbol_name, $value ) = @_;
638              
639 116 50       371 if ( Scalar::Util::tainted( $value ) ) {
640 0         0 Marpa::R3::exception(
641             "Problem in Marpa::R3: Attempt to use a tainted token value\n",
642             "Marpa::R3 is insecure for use with tainted data\n"
643             );
644             }
645              
646             Marpa::R3::exception(
647 116 50       270 "slr->alternative(): symbol name is undefined\n",
648             " The symbol name cannot be undefined\n"
649             ) if not defined $symbol_name;
650              
651 116         159 my $ok;
652 116 50       242 if (defined $value) {
653 116         316 ($ok) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
654             <<'END_OF_LUA', 'sS', $symbol_name, $value );
655             local slr, symbol_name, token_sv = ...
656             return slr:lexeme_alternative(symbol_name, token_sv)
657             END_OF_LUA
658             } else {
659 0         0 ($ok) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
660             <<'END_OF_LUA', 's', $symbol_name );
661             local slr, symbol_name = ...
662             return slr:lexeme_alternative_undef(symbol_name )
663             END_OF_LUA
664             }
665              
666 114 50       404 return 1 if $ok;
667 0         0 return;
668             }
669              
670             # Returns 0 on unthrown failure, current location on success
671             sub Marpa::R3::Recognizer::lexeme_complete {
672 168     168   814 my ( $slr, $block, $offset, $length ) = @_;
673 168 50       396 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
674 0         0 Marpa::R3::exception(
675             "$slr->lexeme_complete() called from inside a handler\n",
676             " This is not allowed\n",
677             " The event was ",
678             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
679             "\n",
680             );
681             }
682              
683 168         270 my $trace_file_handle =
684             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
685              
686             my ($return_value) = $slr->coro_by_tag(
687             ( '@' . __FILE__ . ':' . __LINE__ ),
688             {
689             signature => 'iii',
690             args => [ $block, $offset, $length ],
691             handlers => {
692             trace => sub {
693 0     0   0 my ($msg) = @_;
694 0         0 say {$trace_file_handle} $msg;
  0         0  
695 0         0 return 'ok';
696             },
697 168         946 event => gen_app_event_handler($slr),
698             }
699             },
700             <<'END_OF_LUA');
701             local slr, block_id_arg, offset_arg, length_arg = ...
702             local block_id, offset, eoread
703             = slr:block_check_range(block_id_arg, offset_arg, length_arg)
704             _M.wrap(function ()
705             local new_offset = slr:lexeme_complete(block_id, offset, eoread-offset)
706             slr:convert_libmarpa_events()
707             return 'ok', new_offset
708             end
709             )
710             END_OF_LUA
711              
712 168         1979 return $return_value;
713              
714             } ## end sub Marpa::R3::Recognizer::lexeme_complete
715              
716             # Returns 0 on unthrown failure, current location on success,
717             # undef if lexeme not accepted.
718             sub Marpa::R3::Recognizer::lexeme_read_literal {
719 116     116   628 my ( $slr, $symbol_name, $block_id, $offset, $length ) = @_;
720 116 50       247 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
721 0         0 Marpa::R3::exception(
722             "$slr->lexeme_read_literal() called from inside a handler\n",
723             " This is not allowed\n",
724             " The event was ",
725             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
726             "\n",
727             );
728             }
729             my ($ok, $return_value) = $slr->coro_by_tag(
730             ( '@' . __FILE__ . ':' . __LINE__ ),
731             {
732             signature => 'siii',
733             args => [ $symbol_name, $block_id, $offset, $length ],
734             handlers => {
735             trace => sub {
736 0     0   0 my ($msg) = @_;
737 0         0 my $trace_file_handle =
738             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
739 0         0 say {$trace_file_handle} $msg;
  0         0  
740 0         0 return 'ok';
741             },
742 116         619 codepoint => gen_codepoint_event_handler($slr),
743             event => gen_app_event_handler($slr),
744             }
745             },
746             <<'END_OF_LUA');
747             local slr, symbol_name, block_id, offset, length = ...
748             _M.wrap(function ()
749             local offset = slr:lexeme_read_literal(symbol_name, block_id, offset, length )
750             if not offset then return 'ok', 0 end
751             return 'ok', 1, offset
752             end
753             )
754             END_OF_LUA
755              
756 116 50       1556 return if not $ok;
757 116         290 return $return_value;
758             }
759              
760             # Returns 0 on unthrown failure, current location on success,
761             # undef if lexeme not accepted.
762             sub Marpa::R3::Recognizer::lexeme_read_block {
763 243     243   6611 my ( $slr, $symbol_name, $value, $block_id, $offset, $length ) = @_;
764 243 50       663 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
765 0         0 Marpa::R3::exception(
766             "$slr->lexeme_read_block() called from inside a handler\n",
767             " This is not allowed\n",
768             " The event was ",
769             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
770             "\n",
771             );
772             }
773 243 50       792 if ( Scalar::Util::tainted( $value ) ) {
774 0         0 Marpa::R3::exception(
775             "Problem in Marpa::R3: Attempt to use a tainted token value\n",
776             "Marpa::R3 is insecure for use with tainted data\n"
777             );
778             }
779             my ($ok, $return_value) = $slr->coro_by_tag(
780             ( '@' . __FILE__ . ':' . __LINE__ ),
781             {
782             signature => 'sSiii',
783             args => [ $symbol_name, $value, $block_id, $offset, $length ],
784             handlers => {
785             trace => sub {
786 0     0   0 my ($msg) = @_;
787 0         0 my $trace_file_handle =
788             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
789 0         0 say {$trace_file_handle} $msg;
  0         0  
790 0         0 return 'ok';
791             },
792 243         1731 codepoint => gen_codepoint_event_handler($slr),
793             event => gen_app_event_handler($slr),
794             }
795             },
796             <<'END_OF_LUA');
797             local slr, symbol_name, token_sv, block_id, offset, length = ...
798             _M.wrap(function ()
799             local offset = slr:lexeme_read_block(symbol_name, token_sv, block_id, offset, length )
800             if not offset then return 'ok', 0 end
801             return 'ok', 1, offset
802             end
803             )
804             END_OF_LUA
805              
806 243 50       4203 return if not $ok;
807 243         824 return $return_value;
808             }
809              
810             # Returns 0 on unthrown failure, current location on success,
811             # undef if lexeme not accepted.
812             sub Marpa::R3::Recognizer::lexeme_read_string {
813 36     36   1591 my ( $slr, $symbol_name, $string ) = @_;
814 36 50       80 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
815 0         0 Marpa::R3::exception(
816             '$recce->lexeme_read_string() called from inside a handler', "\n",
817             " This is not allowed\n",
818             " The event was ",
819             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
820             "\n",
821             );
822             }
823              
824             my ($ok, $return_value) = $slr->coro_by_tag(
825             ( '@' . __FILE__ . ':' . __LINE__ ),
826             {
827             signature => 'ss',
828             args => [ $symbol_name, $string ],
829             handlers => {
830             trace => sub {
831 0     0   0 my ($msg) = @_;
832 0         0 my $trace_file_handle =
833             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
834 0         0 say {$trace_file_handle} $msg;
  0         0  
835 0         0 return 'ok';
836             },
837 36         198 codepoint => gen_codepoint_event_handler($slr),
838             event => gen_app_event_handler($slr),
839             }
840             },
841             <<'END_OF_LUA');
842             local slr, symbol_name, input_string = ...
843             _M.wrap(function ()
844             local offset = slr:lexeme_read_string(symbol_name, input_string )
845             if not offset then return 'ok', 0 end
846             return 'ok', 1, offset
847             end
848             )
849             END_OF_LUA
850              
851 36 100       473 return if not $ok;
852 35         94 return $return_value;
853              
854             }
855              
856             sub Marpa::R3::Recognizer::g1_to_block_first {
857 56     56   1312 my ( $slr, $g1_pos ) = @_;
858 56         219 return $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
859             <<'END_OF_LUA', 'i', $g1_pos );
860             local slr, g1_pos = ...
861             g1_pos = math.tointeger(g1_pos)
862             if not g1_pos then
863             _M.userX(
864             "g1_to_block_first(%s): argument must be an integer",
865             g1_pos)
866             end
867             return slr:g1_to_block_first(g1_pos)
868             END_OF_LUA
869             }
870              
871             sub Marpa::R3::Recognizer::g1_to_block_last {
872 51     51   196 my ( $slr, $g1_pos ) = @_;
873 51         143 return $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
874             <<'END_OF_LUA', 'i', $g1_pos );
875             local slr, g1_pos = ...
876             g1_pos = math.tointeger(g1_pos)
877             if not g1_pos then
878             _M.userX(
879             "g1_to_block_last(%s): argument must be an integer",
880             g1_pos)
881             end
882             return slr:g1_to_block_last(g1_pos)
883             END_OF_LUA
884             }
885              
886             # TODO -- Document this method ??
887             sub Marpa::R3::Recognizer::lc_brief {
888 36     36   97 my ( $slr, $first_block, $first_pos, $last_block, $last_pos ) = @_;
889 36         122 my ($desc) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
890             <<'END_OF_LUA', 'iiii', $first_block, $first_pos, $last_block, $last_pos );
891             local slr, first_block, first_pos, last_block, last_pos = ...
892             local function usage()
893             error(
894             "usage: $recce->lc_brief(first_block, first_pos, [last_block, last_pos])"
895             )
896             end
897             if not first_block or not first_pos then
898             return usage()
899             end
900             if last_block == nil or last_pos == nil then
901             if last_block ~= nil or last_pos ~= nil then
902             return usage()
903             end
904             last_block = first_block
905             last_pos = first_pos
906             end
907             return slr:lc_range_brief(
908             first_block, first_pos, last_block, last_pos)
909             END_OF_LUA
910 36         127 return $desc;
911             }
912              
913             sub Marpa::R3::Recognizer::line_column {
914 131     131   1012 my ( $slr, $block, $pos, ) = @_;
915 131   33     375 $pos //= $slr->pos();
916 131   50     277 $block //= -1;
917              
918 131         405 my ($line_no, $column_no) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
919             <<'END_OF_LUA', 'ii', $block, $pos );
920             local slr, block, pos = ...
921             if block <= 0 then block = slr.current_block.index end
922             local _, line_no, column_no = slr:per_pos(block, pos)
923             return line_no, column_no
924             END_OF_LUA
925              
926 131         427 return $line_no, $column_no;
927             } ## end sub Marpa::R3::Recognizer::line_column
928              
929             sub Marpa::R3::Recognizer::block_new {
930 1297     1297   3406 my ( $slr, $p_string ) = @_;
931 1297         2548 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
932              
933             Marpa::R3::exception(
934             q{Attempt to use a tainted input string in $slr->read()},
935             qq{\n Marpa::R3 is insecure for use with tainted data\n}
936 1297 100       2256 ) if Scalar::Util::tainted( ${$p_string} );
  1297         5989  
937              
938 1296 50       5324 if ( ( my $ref_type = ref $p_string ) ne 'SCALAR' ) {
939 0 0       0 my $desc = $ref_type ? "a ref to $ref_type" : 'not a ref';
940 0         0 Marpa::R3::exception(
941             qq{Arg to Marpa::R3::Recognizer::read() is $desc\n},
942             ' It should be a ref to scalar' );
943             } ## end if ( ( my $ref_type = ref $p_string ) ne 'SCALAR' )
944              
945 1296 50       2304 if ( not defined ${$p_string} ) {
  1296         3641  
946 0         0 Marpa::R3::exception(
947             qq{Arg to Marpa::R3::Recognizer::read() is a ref to an undef\n},
948             ' It should be a ref to a defined scalar' );
949             } ## end if ( ( my $ref_type = ref $p_string ) ne 'SCALAR' )
950              
951 1296         3074 my $character_class_table =
952             $slg->[Marpa::R3::Internal_G::CHARACTER_CLASS_TABLE];
953              
954             my ($block_id) = $slr->coro_by_tag(
955             ( '@' . __FILE__ . ':' . __LINE__ ),
956             {
957             signature => 's',
958 1296         2787 args => [ ${$p_string} ],
  1296         4998  
959             handlers => {
960             codepoint => gen_codepoint_event_handler($slr),
961             event => gen_app_event_handler($slr),
962             },
963             },
964             <<'END_OF_LUA');
965             local slr, input_string = ...
966             local new_block_id
967             _M.wrap(function()
968             new_block_id = slr:block_new(input_string)
969             return 'ok', new_block_id
970             end
971             )
972             END_OF_LUA
973              
974 1296         24258 return $block_id;
975             }
976              
977             sub Marpa::R3::Recognizer::block_progress {
978 611     611   30920 my ($slr, $block_id) = @_;
979 611         1077 my ($l0_pos, $l0_end);
980 611         1846 ($block_id, $l0_pos, $l0_end)
981             = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
982             <<'END_OF_LUA', 'i', $block_id );
983             local slr, block_id_arg = ...
984             local block_id, erreur = slr:block_check_id(block_id_arg)
985             if not block_id then
986             error(erreur)
987             end
988             local l0_pos, l0_end
989             block_id, l0_pos, l0_end = slr:block_progress(block_id)
990             return block_id, l0_pos, l0_end
991             END_OF_LUA
992 611         1863 return $block_id, $l0_pos, $l0_end;
993             }
994              
995             sub Marpa::R3::Recognizer::block_set {
996 1341     1341   5841 my ($slr, $block_id) = @_;
997 1341 50       4275 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
998 0         0 Marpa::R3::exception(
999             "$slr->block_set() called from inside a handler\n",
1000             " This is not allowed\n",
1001             " The event was ",
1002             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
1003             "\n",
1004             );
1005             }
1006 1341         5971 $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1007             <<'END_OF_LUA', 'i', $block_id );
1008             local slr, block_id_arg = ...
1009             local block_id, erreur = slr:block_check_id(block_id_arg)
1010             if not block_id then
1011             error(erreur)
1012             end
1013             return slr:block_set(block_id)
1014             END_OF_LUA
1015 1341         2975 return;
1016             }
1017              
1018             # block_id defaults to current block
1019             # block_offset defaults to don't set offset
1020             # length defaults to don't set eoread
1021             sub Marpa::R3::Recognizer::block_move {
1022 2142     2142   7662 my ($slr, $offset, $length) = @_;
1023 2142         7421 $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1024             <<'END_OF_LUA', 'ii', $offset, $length );
1025             local slr, offset_arg, length_arg = ...
1026             local ok, offset, eoread
1027             = slr:block_check_range(nil, offset_arg, length_arg)
1028             if not ok then
1029             -- new_block_offset is error message
1030             error(offset)
1031             end
1032             -- we don't set offset if the arg was nil
1033             local new_offset = offset_arg and offset or nil
1034             -- we don't set eoread if the length arg was nil
1035             local new_eoread = length_arg and eoread or nil
1036             return slr:block_move(new_offset, new_eoread)
1037             END_OF_LUA
1038 2142         4689 return;
1039             }
1040              
1041             sub Marpa::R3::Recognizer::block_read {
1042 1801     1801   4918 my ($slr ) = @_;
1043             my ($offset) = $slr->coro_by_tag(
1044             ( '@' . __FILE__ . ':' . __LINE__ ),
1045             {
1046             signature => '',
1047             args => [],
1048             handlers => {
1049             trace => sub {
1050 314     314   732 my ($msg) = @_;
1051 314         623 my $trace_file_handle =
1052             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
1053 314         459 say {$trace_file_handle} $msg;
  314         1178  
1054 314         934 return 'ok';
1055             },
1056 1801         12417 event => gen_app_event_handler($slr),
1057             }
1058             },
1059             <<'END_OF_LUA');
1060             local slr = ...
1061             _M.wrap(function ()
1062             local offset = slr:block_read()
1063             return 'ok', offset
1064             end
1065             )
1066             END_OF_LUA
1067 1792         32420 return $offset;
1068             }
1069              
1070             sub Marpa::R3::Recognizer::input_length {
1071 2     2   1801 my ( $slr, $block_id ) = @_;
1072 2   100     19 my ($length) = $slr->call_by_tag(
1073             ('@' . __FILE__ . ':' . __LINE__),
1074             <<'END_OF_LUA', 'i', ($block_id // -1));
1075             local slr, block_id = ...
1076             local block = block_id > 0 and slr.inputs[block_id] or slr.current_block
1077             return #block
1078             END_OF_LUA
1079              
1080 2         11 return $length;
1081             }
1082              
1083             # no return value documented
1084             sub Marpa::R3::Recognizer::activate {
1085 536     536   2134 my ( $slr, $event_name, $activate ) = @_;
1086 536         849 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
1087              
1088 536         1476 $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1089             <<'END_OF_LUA', 'si', $event_name, $activate);
1090             local slr, event_name, activate = ...
1091             if not activate then
1092             activate = 1
1093             else
1094             activate = activate ~= 0
1095             end
1096             -- print('$slr->activate():', event_name, activate)
1097             return slr:activate_by_event_name(event_name, activate)
1098             END_OF_LUA
1099 536         1267 return;
1100             }
1101              
1102             # On success, returns the old priority value.
1103             # Failures are thrown.
1104             sub Marpa::R3::Recognizer::lexeme_priority_set {
1105 12     12   70 my ( $slr, $lexeme_name, $new_priority ) = @_;
1106 12         184 my ($old_priority) = $slr->call_by_tag(
1107             ('@' . __FILE__ . ':' . __LINE__),
1108             <<'END_OF_LUA', 'si>*', $lexeme_name, $new_priority );
1109             local recce, lexeme_name, new_priority = ...
1110             local slg = recce.slg
1111             local g1g = slg.g1
1112             local lexeme_id = g1g.isyid_by_name[lexeme_name]
1113             if not lexeme_id then
1114             _M.userX(
1115             "lexeme_priority_set(): no such symbol as %q",
1116             lexeme_name
1117             )
1118             end
1119             if type(new_priority) ~= 'number' then
1120             _M.userX(
1121             "lexeme_priority_set(): priority is not a number, it is %s",
1122             new_priority
1123             )
1124             end
1125             local g_lexeme_data = slg.g1.isys[lexeme_id]
1126             local r_lexeme_data = recce.g1_isys[lexeme_id]
1127             if not g_lexeme_data.lexeme then
1128             print(inspect(lexeme_data))
1129             _M.userX(
1130             "lexeme_priority_set(): %q is not a lexeme",
1131             lexeme_name
1132             )
1133             end
1134             local old_priority = r_lexeme_data.lexeme_priority
1135             r_lexeme_data.lexeme_priority = new_priority
1136             return old_priority
1137             END_OF_LUA
1138              
1139 12         33 return $old_priority;
1140             }
1141              
1142             # Internal methods, not to be documented
1143              
1144             # not to be documented
1145             sub Marpa::R3::Recognizer::call_by_tag {
1146 8649     8649   34195 my ( $slr, $tag, $codestr, $signature, @args ) = @_;
1147 8649         14774 my $lua = $slr->[Marpa::R3::Internal_R::L];
1148 8649         13166 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
1149              
1150 8649 50       18831 $DB::single = 1 if not $slr;
1151 8649 50       15907 $DB::single = 1 if not $regix;
1152             # $DB::single = 1 if grep { not defined $_ } @args;
1153 8649         18807 my @results;
1154             my $eval_error;
1155 8649         0 my $eval_ok;
1156             {
1157 8649         11593 local $@;
  8649         12186  
1158 8649         14510 $eval_ok = eval {
1159 8649         352363 @results =
1160             $lua->call_by_tag( $regix, $tag, $codestr, $signature, @args );
1161 8647         22522 return 1;
1162             };
1163 8649         19192 $eval_error = $@;
1164             }
1165 8649 100       20437 if ( not $eval_ok ) {
1166 2         6 Marpa::R3::exception($eval_error);
1167             }
1168 8647         29390 return @results;
1169             }
1170              
1171             # not to be documented
1172             sub Marpa::R3::Recognizer::coro_by_tag {
1173 6051     6051   16394 my ( $slr, $tag, $args, $codestr ) = @_;
1174 6051         10930 my $lua = $slr->[Marpa::R3::Internal_R::L];
1175 6051         9598 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
1176 6051   50     16226 my $handler = $args->{handlers} // {};
1177 6051         13865 my $resume_tag = $tag . '[R]';
1178 6051   50     14440 my $signature = $args->{signature} // '';
1179 6051   50     13612 my $p_args = $args->{args} // [];
1180              
1181 6051         14442 my @results;
1182             my $eval_error;
1183 6051         0 my $eval_ok;
1184             {
1185 6051         9027 local $@;
  6051         8849  
1186 6051         11351 $eval_ok = eval {
1187 6051         10320 $lua->call_by_tag( $regix, $tag, $codestr, $signature, @{$p_args} );
  6051         115479  
1188 6051         19358 my @resume_args = ('');
1189 6051         10481 my $signature = 's';
1190 6051         9148 CORO_CALL: while (1) {
1191 13108         8901966 my ( $cmd, $yield_data ) =
1192             $lua->call_by_tag( $regix, $resume_tag,
1193             'local slr, resume_arg = ...; return _M.resume(resume_arg)',
1194             $signature, @resume_args ) ;
1195 13099 100       51884 if (not $cmd) {
1196 6042         9685 @results = @{$yield_data};
  6042         14029  
1197 6042         21976 return 1;
1198             }
1199 7057         15911 my $handler = $handler->{$cmd};
1200 7057 50       15052 Marpa::R3::exception(qq{No coro handler for "$cmd"})
1201             if not $handler;
1202 7057   50     14274 $yield_data //= [];
1203 7057         10695 my ($handler_cmd, $new_resume_args) = $handler->(@{$yield_data});
  7057         17698  
1204 7057 50       17235 Marpa::R3::exception(qq{Undefined return command from handler for "$cmd"})
1205             if not defined $handler_cmd;
1206 7057 50       15534 if ($handler_cmd eq 'ok') {
1207 7057         11312 $signature = 's';
1208 7057         21388 @resume_args = ($new_resume_args);
1209 7057 50       16602 if (scalar @resume_args < 1) {
1210 0         0 @resume_args = ('');
1211             }
1212 7057         18456 next CORO_CALL;
1213             }
1214 0 0       0 if ($handler_cmd eq 'sig') {
1215 0         0 @resume_args = @{$new_resume_args};
  0         0  
1216 0         0 $signature = shift @resume_args;
1217 0         0 next CORO_CALL;
1218             }
1219 0         0 Marpa::R3::exception(qq{Bad return command ("$handler_cmd") from handler for "$cmd"})
1220             }
1221 0         0 return 1;
1222             };
1223 6051         15052 $eval_error = $@;
1224             }
1225 6051 100       14677 if ( not $eval_ok ) {
1226             # if it's an object, just die
1227 9 50       41 die $eval_error if ref $eval_error;
1228 9         47 Marpa::R3::exception($eval_error);
1229             }
1230 6042         18755 return @results;
1231             }
1232              
1233             # not to be documented
1234             sub Marpa::R3::Recognizer::earley_set_size {
1235 78     78   348 my ($slr, $set_id) = @_;
1236 78   50     238 my ($size) = $slr->call_by_tag(
1237             ('@' . __FILE__ . ':' . __LINE__),
1238             <<'END_OF_LUA', 'i', ($set_id // -1));
1239             local recce, set_id = ...
1240             local g1r = recce.g1
1241             if set_id < 0 then set_id = g1r:lastest_earley_set() end
1242             return g1r:_earley_set_size(set_id)
1243             END_OF_LUA
1244 78         180 return $size;
1245             }
1246              
1247             # not to be documented
1248             sub Marpa::R3::Recognizer::earley_sets_show {
1249 8     8   2955 my ($slr) = @_;
1250              
1251 8         38 my ($last_completed_earleme, $furthest_earleme) = $slr->call_by_tag(
1252             ('@' . __FILE__ . ':' . __LINE__),
1253             <<'END_OF_LUA', '');
1254             local recce = ...
1255             local g1r = recce.g1
1256             return g1r:current_earleme(), g1r:furthest_earleme()
1257             END_OF_LUA
1258              
1259 8         49 my $text = "Last Completed: $last_completed_earleme; "
1260             . "Furthest: $furthest_earleme\n";
1261 8         22 LIST: for ( my $ix = 0;; $ix++ ) {
1262 67         278 my $set_desc =
1263             $slr->Marpa::R3::Recognizer::earley_set_show( $ix );
1264 67 100       207 last LIST if not $set_desc;
1265 59         539 $text .= "Earley Set $ix\n$set_desc";
1266             }
1267 8         87 return $text;
1268             }
1269              
1270             # not to be documented
1271             sub Marpa::R3::Recognizer::earley_set_show {
1272 67     67   151 my ( $slr, $traced_set_id ) = @_;
1273 67         404 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
1274              
1275 67         174 my ($set_data) =
1276             $slr->call_by_tag(
1277             ('@' . __FILE__ . ':' . __LINE__),
1278             <<'END_OF_LUA', 'i>2', $traced_set_id );
1279             local recce, traced_set_id = ...
1280             return recce:g1_earley_set_data(traced_set_id)
1281             END_OF_LUA
1282              
1283 67 100       171 return if not $set_data;
1284 59         85 my %set_data = @{$set_data};
  59         404  
1285              
1286 59         129 my $current_earleme = $set_data{earleme};
1287              
1288 59         95 my @sorted_data = ();
1289              
1290 59         97 EARLEY_ITEM: for ( my $item_id = 0 ; ; $item_id++ ) {
1291              
1292 549         878 my $item_data = $set_data{ $item_id + 1 };
1293 549 100       977 last EARLEY_ITEM if not defined $item_data;
1294              
1295 490         546 my %item_data = @{$item_data};
  490         1954  
1296              
1297 490         797 my $nrl_id = $item_data{nrl_id};
1298 490         600 my $dot_position = $item_data{dot_position};
1299 490         614 my $ahm_desc;
1300 490 100       986 if ( $dot_position < 0 ) {
1301 207         576 $ahm_desc = sprintf( 'R%d$', $nrl_id );
1302             }
1303             else {
1304 283         778 $ahm_desc = sprintf( 'R%d:%d', $nrl_id, $dot_position );
1305             }
1306 490         659 my $ahm_id_of_yim = $item_data{ahm_id_of_yim};
1307 490         571 my $origin_earleme = $item_data{origin_earleme};
1308              
1309 490         1168 my $text .= sprintf "ahm%d: %s@%d-%d", $ahm_id_of_yim,
1310             $ahm_desc,
1311             $origin_earleme, $current_earleme;
1312              
1313 490         808 my @lines = $text;
1314 490         1556 push @lines,
1315             qq{ }
1316             . $ahm_desc . q{: }
1317             . $slg->dotted_nrl_show( $nrl_id, $dot_position );
1318              
1319 490         882 push @sorted_data, @lines;
1320              
1321             # Token links
1322             {
1323 490         630 my @sort_data = ();
1324 490         590 my @lines = ();
1325 490         717 my $token_links = $item_data{token_links};
1326 490         541 my %token_links = @{$token_links};
  490         799  
1327 490         716 TOKEN_LINK: for ( my $token_link_ix = 0 ; ; $token_link_ix++ ) {
1328 557         925 my $token_link_data = $token_links{ $token_link_ix + 1 };
1329 557 100       1479 last TOKEN_LINK if not $token_link_data;
1330 67         105 my %token_link_data = @{$token_link_data};
  67         264  
1331              
1332 67         109 my $predecessor_ahm = $token_link_data{predecessor_ahm};
1333 67         88 my $origin_earleme = $token_link_data{origin_earleme};
1334 67         84 my $middle_earleme = $token_link_data{middle_earleme};
1335 67         96 my $middle_set_id = $token_link_data{middle_set_id};
1336 67         99 my $token_name = $token_link_data{token_name};
1337 67         85 my $token_id = $token_link_data{token_id};
1338 67         92 my $value_ix = $token_link_data{value_ix};
1339 67         95 my $value = $token_link_data{value};
1340             my $source_predecessor_state =
1341 67         96 $token_link_data{source_predecessor_state};
1342              
1343 67         89 my @pieces = ();
1344 67 50       143 if ( defined $predecessor_ahm ) {
1345 67         187 my $ahm_desc = $slg->briefer_ahm($predecessor_ahm);
1346 67         190 push @pieces,
1347             'c='
1348             . $ahm_desc . q{@}
1349             . $origin_earleme . q{-}
1350             . $middle_earleme;
1351             } ## end if ( defined $predecessor_ahm )
1352              
1353 67         125 push @pieces, 's=' . $token_name;
1354              
1355 67 50       144 if ( not defined $value ) {
1356              
1357             # Value is literal
1358 67         106 my $token_length = $current_earleme - $middle_earleme;
1359 67         167 $value = $slr->g1_literal( $middle_earleme, $token_length );
1360             }
1361 67         359 my $token_dump =
1362             Data::Dumper->new( [ \$value ] )->Terse(1)->Dump;
1363 67         3426 chomp $token_dump;
1364 67         163 push @pieces, "t=$token_dump";
1365 67         181 my $token_link_desc = '[' . ( join '; ', @pieces ) . ']';
1366 67         253 push @sort_data,
1367             [
1368             $middle_set_id, $token_id,
1369             $predecessor_ahm, $token_link_desc
1370             ];
1371             }
1372 67         294 push @sorted_data, map { qq{ } . $_->[-1] } sort {
1373 490 0 0     1001 $a->[0] <=> $b->[0]
  0         0  
1374             || $a->[1] <=> $b->[1]
1375             || $a->[2] <=> $b->[2]
1376             } @sort_data;
1377             }
1378              
1379             # Completion links
1380             {
1381 490         651 my @sort_data = ();
  490         580  
1382 490         587 my @lines = ();
1383 490         671 my $completion_links = $item_data{completion_links};
1384 490         567 my %completion_links = @{$completion_links};
  490         921  
1385             TOKEN_LINK:
1386 490         685 for ( my $completion_link_ix = 0 ; ; $completion_link_ix++ ) {
1387             my $completion_link_data =
1388 757         1117 $completion_links{ $completion_link_ix + 1 };
1389 757 100       1351 last TOKEN_LINK if not $completion_link_data;
1390 267         311 my %completion_link_data = @{$completion_link_data};
  267         737  
1391              
1392             my $predecessor_ahm_id =
1393 267         416 $completion_link_data{predecessor_state};
1394 267         339 my $ahm_id = $completion_link_data{ahm_id};
1395 267         366 my $origin_earleme = $completion_link_data{origin_earleme};
1396 267         323 my $middle_earleme = $completion_link_data{middle_earleme};
1397 267         647 my $ahm_desc = $slg->briefer_ahm($ahm_id);
1398              
1399 267         408 my @pieces = ();
1400 267 50       498 if ( defined $predecessor_ahm_id ) {
1401 267         535 my $predecessor_ahm_desc =
1402             $slg->briefer_ahm($predecessor_ahm_id);
1403 267         688 push @pieces,
1404             'p='
1405             . $predecessor_ahm_desc . '@'
1406             . $origin_earleme . q{-}
1407             . $middle_earleme;
1408             }
1409              
1410 267         492 push @pieces,
1411             'c='
1412             . $ahm_desc . q{@}
1413             . $middle_earleme . q{-}
1414             . $current_earleme;
1415 267         550 my $link_desc = '[' . ( join '; ', @pieces ) . ']';
1416              
1417 267   50     1054 push @sort_data,
1418             [
1419             $middle_earleme, $ahm_id,
1420             ( $predecessor_ahm_id // -1 ), $link_desc
1421             ];
1422             }
1423 267         999 push @sorted_data, map { q{ } . $_->[-1] } sort {
1424 490 50 66     917 $a->[0] <=> $b->[0]
  27         137  
1425             || $a->[1] <=> $b->[1]
1426             || $a->[2] <=> $b->[2]
1427             } @sort_data;
1428             }
1429              
1430             # Leo links
1431             {
1432 490         579 my @sort_data = ();
  490         646  
  490         630  
1433 490         575 my @lines = ();
1434 490         699 my $leo_links = $item_data{leo_links};
1435 490         565 my %leo_links = @{$leo_links};
  490         705  
1436             LEO_LINK:
1437 490         944 for ( my $leo_link_ix = 0 ; ; $leo_link_ix++ ) {
1438 498         690 my $leo_link_data = $leo_links{ $leo_link_ix + 1 };
1439 498 100       917 last LEO_LINK if not $leo_link_data;
1440 8         13 my %leo_link_data = @{$leo_link_data};
  8         23  
1441              
1442 8         13 my $middle_earleme = $leo_link_data{middle_earleme};
1443 8         16 my $middle_set_id = $leo_link_data{middle_set_id};
1444             my $leo_transition_symbol =
1445 8         16 $leo_link_data{leo_transition_symbol};
1446 8         11 my $ahm_id = $leo_link_data{ahm_id};
1447 8         24 my $ahm_desc = $slg->briefer_ahm($ahm_id);
1448              
1449 8         18 my @pieces = ();
1450 8         26 push @pieces,
1451             'l=L' . $leo_transition_symbol . q{@} . $middle_earleme;
1452 8         19 push @pieces,
1453             'c='
1454             . $ahm_desc . q{@}
1455             . $middle_earleme . q{-}
1456             . $current_earleme;
1457 8         23 my $link_desc = '[' . ( join '; ', @pieces ) . ']';
1458              
1459 8         31 push @sort_data,
1460             [
1461             $middle_set_id, $ahm_id,
1462             $leo_transition_symbol, $link_desc,
1463             ];
1464             }
1465 8         49 push @sorted_data, map { q{ } . $_->[-1] } sort {
1466 490 0 0     1522 $a->[0] <=> $b->[0]
  0         0  
1467             || $a->[1] <=> $b->[1]
1468             || $a->[2] <=> $b->[2]
1469             } @sort_data;
1470             }
1471             }
1472              
1473             # Leo items
1474             {
1475 59         78 my $leo_data = $set_data{leo};
  59         98  
1476 59         77 my %leo_data = @{$leo_data};
  59         98  
1477 59         91 my @sort_data = ();
1478 59         119 LEO_ITEM: for ( my $leo_item_id = 0 ; ; $leo_item_id++ ) {
1479              
1480 67         105 my $leo_item_data = $leo_data{ $leo_item_id + 1 };
1481 67 100       184 last LEO_ITEM if not defined $leo_item_data;
1482              
1483 8         9 my %leo_item_data = @{$leo_item_data};
  8         30  
1484 8         14 my $postdot_symbol_id = $leo_item_data{postdot_symbol_id};
1485 8         14 my $postdot_symbol_name = $leo_item_data{postdot_symbol_name};
1486 8         11 my $predecessor_symbol_id = $leo_item_data{predecessor_symbol_id};
1487 8         8 my $base_origin_earleme = $leo_item_data{base_origin_earleme};
1488 8         13 my $leo_base_state = $leo_item_data{leo_base_state};
1489 8         12 my $trace_earleme = $leo_item_data{trace_earleme};
1490              
1491             # L2@8 ["Expression"; L2@6; S16@6-8]
1492 8         21 my @link_texts = ( q{"} . $postdot_symbol_name . q{"} );
1493 8 100       20 if ( defined $predecessor_symbol_id ) {
1494 6         14 push @link_texts,
1495             sprintf( 'L%d@%d',
1496             $predecessor_symbol_id, $base_origin_earleme );
1497             }
1498 8         19 push @link_texts,
1499             sprintf( 'S%d@%d-%d',
1500             $leo_base_state, $base_origin_earleme, $trace_earleme );
1501 8         26 my $leo_line = sprintf( 'L%d@%d [%s]',
1502             $postdot_symbol_id, $trace_earleme,
1503             ( join q{; }, @link_texts ) );
1504 8         18 push @sort_data, [ $postdot_symbol_id, $leo_line ];
1505             push @sorted_data,
1506             (
1507             join q{},
1508 8         19 map { $_->[-1] } sort { $a->[0] <=> $b->[0] } @sort_data
  8         32  
  0         0  
1509             );
1510             }
1511             }
1512              
1513 59         1292 return join "\n", @sorted_data, q{};
1514             }
1515              
1516             # not to be documented
1517             sub Marpa::R3::Recognizer::regix {
1518 1     1   6880 my ( $slr ) = @_;
1519 1         5 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
1520 1         3 return $regix;
1521             }
1522              
1523             # Dump semantics for diagnostics
1524             sub Marpa::R3::Recognizer::show_semantics {
1525 0     0   0 my ( $slg, @ops ) = @_;
1526 0         0 my @op_descs = ();
1527 0         0 my $op_ix = 0;
1528 0         0 OP: while ( $op_ix < scalar @ops ) {
1529 0         0 my $op = $ops[ $op_ix++ ];
1530              
1531 0         0 my $op_name = $slg->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1532             <<'END_OF_LUA', 'i', $op );
1533             local grammar, op = ...
1534             return _M.op_names[op]
1535             END_OF_LUA
1536              
1537 0         0 push @op_descs, $op_name;
1538 0 0       0 if ( $op_name eq 'lua' ) {
1539              
1540 0         0 my ($lua_op_name) = op_fn_name_by_key( $slg, $ops[$op_ix] );
1541 0         0 push @op_descs, $lua_op_name;
1542 0         0 $op_ix++;
1543 0 0       0 if ( $lua_op_name eq 'callback' ) {
1544 0         0 push @op_descs, op_fn_name_by_key( $slg, $ops[$op_ix] );
1545             }
1546             else {
1547 0         0 push @op_descs, $ops[$op_ix];
1548             }
1549 0         0 $op_ix++;
1550 0         0 next OP;
1551             }
1552 0 0       0 if ( $op_name eq 'alternative' ) {
1553 0         0 push @op_descs, $ops[$op_ix];
1554 0         0 $op_ix++;
1555 0         0 push @op_descs, $ops[$op_ix];
1556 0         0 $op_ix++;
1557 0         0 next OP;
1558             } ## end if ( $op_name eq 'alternative' )
1559             } ## end OP: while ( $op_ix < scalar @ops )
1560 0         0 return join q{ }, @op_descs;
1561             } ## end sub show_semantics
1562              
1563             # For diagnostics
1564             sub g1_show_rule_list {
1565 0     0   0 my ( $slg, $rule_ids ) = @_;
1566 0         0 my @rules = map { $slg->g1_rule_show($_) } @{$rule_ids};
  0         0  
  0         0  
1567 0         0 return join q{}, map { q{ } . $_ . "\n" } @rules;
  0         0  
1568             }
1569              
1570             sub Marpa::R3::Recognizer::value {
1571 737     737   308689 my ( $slr, $per_parse_arg ) = @_;
1572 737         5391 my $slv = Marpa::R3::Valuer->new( { recognizer => $slr } );
1573 737         3917 my $ambiguity_level = $slv->ambiguity_level();
1574 737 100       2493 return if $ambiguity_level == 0;
1575 717 50       2063 if ( $ambiguity_level != 1 ) {
1576 0         0 my $ambiguous_status = $slv->ambiguous();
1577 0         0 Marpa::R3::exception( "Parse of the input is ambiguous\n",
1578             $ambiguous_status );
1579             }
1580 717         2664 my $value_ref = $slv->value($per_parse_arg);
1581 707 50       2521 Marpa::R3::exception("$slr->value(): No parse\n")
1582             if not $value_ref;
1583 707         3394 return $value_ref;
1584             }
1585              
1586             # INTERNAL OK AFTER HERE _marpa_
1587              
1588             1;
1589              
1590             # vim: expandtab shiftwidth=4: