File Coverage

blib/lib/Marpa/R3/SLR.pm
Criterion Covered Total %
statement 488 592 82.4
branch 95 158 60.1
condition 28 52 53.8
subroutine 61 72 84.7
pod 0 1 0.0
total 672 875 76.8


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 104     104   2260 use 5.010001;
  104         316  
15 104     104   473 use strict;
  104         190  
  104         1928  
16 104     104   462 use warnings;
  104         218  
  104         3155  
17              
18 104     104   489 use vars qw($VERSION $STRING_VERSION);
  104         190  
  104         7572  
19             $VERSION = '4.001_054';
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 104     104   616 use Scalar::Util qw(blessed tainted);
  104         176  
  104         6618  
28 104     104   613 use English qw( -no_match_vars );
  104         249  
  104         704  
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   677 my ( $slr, $symbol_name ) = @_;
40 86         245 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       235 return if not defined $start;
53 74         168 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   3438 my ( $slr, $g1_start, $g1_count ) = @_;
60              
61 1635         3425 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         6232 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 98     98   551 my ( $slr, $block_id, $offset, $length ) = @_;
76 98         305 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 98         755 return $literal;
88             }
89              
90             sub Marpa::R3::Internal::meta_recce {
91 292     292 0 761 my ($hash_args) = @_;
92 292         879 state $meta_grammar = Marpa::R3::Internal::meta_grammar();
93 292         1333 $hash_args->{grammar} = $meta_grammar;
94 292         2068 my $self = Marpa::R3::Recognizer->new($hash_args);
95 292         1255 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 1217     1217   2209 my ( $slr, $flat_args ) = @_;
101 1217 100       3041 if ( my $value = $flat_args->{'trace_file_handle'} ) {
102 10         22 $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE] = $value;
103             }
104 1217         3144 my $trace_file_handle =
105             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
106 1217         1830 delete $flat_args->{'trace_file_handle'};
107 1217         2052 return $flat_args;
108             }
109              
110             sub gen_app_event_handler {
111 6119     6119   10290 my ($slr) = @_;
112 6119         8438 my $event_handlers =
113             $slr->[Marpa::R3::Internal_R::EVENT_HANDLERS];
114             return sub {
115 1333     1333   3021 my ( $event_type, $event_name, @data ) = @_;
116 1333         2070 my $current_event =
117             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT];
118 1333 50       2395 if ($current_event) {
119 0         0 Marpa::R3::exception(
120             qq{Attempt to 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         2212 my $handler = $event_handlers->{$event_name};
127 1333 100       2154 if ( not $handler ) {
128 725         1001 $handler = $event_handlers->{"'default"};
129             }
130 1333 50       2126 if ( not $handler ) {
131 0         0 Marpa::R3::exception(
132             qq{'No event handler for event "$event_name"\n});
133             }
134 1333 50       3286 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         2023 $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] = $event_name;
143 1333   50     3182 my $retour = $handler->( $slr, $event_name, @data ) // 'ok';
144              
145             RETOUR_CHECK: {
146 1333 100       7994 if ($retour eq 'ok') {
  1333         2430  
147 644 50       995 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         1209 last RETOUR_CHECK;
156             }
157 689 50       1434 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         2141 $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] = undef;
166 1333         3200 return 'ok', $retour;
167 6119         47126 };
168             }
169              
170             sub gen_codepoint_event_handler {
171 3099     3099   5128 my ($slr) = @_;
172 3099         4626 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
173 3099         4008 my $character_class_table =
174             $slg->[Marpa::R3::Internal_G::CHARACTER_CLASS_TABLE];
175              
176             return sub {
177 5563     5563   8074 my ( $codepoint, $trace_terminals ) = @_;
178 5563         15555 my $character = pack( 'U', $codepoint );
179 5563         18677 my $is_graphic = ( $character =~ m/[[:graph:]]+/ );
180              
181 5563         7161 my @symbols;
182 5563         5957 for my $entry ( @{$character_class_table} ) {
  5563         10370  
183              
184 232100         254029 my ( $symbol_id, $re ) = @{$entry};
  232100         301767  
185              
186             # say STDERR "Codepoint %x vs $re\n";
187              
188 232100 100       721381 if ( $character =~ $re ) {
189              
190 26256 100       49259 if ( $trace_terminals >= 2 ) {
191 18         139 my $trace_file_handle =
192             $slr
193             ->[ Marpa::R3::Internal_R::TRACE_FILE_HANDLE ];
194 18         34 my $char_desc = character_describe( $slr, $codepoint );
195 18 50       24 say {$trace_file_handle}
  18         64  
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 26256         41227 push @symbols, $symbol_id;
202              
203             } ## end if ( $character =~ $re )
204             } ## end for my $entry ( @{$character_class_table} )
205              
206 5563         12764 my $coro_arg = { symbols => \@symbols };
207 5563 100       12008 $coro_arg->{is_graphic} = 'true' if $is_graphic;
208 5563         11517 return 'ok', $coro_arg;
209 3099         14795 };
210             }
211              
212             sub Marpa::R3::Recognizer::new {
213 1206     1206   249737 my ( $class, @args ) = @_;
214              
215 1206         2266 my $slr = [];
216 1206         2584 bless $slr, $class;
217              
218             # Set recognizer args to default
219             # Lua equivalent is set below
220              
221 1206         4995 my ( $flat_args, $error_message ) = Marpa::R3::flatten_hash_args( \@args );
222 1206 50       2986 Marpa::R3::exception( sprintf $error_message, '$slr->new' )
223             if not $flat_args;
224 1206         3260 $flat_args = perl_common_set( $slr, $flat_args );
225              
226 1206         2246 my $slg = $flat_args->{grammar};
227 1206 50       2546 Marpa::R3::exception(
228             qq{Marpa::R3::Recognizer::new() called without a "grammar" argument} )
229             if not defined $slg;
230 1206         2206 $slr->[Marpa::R3::Internal_R::SLG] = $slg;
231 1206         1994 delete $flat_args->{grammar};
232              
233 1206   100     4221 my $event_handlers = $flat_args->{event_handlers} // {};
234 1206         2415 $slr->[Marpa::R3::Internal_R::EVENT_HANDLERS] = $event_handlers;
235 1206 50       2998 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 1206         1779 delete $flat_args->{event_handlers};
245              
246 1206         1827 my $slg_class = 'Marpa::R3::Grammar';
247 1206 50 33     10217 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 1206   66     5781 $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE] //=
257             $slg->[Marpa::R3::Internal_G::TRACE_FILE_HANDLE];
258              
259 1206         1911 my $trace_file_handle =
260             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
261              
262 1206         2009 my $lua = $slg->[Marpa::R3::Internal_G::L];
263 1206         2322 $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 0     0   0 return 'sig', [ 'S', undef ];
273             },
274             trace => sub {
275 8     8   14 my ($msg) = @_;
276 8         11 say {$trace_file_handle} $msg;
  8         29  
277 8         24 return 'ok';
278             },
279 1206         8972 codepoint => gen_codepoint_event_handler($slr),
280             event => gen_app_event_handler($slr),
281             }
282             },
283             <<'END_OF_LUA');
284             local slg, flat_args = ...
285             _M.wrap(function ()
286             local slr = slg:slr_new(flat_args)
287             return 'ok', slr.regix
288             end)
289             END_OF_LUA
290              
291 1206         26638 $slr->[Marpa::R3::Internal_R::REGIX] = $regix;
292              
293             $slr->coro_by_tag(
294             ( '@' . __FILE__ . ':' . __LINE__ ),
295             {
296             signature => 's',
297             args => [$flat_args],
298             handlers => {
299             trace => sub {
300 0     0   0 my ($msg) = @_;
301 0         0 say {$trace_file_handle} $msg;
  0         0  
302 0         0 return 'ok';
303             },
304 1206         7580 event => gen_app_event_handler($slr),
305             }
306             },
307             <<'END_OF_LUA');
308             local slr, flat_args = ...
309             _M.wrap(function ()
310             slr:convert_libmarpa_events()
311             return 'ok'
312             end)
313             END_OF_LUA
314              
315 1206         25150 return $slr;
316             } ## end sub Marpa::R3::Recognizer::new
317              
318             sub Marpa::R3::Recognizer::DESTROY {
319             # say STDERR "In Marpa::R3::Recognizer::DESTROY before test";
320 1199     1199   136257 my $slr = shift;
321 1199         2156 my $lua = $slr->[Marpa::R3::Internal_R::L];
322              
323             # If we are destroying the Perl interpreter, then all the Marpa
324             # objects will be destroyed, including Marpa's Lua interpreter.
325             # We do not need to worry about cleaning up the
326             # recognizer is an orderly manner, because the Lua interpreter
327             # containing the recognizer will be destroyed.
328             # In fact, the Lua interpreter may already have been destroyed,
329             # so this test is necessary to avoid a warning message.
330 1199 50       2967 return if not $lua;
331             # say STDERR "In Marpa::R3::Recognizer::DESTROY after test";
332              
333 1199         2181 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
334 1199         3804 $slr->call_by_tag(
335             ('@' . __FILE__ . ':' . __LINE__),
336             <<'END_OF_LUA', '');
337             local slr = ...
338             local regix = slr.regix
339             _M.unregister(_M.registry, regix)
340             END_OF_LUA
341             }
342              
343             sub Marpa::R3::Recognizer::set {
344 11     11   4897 my ( $slr, @args ) = @_;
345              
346 11         39 my ($flat_args, $error_message) = Marpa::R3::flatten_hash_args(\@args);
347 11 50       31 Marpa::R3::exception( sprintf $error_message, '$slr->set()' ) if not $flat_args;
348 11         30 $flat_args = perl_common_set($slr, $flat_args);
349 11         20 my $trace_file_handle =
350             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
351              
352             $slr->coro_by_tag(
353             ( '@' . __FILE__ . ':' . __LINE__ ),
354             {
355             signature => 's',
356             args => [ $flat_args ],
357             handlers => {
358             trace => sub {
359 2     2   5 my ($msg) = @_;
360 2         6 say {$trace_file_handle} $msg;
  2         8  
361 2         6 return 'ok';
362             }
363             }
364             },
365 11         202 <<'END_OF_LUA');
366             local slr, flat_args = ...
367             return _M.wrap(function ()
368             slr:common_set(flat_args)
369             end
370             )
371             END_OF_LUA
372 11         67 return;
373             } ## end sub Marpa::R3::Recognizer::set
374              
375             sub Marpa::R3::Recognizer::read {
376 1211     1211   13479 my ( $slr, $p_string, $start_pos, $length ) = @_;
377 1211 50       3073 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
378 0         0 Marpa::R3::exception(
379             "$slr->read() called from inside a handler\n",
380             " This is not allowed\n",
381             " The event was ",
382             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
383             "\n",
384             );
385             }
386 1211         1983 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
387              
388 1211         3595 my $block_id = $slr->block_new($p_string);
389 1210         4325 $slr->block_set($block_id);
390 1210         3557 $slr->block_move($start_pos, $length);
391 1210         3004 return $slr->block_read();
392             }
393              
394             sub Marpa::R3::Recognizer::resume {
395 549     549   3587 my ( $slr, $start_pos, $length ) = @_;
396 549 50       1236 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
397 0         0 Marpa::R3::exception(
398             "$slr->resume() called from inside a handler\n",
399             " This is not allowed\n",
400             " The event was ",
401             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
402             "\n",
403             );
404             }
405 549         870 my $trace_file_handle =
406             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
407 549   100     1858 $length //= -1;
408 549         1377 $slr->block_move( $start_pos, $length );
409 549         1147 return $slr->block_read();
410             }
411              
412             sub character_describe {
413 18     18   27 my ($slr, $codepoint) = @_;
414              
415 18         44 my ($desc) = $slr->call_by_tag(
416             ('@' . __FILE__ . ':' . __LINE__),
417             <<'END__OF_LUA', 'i', $codepoint );
418             local slr, codepoint = ...
419             return slr:character_describe(codepoint)
420             END__OF_LUA
421              
422 18         28 return $desc;
423             } ## end sub character_describe
424              
425             # This is a Marpa Grammar method, but is included in this
426             # file because internally it is all about the recognizer.
427             sub Marpa::R3::Grammar::parse {
428 2     2   22 my ( $slg, $input_ref, @more_args ) = @_;
429 2 50 33     15 if ( not defined $input_ref or ref $input_ref ne 'SCALAR' ) {
430 0         0 Marpa::R3::exception(
431             q{$slr->parse(): first argument must be a ref to string});
432             }
433 2         9 my @recce_args = ( { grammar => $slg } );
434 2 50       6 if ( grep { ref $_ ne 'HASH' } @more_args ) {
  0         0  
435 0         0 Marpa::R3::exception(
436             q{$slr->parse(): second and later arguments must be ref to HASH});
437             }
438 2         12 my $slr = Marpa::R3::Recognizer->new( @recce_args, @more_args,
439             );
440 2         4 my $input_length = ${$input_ref};
  2         5  
441 2         9 my $length_read = $slr->read($input_ref);
442 2 50       11 if ( $length_read != length $input_length ) {
443 0         0 die 'read in $slr->parse() ended prematurely', "\n",
444             " The input length is $input_length\n",
445             " The length read is $length_read\n",
446             " The cause may be an event\n",
447             " The $slr->parse() method does not allow parses to trigger events";
448             } ## end if ( $length_read != length $input_length )
449 2         21 my $slv = Marpa::R3::Valuer->new( { recognizer => $slr });
450 2         12 my $ambiguity_level = $slv->ambiguity_level();
451 2 50       8 if ( $ambiguity_level != 1 ) {
452 0         0 my $ambiguous_status = $slv->ambiguous();
453 0         0 Marpa::R3::exception( "Parse of the input is ambiguous\n",
454             $ambiguous_status );
455             }
456              
457 2         8 my $value_ref = $slv->value();
458 2 50       18 Marpa::R3::exception(
459             '$slr->parse() read the input, but there was no parse', "\n" )
460             if not $value_ref;
461              
462 2         11 return $value_ref;
463             } ## end sub Marpa::R3::Grammar::parse
464              
465             # Brief description of block/line/column for
466             # an L0 range
467             sub lc_brief {
468 0     0   0 my ( $slr, $pos, $block ) = @_;
469 0   0     0 my ($result) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
470             <<'END_OF_LUA', 'ii', $pos, ($block // -1));
471             local slr, pos, block = ...
472             if block < 0 then block = nil end
473             return slr:lc_brief(block, pos)
474             END_OF_LUA
475 0         0 return $result;
476             }
477              
478             # Brief description of block/line/column for
479             # an L0 range
480             sub lc_range_brief {
481 0     0   0 my ( $slr, $first_block, $first_pos, $last_block, $last_pos ) = @_;
482 0         0 my ($result) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
483             <<'END_OF_LUA', 'iiii', $first_block, $first_pos, $last_block, $last_pos );
484             local slr, block1, pos1, block2, pos2 = ...
485             return slr:lc_range_brief(block1, pos1, block2, pos2)
486             END_OF_LUA
487 0         0 return $result;
488              
489             }
490              
491             sub Marpa::R3::Recognizer::progress_show {
492 19     19   2626 my ( $slr, $start_ordinal, $end_ordinal ) = @_;
493 19         71 my ($text) = $slr->call_by_tag(
494             ( '@' . __FILE__ . ':' . __LINE__ ),
495             <<'END_OF_LUA', 'ii', $start_ordinal, $end_ordinal );
496             local slr, start_ordinal_arg, end_ordinal_arg = ...
497             return slr:progress_show(start_ordinal_arg, end_ordinal_arg )
498             END_OF_LUA
499 19         116 return $text;
500             }
501              
502             sub Marpa::R3::Recognizer::progress {
503 19     19   13121 my ( $slr, $ordinal_arg ) = @_;
504 19   100     91 my ($result) = $slr->call_by_tag(
505             ('@' . __FILE__ . ':' . __LINE__),
506             <<'END_OF_LUA', 'i>0', ($ordinal_arg // -1));
507             local slr, ordinal_arg = ...
508             return slr:progress(ordinal_arg)
509             END_OF_LUA
510 19         110 return $result;
511             }
512              
513             sub Marpa::R3::Recognizer::g1_progress_show {
514 0     0   0 my ( $slr, $start_ordinal, $end_ordinal ) = @_;
515 0         0 my ($text) = $slr->call_by_tag(
516             ( '@' . __FILE__ . ':' . __LINE__ ),
517             <<'END_OF_LUA', 'ii', $start_ordinal, $end_ordinal );
518             local slr, start_ordinal_arg, end_ordinal_arg = ...
519             return slr:g1_progress_show(start_ordinal_arg, end_ordinal_arg )
520             END_OF_LUA
521 0         0 return $text;
522             }
523              
524             sub Marpa::R3::Recognizer::g1_progress {
525 21     21   10192 my ( $slr, $ordinal_arg ) = @_;
526 21   50     81 my ($result) = $slr->call_by_tag(
527             ('@' . __FILE__ . ':' . __LINE__),
528             <<'END_OF_LUA', 'i>0', ($ordinal_arg // -1));
529             local slr, ordinal_arg = ...
530             return slr:g1_progress(ordinal_arg)
531             END_OF_LUA
532 21         61 return $result;
533             }
534              
535             sub Marpa::R3::Recognizer::terminals_expected {
536 35     35   732 my ($slr) = @_;
537 35         77 my ($results) = $slr->call_by_tag(
538             ('@' . __FILE__ . ':' . __LINE__),
539             <<'END_OF_LUA', '');
540             local slr = ...
541             local slg = slr.slg
542             local g1g = slg.g1
543             local terminals_expected = slr.g1:terminals_expected()
544             local results = {}
545             for ix = 1, #terminals_expected do
546             local g1_symbol_id = terminals_expected[ix]
547             local xsy = g1g:_xsy(g1_symbol_id)
548             if xsy then
549             results[#results+1] = xsy.name
550             end
551             end
552             return results
553             END_OF_LUA
554              
555 35         92 return $results;
556             }
557              
558             sub Marpa::R3::Recognizer::exhausted {
559 18     18   215 my ($slr) = @_;
560 18         46 my ($is_exhausted) = $slr->call_by_tag(
561             ('@' . __FILE__ . ':' . __LINE__),
562             <<'END_OF_LUA', '');
563             local recce = ...
564             local is_exhausted = recce.g1:is_exhausted()
565             return is_exhausted
566             END_OF_LUA
567 18         36 return $is_exhausted;
568             }
569              
570             # Latest and current G1 location are the same
571             sub Marpa::R3::Recognizer::g1_pos {
572 185     185   5798 my ($slr) = @_;
573 185         508 my ($latest_earley_set) = $slr->call_by_tag(
574             ('@' . __FILE__ . ':' . __LINE__),
575             <<'END_OF_LUA', '');
576             local recce = ...
577             local latest_earley_set = recce:latest_earley_set()
578             return latest_earley_set
579             END_OF_LUA
580 185         504 return $latest_earley_set;
581             }
582              
583             sub Marpa::R3::Recognizer::current_earleme {
584 12     12   4909 my ($slr) = @_;
585 12         34 my ($current_earleme) = $slr->call_by_tag(
586             ('@' . __FILE__ . ':' . __LINE__),
587             <<'END_OF_LUA', '');
588             local recce = ...
589             local current_earleme = recce:current_earleme()
590             return current_earleme
591             END_OF_LUA
592 12         24 return $current_earleme;
593             }
594              
595             sub Marpa::R3::Recognizer::closest_earleme {
596 12     12   4762 my ($slr) = @_;
597 12         32 my ($closest_earleme) = $slr->call_by_tag(
598             ('@' . __FILE__ . ':' . __LINE__),
599             <<'END_OF_LUA', '');
600             local recce = ...
601             local closest_earleme = recce:closest_earleme()
602             return closest_earleme
603             END_OF_LUA
604 12         25 return $closest_earleme;
605             }
606              
607             sub Marpa::R3::Recognizer::furthest_earleme {
608 12     12   5113 my ($slr) = @_;
609 12         34 my ($furthest_earleme) = $slr->call_by_tag(
610             ('@' . __FILE__ . ':' . __LINE__),
611             <<'END_OF_LUA', '');
612             local recce = ...
613             local furthest_earleme = recce:furthest_earleme()
614             return furthest_earleme
615             END_OF_LUA
616 12         24 return $furthest_earleme;
617             }
618              
619             sub Marpa::R3::Recognizer::latest_earleme {
620 11     11   12760 my ($slr) = @_;
621 11         33 my ($latest_earleme) = $slr->call_by_tag(
622             ('@' . __FILE__ . ':' . __LINE__),
623             <<'END_OF_LUA', '');
624             local recce = ...
625             local latest_earleme = recce:latest_earleme()
626             return latest_earleme
627             END_OF_LUA
628 11         25 return $latest_earleme;
629             }
630              
631             sub Marpa::R3::Recognizer::earleme {
632 1     1   6 my ( $slr, $earley_set_id ) = @_;
633 1         3 my ($earleme) = $slr->call_by_tag(
634             ('@' . __FILE__ . ':' . __LINE__),
635             <<'END_OF_LUA', 'i', $earley_set_id);
636             local recce, earley_set_id = ...
637             local earleme = recce:earleme(earley_set_id)
638             return earleme
639             END_OF_LUA
640 1         3 return $earleme;
641             }
642              
643             sub Marpa::R3::Recognizer::lexeme_alternative_literal {
644 84     84   4112 my ( $slr, $symbol_name, $length ) = @_;
645 84   100     293 $length //= 1;
646              
647 84 50       141 Marpa::R3::exception(
648             "slr->alternative_literal(): symbol name is undefined\n",
649             " The symbol name cannot be undefined\n"
650             ) if not defined $symbol_name;
651              
652 84         183 my ($ok) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
653             <<'END_OF_LUA', 'si', $symbol_name, $length);
654             local slr, symbol_name, length = ...
655             return slr:lexeme_alternative_literal(symbol_name, length)
656             END_OF_LUA
657 84 50       214 return 1 if $ok;
658 0         0 return;
659             }
660              
661             sub Marpa::R3::Recognizer::lexeme_alternative {
662 137     137   1113 my ( $slr, $symbol_name, $value, $length ) = @_;
663 137   100     442 $length //= 1;
664              
665 137 50       394 if ( Scalar::Util::tainted( $value ) ) {
666 0         0 Marpa::R3::exception(
667             "Problem in Marpa::R3: Attempt to use a tainted token value\n",
668             "Marpa::R3 is insecure for use with tainted data\n"
669             );
670             }
671              
672             Marpa::R3::exception(
673 137 50       236 "slr->alternative(): symbol name is undefined\n",
674             " The symbol name cannot be undefined\n"
675             ) if not defined $symbol_name;
676              
677 137         142 my $ok;
678 137 100       221 if (defined $value) {
679 127         274 ($ok) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
680             <<'END_OF_LUA', 'sSi', $symbol_name, $value, $length );
681             local slr, symbol_name, token_sv, length = ...
682             return slr:lexeme_alternative(symbol_name, token_sv, length)
683             END_OF_LUA
684             } else {
685 10         24 ($ok) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
686             <<'END_OF_LUA', 'si', $symbol_name, $length );
687             local slr, symbol_name, length = ...
688             return slr:lexeme_alternative_undef(symbol_name, length )
689             END_OF_LUA
690             }
691              
692 135 50       589 return 1 if $ok;
693 0         0 return;
694             }
695              
696             # Returns 0 on unthrown failure, current location on success
697             sub Marpa::R3::Recognizer::lexeme_complete {
698 189     189   3932 my ( $slr, $block, $offset, $length ) = @_;
699 189 50       406 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
700 0         0 Marpa::R3::exception(
701             "$slr->lexeme_complete() called from inside a handler\n",
702             " This is not allowed\n",
703             " The event was ",
704             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
705             "\n",
706             );
707             }
708              
709 189         237 my $trace_file_handle =
710             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
711              
712             my ($return_value) = $slr->coro_by_tag(
713             ( '@' . __FILE__ . ':' . __LINE__ ),
714             {
715             signature => 'iii',
716             args => [ $block, $offset, $length ],
717             handlers => {
718             trace => sub {
719 0     0   0 my ($msg) = @_;
720 0         0 say {$trace_file_handle} $msg;
  0         0  
721 0         0 return 'ok';
722             },
723 189         999 codepoint => gen_codepoint_event_handler($slr),
724             event => gen_app_event_handler($slr),
725             }
726             },
727             <<'END_OF_LUA');
728             local slr, block_id_arg, offset_arg, length_arg = ...
729             local block_id, offset, eoread
730             = slr:block_check_range(block_id_arg, offset_arg, length_arg)
731             _M.wrap(function ()
732             local new_offset = slr:lexeme_complete(block_id, offset, eoread-offset)
733             slr:convert_libmarpa_events()
734             return 'ok', new_offset
735             end
736             )
737             END_OF_LUA
738              
739 189         2406 return $return_value;
740              
741             } ## end sub Marpa::R3::Recognizer::lexeme_complete
742              
743             # Returns 0 on unthrown failure, current location on success,
744             # undef if lexeme not accepted.
745             sub Marpa::R3::Recognizer::lexeme_read_literal {
746 116     116   514 my ( $slr, $symbol_name, $block_id, $offset, $length ) = @_;
747 116 50       259 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
748 0         0 Marpa::R3::exception(
749             "$slr->lexeme_read_literal() called from inside a handler\n",
750             " This is not allowed\n",
751             " The event was ",
752             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
753             "\n",
754             );
755             }
756             my ($ok, $return_value) = $slr->coro_by_tag(
757             ( '@' . __FILE__ . ':' . __LINE__ ),
758             {
759             signature => 'siii',
760             args => [ $symbol_name, $block_id, $offset, $length ],
761             handlers => {
762             trace => sub {
763 0     0   0 my ($msg) = @_;
764 0         0 my $trace_file_handle =
765             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
766 0         0 say {$trace_file_handle} $msg;
  0         0  
767 0         0 return 'ok';
768             },
769 116         568 codepoint => gen_codepoint_event_handler($slr),
770             event => gen_app_event_handler($slr),
771             }
772             },
773             <<'END_OF_LUA');
774             local slr, symbol_name, block_id, offset, length = ...
775             _M.wrap(function ()
776             local offset = slr:lexeme_read_literal(symbol_name, block_id, offset, length )
777             if not offset then return 'ok', 0 end
778             return 'ok', 1, offset
779             end
780             )
781             END_OF_LUA
782              
783 116 50       1310 return if not $ok;
784 116         245 return $return_value;
785             }
786              
787             # Returns 0 on unthrown failure, current location on success,
788             # undef if lexeme not accepted.
789             sub Marpa::R3::Recognizer::lexeme_read_block {
790 243     243   7240 my ( $slr, $symbol_name, $value, $block_id, $offset, $length ) = @_;
791 243 50       488 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
792 0         0 Marpa::R3::exception(
793             "$slr->lexeme_read_block() called from inside a handler\n",
794             " This is not allowed\n",
795             " The event was ",
796             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
797             "\n",
798             );
799             }
800 243 50       627 if ( Scalar::Util::tainted( $value ) ) {
801 0         0 Marpa::R3::exception(
802             "Problem in Marpa::R3: Attempt to use a tainted token value\n",
803             "Marpa::R3 is insecure for use with tainted data\n"
804             );
805             }
806             my ($ok, $return_value) = $slr->coro_by_tag(
807             ( '@' . __FILE__ . ':' . __LINE__ ),
808             {
809             signature => 'sSiii',
810             args => [ $symbol_name, $value, $block_id, $offset, $length ],
811             handlers => {
812             trace => sub {
813 0     0   0 my ($msg) = @_;
814 0         0 my $trace_file_handle =
815             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
816 0         0 say {$trace_file_handle} $msg;
  0         0  
817 0         0 return 'ok';
818             },
819 243         1338 codepoint => gen_codepoint_event_handler($slr),
820             event => gen_app_event_handler($slr),
821             }
822             },
823             <<'END_OF_LUA');
824             local slr, symbol_name, token_sv, block_id, offset, length = ...
825             _M.wrap(function ()
826             local offset = slr:lexeme_read_block(symbol_name, token_sv, block_id, offset, length )
827             if not offset then return 'ok', 0 end
828             return 'ok', 1, offset
829             end
830             )
831             END_OF_LUA
832              
833 243 50       3141 return if not $ok;
834 243         1151 return $return_value;
835             }
836              
837             # Returns 0 on unthrown failure, current location on success,
838             # undef if lexeme not accepted.
839             sub Marpa::R3::Recognizer::lexeme_read_string {
840 36     36   867 my ( $slr, $symbol_name, $string ) = @_;
841 36 50       70 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
842 0         0 Marpa::R3::exception(
843             '$recce->lexeme_read_string() called from inside a handler', "\n",
844             " This is not allowed\n",
845             " The event was ",
846             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
847             "\n",
848             );
849             }
850              
851             my ($ok, $return_value) = $slr->coro_by_tag(
852             ( '@' . __FILE__ . ':' . __LINE__ ),
853             {
854             signature => 'ss',
855             args => [ $symbol_name, $string ],
856             handlers => {
857             trace => sub {
858 0     0   0 my ($msg) = @_;
859 0         0 my $trace_file_handle =
860             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
861 0         0 say {$trace_file_handle} $msg;
  0         0  
862 0         0 return 'ok';
863             },
864 36         342 codepoint => gen_codepoint_event_handler($slr),
865             event => gen_app_event_handler($slr),
866             }
867             },
868             <<'END_OF_LUA');
869             local slr, symbol_name, input_string = ...
870             _M.wrap(function ()
871             local offset = slr:lexeme_read_string(symbol_name, input_string )
872             if not offset then return 'ok', 0 end
873             return 'ok', 1, offset
874             end
875             )
876             END_OF_LUA
877              
878 36 100       484 return if not $ok;
879 35         82 return $return_value;
880              
881             }
882              
883             sub Marpa::R3::Recognizer::g1_to_block_first {
884 57     57   805 my ( $slr, $g1_pos ) = @_;
885 57         160 return $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
886             <<'END_OF_LUA', 'i', $g1_pos );
887             local slr, g1_pos = ...
888             g1_pos = math.tointeger(g1_pos)
889             if not g1_pos then
890             _M.userX(
891             "g1_to_block_first(%s): argument must be an integer",
892             g1_pos)
893             end
894             return slr:g1_to_block_first(g1_pos)
895             END_OF_LUA
896             }
897              
898             sub Marpa::R3::Recognizer::g1_to_block_last {
899 54     54   155 my ( $slr, $g1_pos ) = @_;
900 54         129 return $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
901             <<'END_OF_LUA', 'i', $g1_pos );
902             local slr, g1_pos = ...
903             g1_pos = math.tointeger(g1_pos)
904             if not g1_pos then
905             _M.userX(
906             "g1_to_block_last(%s): argument must be an integer",
907             g1_pos)
908             end
909             return slr:g1_to_block_last(g1_pos)
910             END_OF_LUA
911             }
912              
913             # TODO -- Document this method ??
914             sub Marpa::R3::Recognizer::lc_brief {
915 39     39   93 my ( $slr, $first_block, $first_pos, $last_block, $last_pos ) = @_;
916 39         96 my ($desc) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
917             <<'END_OF_LUA', 'iiii', $first_block, $first_pos, $last_block, $last_pos );
918             local slr, first_block, first_pos, last_block, last_pos = ...
919             local function usage()
920             error(
921             "usage: $recce->lc_brief(first_block, first_pos, [last_block, last_pos])"
922             )
923             end
924             if not first_block or not first_pos then
925             return usage()
926             end
927             if last_block == nil or last_pos == nil then
928             if last_block ~= nil or last_pos ~= nil then
929             return usage()
930             end
931             last_block = first_block
932             last_pos = first_pos
933             end
934             return slr:lc_range_brief(
935             first_block, first_pos, last_block, last_pos)
936             END_OF_LUA
937 39         104 return $desc;
938             }
939              
940             sub Marpa::R3::Recognizer::line_column {
941 131     131   659 my ( $slr, $block, $offset, ) = @_;
942 131   50     226 $offset //= -1;
943 131   50     207 $block //= -1;
944              
945 131         256 my ($line_no, $column_no) = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
946             <<'END_OF_LUA', 'ii', $block, $offset );
947             local slr, block_arg, offset_arg = ...
948             local block_id = block_arg ~= -1 and block_arg or nil
949             local offset = offset_arg ~= -1 and offset_arg or nil
950             local erreur
951             block_id, offset = slr:block_check_offset(block_id, offset)
952             if not block_id then
953             -- if block_id is nil, then offset is an error message
954             return nil, offset
955             end
956             local _, line_no, column_no = slr:per_pos(block_id, offset)
957             return line_no, column_no
958             END_OF_LUA
959              
960             # if $line_no is nil, 2nd return value is error message
961             # Marpa::R3::exception("line_column(): ", $column_no) if not defined $line_no;
962 131 50       269 $DB::single = 1 if not defined $line_no;
963 131         249 return $line_no, $column_no;
964             } ## end sub Marpa::R3::Recognizer::line_column
965              
966             sub Marpa::R3::Recognizer::block_new {
967 1310     1310   3011 my ( $slr, $p_string ) = @_;
968 1310         2268 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
969              
970             Marpa::R3::exception(
971             q{Attempt to use a tainted input string in $slr->read()},
972             qq{\n Marpa::R3 is insecure for use with tainted data\n}
973 1310 100       1796 ) if Scalar::Util::tainted( ${$p_string} );
  1310         4691  
974              
975 1309 50       4073 if ( ( my $ref_type = ref $p_string ) ne 'SCALAR' ) {
976 0 0       0 my $desc = $ref_type ? "a ref to $ref_type" : 'not a ref';
977 0         0 Marpa::R3::exception(
978             qq{Arg to Marpa::R3::Recognizer::read() is $desc\n},
979             ' It should be a ref to scalar' );
980             } ## end if ( ( my $ref_type = ref $p_string ) ne 'SCALAR' )
981              
982 1309 50       1773 if ( not defined ${$p_string} ) {
  1309         3011  
983 0         0 Marpa::R3::exception(
984             qq{Arg to Marpa::R3::Recognizer::read() is a ref to an undef\n},
985             ' It should be a ref to a defined scalar' );
986             } ## end if ( ( my $ref_type = ref $p_string ) ne 'SCALAR' )
987              
988 1309         2282 my $character_class_table =
989             $slg->[Marpa::R3::Internal_G::CHARACTER_CLASS_TABLE];
990              
991             my ($block_id) = $slr->coro_by_tag(
992             ( '@' . __FILE__ . ':' . __LINE__ ),
993             {
994             signature => 's',
995 1309         2520 args => [ ${$p_string} ],
  1309         3619  
996             handlers => {
997             codepoint => gen_codepoint_event_handler($slr),
998             event => gen_app_event_handler($slr),
999             },
1000             },
1001             <<'END_OF_LUA');
1002             local slr, input_string = ...
1003             local new_block_id
1004             _M.wrap(function()
1005             new_block_id = slr:block_new(input_string)
1006             return 'ok', new_block_id
1007             end
1008             )
1009             END_OF_LUA
1010              
1011 1309         18081 return $block_id;
1012             }
1013              
1014             sub Marpa::R3::Recognizer::block_progress {
1015 648     648   23480 my ($slr, $block_id) = @_;
1016 648         834 my ($l0_pos, $l0_end);
1017 648         1289 ($block_id, $l0_pos, $l0_end)
1018             = $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1019             <<'END_OF_LUA', 'i', $block_id );
1020             local slr, block_id_arg = ...
1021             local block_id, erreur = slr:block_check_id(block_id_arg)
1022             if not block_id then
1023             error(erreur)
1024             end
1025             local l0_pos, l0_end
1026             block_id, l0_pos, l0_end = slr:block_progress(block_id)
1027             return block_id, l0_pos, l0_end
1028             END_OF_LUA
1029 648         1344 return $block_id, $l0_pos, $l0_end;
1030             }
1031              
1032             sub Marpa::R3::Recognizer::block_set {
1033 1354     1354   4277 my ($slr, $block_id) = @_;
1034 1354 50       3569 if ( $slr->[Marpa::R3::Internal_R::CURRENT_EVENT] ) {
1035 0         0 Marpa::R3::exception(
1036             "$slr->block_set() called from inside a handler\n",
1037             " This is not allowed\n",
1038             " The event was ",
1039             $slr->[Marpa::R3::Internal_R::CURRENT_EVENT],
1040             "\n",
1041             );
1042             }
1043 1354         4456 $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1044             <<'END_OF_LUA', 'i', $block_id );
1045             local slr, block_id_arg = ...
1046             local block_id, erreur = slr:block_check_id(block_id_arg)
1047             if not block_id then
1048             error(erreur)
1049             end
1050             return slr:block_set(block_id)
1051             END_OF_LUA
1052 1354         2091 return;
1053             }
1054              
1055             # block_id defaults to current block
1056             # block_offset defaults to don't set offset
1057             # length defaults to don't set eoread
1058             sub Marpa::R3::Recognizer::block_move {
1059 2155     2155   5764 my ($slr, $offset, $length) = @_;
1060 2155         6041 $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1061             <<'END_OF_LUA', 'ii', $offset, $length );
1062             local slr, offset_arg, length_arg = ...
1063             local ok, offset, eoread
1064             = slr:block_check_range(nil, offset_arg, length_arg)
1065             if not ok then
1066             -- new_block_offset is error message
1067             error(offset)
1068             end
1069             -- we don't set offset if the arg was nil
1070             local new_offset = offset_arg and offset or nil
1071             -- we don't set eoread if the length arg was nil
1072             local new_eoread = length_arg and eoread or nil
1073             return slr:block_move(new_offset, new_eoread)
1074             END_OF_LUA
1075 2155         3525 return;
1076             }
1077              
1078             sub Marpa::R3::Recognizer::block_read {
1079 1814     1814   4060 my ($slr ) = @_;
1080             my ($offset) = $slr->coro_by_tag(
1081             ( '@' . __FILE__ . ':' . __LINE__ ),
1082             {
1083             signature => '',
1084             args => [],
1085             handlers => {
1086             trace => sub {
1087 314     314   510 my ($msg) = @_;
1088 314         453 my $trace_file_handle =
1089             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
1090 314         323 say {$trace_file_handle} $msg;
  314         837  
1091 314         828 return 'ok';
1092             },
1093 1814         10727 event => gen_app_event_handler($slr),
1094             }
1095             },
1096             <<'END_OF_LUA');
1097             local slr = ...
1098             _M.wrap(function ()
1099             local offset = slr:block_read()
1100             return 'ok', offset
1101             end
1102             )
1103             END_OF_LUA
1104 1805         27267 return $offset;
1105             }
1106              
1107             sub Marpa::R3::Recognizer::input_length {
1108 2     2   1067 my ( $slr, $block_id ) = @_;
1109 2   100     12 my ($length) = $slr->call_by_tag(
1110             ('@' . __FILE__ . ':' . __LINE__),
1111             <<'END_OF_LUA', 'i', ($block_id // -1));
1112             local slr, block_id = ...
1113             local block = block_id > 0 and slr.inputs[block_id] or slr.current_block
1114             return #block
1115             END_OF_LUA
1116              
1117 2         6 return $length;
1118             }
1119              
1120             # no return value documented
1121             sub Marpa::R3::Recognizer::activate {
1122 536     536   1485 my ( $slr, $event_name, $activate ) = @_;
1123 536         623 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
1124              
1125 536         1031 $slr->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1126             <<'END_OF_LUA', 'si', $event_name, $activate);
1127             local slr, event_name, activate = ...
1128             if not activate then
1129             activate = 1
1130             else
1131             activate = activate ~= 0
1132             end
1133             -- print('$slr->activate():', event_name, activate)
1134             return slr:activate_by_event_name(event_name, activate)
1135             END_OF_LUA
1136 536         907 return;
1137             }
1138              
1139             # On success, returns the old priority value.
1140             # Failures are thrown.
1141             sub Marpa::R3::Recognizer::lexeme_priority_set {
1142 12     12   49 my ( $slr, $lexeme_name, $new_priority ) = @_;
1143 12         26 my ($old_priority) = $slr->call_by_tag(
1144             ('@' . __FILE__ . ':' . __LINE__),
1145             <<'END_OF_LUA', 'si>*', $lexeme_name, $new_priority );
1146             local recce, lexeme_name, new_priority = ...
1147             local slg = recce.slg
1148             local g1g = slg.g1
1149             local lexeme_id = g1g.isyid_by_name[lexeme_name]
1150             if not lexeme_id then
1151             _M.userX(
1152             "lexeme_priority_set(): no such symbol as %q",
1153             lexeme_name
1154             )
1155             end
1156             if type(new_priority) ~= 'number' then
1157             _M.userX(
1158             "lexeme_priority_set(): priority is not a number, it is %s",
1159             new_priority
1160             )
1161             end
1162             local g_lexeme_data = slg.g1.isys[lexeme_id]
1163             local r_lexeme_data = recce.g1_isys[lexeme_id]
1164             if not g_lexeme_data.lexeme then
1165             print(inspect(lexeme_data))
1166             _M.userX(
1167             "lexeme_priority_set(): %q is not a lexeme",
1168             lexeme_name
1169             )
1170             end
1171             local old_priority = r_lexeme_data.lexeme_priority
1172             r_lexeme_data.lexeme_priority = new_priority
1173             return old_priority
1174             END_OF_LUA
1175              
1176 12         21 return $old_priority;
1177             }
1178              
1179             # Internal methods, not to be documented
1180              
1181             # not to be documented
1182             sub Marpa::R3::Recognizer::call_by_tag {
1183 8845     8845   27175 my ( $slr, $tag, $codestr, $signature, @args ) = @_;
1184 8845         13277 my $lua = $slr->[Marpa::R3::Internal_R::L];
1185 8845         10743 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
1186              
1187 8845 50       14879 $DB::single = 1 if not $slr;
1188 8845 50       13206 $DB::single = 1 if not $regix;
1189             # $DB::single = 1 if grep { not defined $_ } @args;
1190 8845         15810 my @results;
1191             my $eval_error;
1192 8845         0 my $eval_ok;
1193             {
1194 8845         9905 local $@;
  8845         11158  
1195 8845         11488 $eval_ok = eval {
1196 8845         252658 @results =
1197             $lua->call_by_tag( $regix, $tag, $codestr, $signature, @args );
1198 8843         16930 return 1;
1199             };
1200 8845         15631 $eval_error = $@;
1201             }
1202 8845 100       15464 if ( not $eval_ok ) {
1203 2         6 Marpa::R3::exception($eval_error);
1204             }
1205 8843         23864 return @results;
1206             }
1207              
1208             # not to be documented
1209             sub Marpa::R3::Recognizer::coro_by_tag {
1210 6125     6125   13206 my ( $slr, $tag, $args, $codestr ) = @_;
1211 6125         8961 my $lua = $slr->[Marpa::R3::Internal_R::L];
1212 6125         8029 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
1213 6125   50     13143 my $handler = $args->{handlers} // {};
1214 6125         10930 my $resume_tag = $tag . '[R]';
1215 6125   50     11276 my $signature = $args->{signature} // '';
1216 6125   50     10773 my $p_args = $args->{args} // [];
1217              
1218 6125         11453 my @results;
1219             my $eval_error;
1220 6125         0 my $eval_ok;
1221             {
1222 6125         7072 local $@;
  6125         7382  
1223 6125         8550 $eval_ok = eval {
1224 6125         7859 $lua->call_by_tag( $regix, $tag, $codestr, $signature, @{$p_args} );
  6125         95518  
1225 6125         14678 my @resume_args = ('');
1226 6125         7888 my $signature = 's';
1227 6125         7350 CORO_CALL: while (1) {
1228 13337         7683177 my ( $cmd, $yield_data ) =
1229             $lua->call_by_tag( $regix, $resume_tag,
1230             'local slr, resume_arg = ...; return _M.resume(resume_arg)',
1231             $signature, @resume_args ) ;
1232 13328 100       41580 if (not $cmd) {
1233 6116         7745 @results = @{$yield_data};
  6116         11204  
1234 6116         25083 return 1;
1235             }
1236 7212         12312 my $handler = $handler->{$cmd};
1237 7212 50       12017 Marpa::R3::exception(qq{No coro handler for "$cmd"})
1238             if not $handler;
1239 7212   50     11181 $yield_data //= [];
1240 7212         8835 my ($handler_cmd, $new_resume_args) = $handler->(@{$yield_data});
  7212         14352  
1241 7212 50       13424 Marpa::R3::exception(qq{Undefined return command from handler for "$cmd"})
1242             if not defined $handler_cmd;
1243 7212 50       13275 if ($handler_cmd eq 'ok') {
1244 7212         9290 $signature = 's';
1245 7212         16884 @resume_args = ($new_resume_args);
1246 7212 50       12523 if (scalar @resume_args < 1) {
1247 0         0 @resume_args = ('');
1248             }
1249 7212         13848 next CORO_CALL;
1250             }
1251 0 0       0 if ($handler_cmd eq 'sig') {
1252 0         0 @resume_args = @{$new_resume_args};
  0         0  
1253 0         0 $signature = shift @resume_args;
1254 0         0 next CORO_CALL;
1255             }
1256 0         0 Marpa::R3::exception(qq{Bad return command ("$handler_cmd") from handler for "$cmd"})
1257             }
1258 0         0 return 1;
1259             };
1260 6125         12830 $eval_error = $@;
1261             }
1262 6125 100       11095 if ( not $eval_ok ) {
1263             # if it's an object, just die
1264 9 50       37 die $eval_error if ref $eval_error;
1265 9         47 Marpa::R3::exception($eval_error);
1266             }
1267 6116         14974 return @results;
1268             }
1269              
1270             # not to be documented
1271             sub Marpa::R3::Recognizer::earley_set_size {
1272 78     78   237 my ($slr, $set_id) = @_;
1273 78   50     180 my ($size) = $slr->call_by_tag(
1274             ('@' . __FILE__ . ':' . __LINE__),
1275             <<'END_OF_LUA', 'i', ($set_id // -1));
1276             local recce, set_id = ...
1277             local g1r = recce.g1
1278             if set_id < 0 then set_id = g1r:latest_earley_set() end
1279             return g1r:_earley_set_size(set_id)
1280             END_OF_LUA
1281 78         285 return $size;
1282             }
1283              
1284             # not to be documented
1285             sub Marpa::R3::Recognizer::earley_sets_show {
1286 8     8   2246 my ($slr) = @_;
1287              
1288 8         35 my ($last_completed_earleme, $furthest_earleme) = $slr->call_by_tag(
1289             ('@' . __FILE__ . ':' . __LINE__),
1290             <<'END_OF_LUA', '');
1291             local recce = ...
1292             local g1r = recce.g1
1293             return g1r:current_earleme(), g1r:furthest_earleme()
1294             END_OF_LUA
1295              
1296 8         43 my $text = "Last Completed: $last_completed_earleme; "
1297             . "Furthest: $furthest_earleme\n";
1298 8         23 LIST: for ( my $ix = 0;; $ix++ ) {
1299 67         199 my $set_desc =
1300             $slr->Marpa::R3::Recognizer::earley_set_show( $ix );
1301 67 100       147 last LIST if not $set_desc;
1302 59         489 $text .= "Earley Set $ix\n$set_desc";
1303             }
1304 8         71 return $text;
1305             }
1306              
1307             # not to be documented
1308             sub Marpa::R3::Recognizer::earley_set_show {
1309 67     67   124 my ( $slr, $traced_set_id ) = @_;
1310 67         103 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
1311              
1312 67         177 my ($set_data) =
1313             $slr->call_by_tag(
1314             ('@' . __FILE__ . ':' . __LINE__),
1315             <<'END_OF_LUA', 'i>2', $traced_set_id );
1316             local recce, traced_set_id = ...
1317             return recce:g1_earley_set_data(traced_set_id)
1318             END_OF_LUA
1319              
1320 67 100       150 return if not $set_data;
1321 59         83 my %set_data = @{$set_data};
  59         340  
1322              
1323 59         114 my $current_earleme = $set_data{earleme};
1324              
1325 59         80 my @sorted_data = ();
1326              
1327 59         205 EARLEY_ITEM: for ( my $item_id = 0 ; ; $item_id++ ) {
1328              
1329 511         757 my $item_data = $set_data{ $item_id + 1 };
1330 511 100       833 last EARLEY_ITEM if not defined $item_data;
1331              
1332 452         473 my %item_data = @{$item_data};
  452         1581  
1333              
1334 452         652 my $nrl_id = $item_data{nrl_id};
1335 452         511 my $dot_position = $item_data{dot_position};
1336 452         495 my $ahm_desc;
1337 452 100       708 if ( $dot_position < 0 ) {
1338 177         424 $ahm_desc = sprintf( 'R%d$', $nrl_id );
1339             }
1340             else {
1341 275         666 $ahm_desc = sprintf( 'R%d:%d', $nrl_id, $dot_position );
1342             }
1343 452         554 my $ahm_id_of_yim = $item_data{ahm_id_of_yim};
1344 452         488 my $origin_earleme = $item_data{origin_earleme};
1345              
1346 452         984 my $text .= sprintf "ahm%d: %s@%d-%d", $ahm_id_of_yim,
1347             $ahm_desc,
1348             $origin_earleme, $current_earleme;
1349              
1350 452         681 my @lines = $text;
1351 452         1221 push @lines,
1352             qq{ }
1353             . $ahm_desc . q{: }
1354             . $slg->dotted_nrl_show( $nrl_id, $dot_position );
1355              
1356 452         726 push @sorted_data, @lines;
1357              
1358             # Token links
1359             {
1360 452         530 my @sort_data = ();
1361 452         510 my @lines = ();
1362 452         613 my $token_links = $item_data{token_links};
1363 452         490 my %token_links = @{$token_links};
  452         636  
1364 452         602 TOKEN_LINK: for ( my $token_link_ix = 0 ; ; $token_link_ix++ ) {
1365 519         805 my $token_link_data = $token_links{ $token_link_ix + 1 };
1366 519 100       985 last TOKEN_LINK if not $token_link_data;
1367 67         77 my %token_link_data = @{$token_link_data};
  67         233  
1368              
1369 67         97 my $predecessor_ahm = $token_link_data{predecessor_ahm};
1370 67         88 my $origin_earleme = $token_link_data{origin_earleme};
1371 67         108 my $middle_earleme = $token_link_data{middle_earleme};
1372 67         77 my $middle_set_id = $token_link_data{middle_set_id};
1373 67         93 my $token_name = $token_link_data{token_name};
1374 67         76 my $token_id = $token_link_data{token_id};
1375 67         82 my $value_ix = $token_link_data{value_ix};
1376 67         85 my $value = $token_link_data{value};
1377             my $source_predecessor_state =
1378 67         87 $token_link_data{source_predecessor_state};
1379              
1380 67         78 my @pieces = ();
1381 67 50       137 if ( defined $predecessor_ahm ) {
1382 67         152 my $ahm_desc = $slg->briefer_ahm($predecessor_ahm);
1383 67         175 push @pieces,
1384             'c='
1385             . $ahm_desc . q{@}
1386             . $origin_earleme . q{-}
1387             . $middle_earleme;
1388             } ## end if ( defined $predecessor_ahm )
1389              
1390 67         108 push @pieces, 's=' . $token_name;
1391              
1392 67 50       133 if ( not defined $value ) {
1393              
1394             # Value is literal
1395 67         85 my $token_length = $current_earleme - $middle_earleme;
1396 67         145 $value = $slr->g1_literal( $middle_earleme, $token_length );
1397             }
1398 67         324 my $token_dump =
1399             Data::Dumper->new( [ \$value ] )->Terse(1)->Dump;
1400 67         3044 chomp $token_dump;
1401 67         143 push @pieces, "t=$token_dump";
1402 67         165 my $token_link_desc = '[' . ( join '; ', @pieces ) . ']';
1403 67         231 push @sort_data,
1404             [
1405             $middle_set_id, $token_id,
1406             $predecessor_ahm, $token_link_desc
1407             ];
1408             }
1409 67         237 push @sorted_data, map { qq{ } . $_->[-1] } sort {
1410 452 0 0     852 $a->[0] <=> $b->[0]
  0         0  
1411             || $a->[1] <=> $b->[1]
1412             || $a->[2] <=> $b->[2]
1413             } @sort_data;
1414             }
1415              
1416             # Completion links
1417             {
1418 452         502 my @sort_data = ();
  452         529  
1419 452         479 my @lines = ();
1420 452         537 my $completion_links = $item_data{completion_links};
1421 452         475 my %completion_links = @{$completion_links};
  452         748  
1422             TOKEN_LINK:
1423 452         567 for ( my $completion_link_ix = 0 ; ; $completion_link_ix++ ) {
1424             my $completion_link_data =
1425 689         912 $completion_links{ $completion_link_ix + 1 };
1426 689 100       1192 last TOKEN_LINK if not $completion_link_data;
1427 237         262 my %completion_link_data = @{$completion_link_data};
  237         541  
1428              
1429             my $predecessor_ahm_id =
1430 237         312 $completion_link_data{predecessor_state};
1431 237         276 my $ahm_id = $completion_link_data{ahm_id};
1432 237         282 my $origin_earleme = $completion_link_data{origin_earleme};
1433 237         275 my $middle_earleme = $completion_link_data{middle_earleme};
1434 237         446 my $ahm_desc = $slg->briefer_ahm($ahm_id);
1435              
1436 237         301 my @pieces = ();
1437 237 50       432 if ( defined $predecessor_ahm_id ) {
1438 237         441 my $predecessor_ahm_desc =
1439             $slg->briefer_ahm($predecessor_ahm_id);
1440 237         526 push @pieces,
1441             'p='
1442             . $predecessor_ahm_desc . '@'
1443             . $origin_earleme . q{-}
1444             . $middle_earleme;
1445             }
1446              
1447 237         431 push @pieces,
1448             'c='
1449             . $ahm_desc . q{@}
1450             . $middle_earleme . q{-}
1451             . $current_earleme;
1452 237         806 my $link_desc = '[' . ( join '; ', @pieces ) . ']';
1453              
1454 237   50     818 push @sort_data,
1455             [
1456             $middle_earleme, $ahm_id,
1457             ( $predecessor_ahm_id // -1 ), $link_desc
1458             ];
1459             }
1460 237         731 push @sorted_data, map { q{ } . $_->[-1] } sort {
1461 452 50 66     763 $a->[0] <=> $b->[0]
  27         131  
1462             || $a->[1] <=> $b->[1]
1463             || $a->[2] <=> $b->[2]
1464             } @sort_data;
1465             }
1466              
1467             # Leo links
1468             {
1469 452         515 my @sort_data = ();
  452         525  
  452         522  
1470 452         494 my @lines = ();
1471 452         575 my $leo_links = $item_data{leo_links};
1472 452         473 my %leo_links = @{$leo_links};
  452         603  
1473             LEO_LINK:
1474 452         527 for ( my $leo_link_ix = 0 ; ; $leo_link_ix++ ) {
1475 460         564 my $leo_link_data = $leo_links{ $leo_link_ix + 1 };
1476 460 100       726 last LEO_LINK if not $leo_link_data;
1477 8         8 my %leo_link_data = @{$leo_link_data};
  8         18  
1478              
1479 8         12 my $middle_earleme = $leo_link_data{middle_earleme};
1480 8         10 my $middle_set_id = $leo_link_data{middle_set_id};
1481             my $leo_transition_symbol =
1482 8         11 $leo_link_data{leo_transition_symbol};
1483 8         10 my $ahm_id = $leo_link_data{ahm_id};
1484 8         18 my $ahm_desc = $slg->briefer_ahm($ahm_id);
1485              
1486 8         10 my @pieces = ();
1487 8         18 push @pieces,
1488             'l=L' . $leo_transition_symbol . q{@} . $middle_earleme;
1489 8         18 push @pieces,
1490             'c='
1491             . $ahm_desc . q{@}
1492             . $middle_earleme . q{-}
1493             . $current_earleme;
1494 8         17 my $link_desc = '[' . ( join '; ', @pieces ) . ']';
1495              
1496 8         25 push @sort_data,
1497             [
1498             $middle_set_id, $ahm_id,
1499             $leo_transition_symbol, $link_desc,
1500             ];
1501             }
1502 8         36 push @sorted_data, map { q{ } . $_->[-1] } sort {
1503 452 0 0     1206 $a->[0] <=> $b->[0]
  0         0  
1504             || $a->[1] <=> $b->[1]
1505             || $a->[2] <=> $b->[2]
1506             } @sort_data;
1507             }
1508             }
1509              
1510             # Leo items
1511             {
1512 59         70 my $leo_data = $set_data{leo};
  59         77  
1513 59         70 my %leo_data = @{$leo_data};
  59         95  
1514 59         84 my @sort_data = ();
1515 59         82 LEO_ITEM: for ( my $leo_item_id = 0 ; ; $leo_item_id++ ) {
1516              
1517 67         88 my $leo_item_data = $leo_data{ $leo_item_id + 1 };
1518 67 100       147 last LEO_ITEM if not defined $leo_item_data;
1519              
1520 8         11 my %leo_item_data = @{$leo_item_data};
  8         29  
1521 8         10 my $postdot_symbol_id = $leo_item_data{postdot_symbol_id};
1522 8         12 my $postdot_symbol_name = $leo_item_data{postdot_symbol_name};
1523 8         11 my $predecessor_symbol_id = $leo_item_data{predecessor_symbol_id};
1524 8         9 my $base_origin_earleme = $leo_item_data{base_origin_earleme};
1525 8         18 my $leo_base_state = $leo_item_data{leo_base_state};
1526 8         10 my $trace_earleme = $leo_item_data{trace_earleme};
1527              
1528             # L2@8 ["Expression"; L2@6; S16@6-8]
1529 8         18 my @link_texts = ( q{"} . $postdot_symbol_name . q{"} );
1530 8 100       15 if ( defined $predecessor_symbol_id ) {
1531 6         18 push @link_texts,
1532             sprintf( 'L%d@%d',
1533             $predecessor_symbol_id, $base_origin_earleme );
1534             }
1535 8         17 push @link_texts,
1536             sprintf( 'S%d@%d-%d',
1537             $leo_base_state, $base_origin_earleme, $trace_earleme );
1538 8         20 my $leo_line = sprintf( 'L%d@%d [%s]',
1539             $postdot_symbol_id, $trace_earleme,
1540             ( join q{; }, @link_texts ) );
1541 8         15 push @sort_data, [ $postdot_symbol_id, $leo_line ];
1542             push @sorted_data,
1543             (
1544             join q{},
1545 8         17 map { $_->[-1] } sort { $a->[0] <=> $b->[0] } @sort_data
  8         30  
  0         0  
1546             );
1547             }
1548             }
1549              
1550 59         1195 return join "\n", @sorted_data, q{};
1551             }
1552              
1553             # not to be documented
1554             sub Marpa::R3::Recognizer::regix {
1555 1     1   5727 my ( $slr ) = @_;
1556 1         4 my $regix = $slr->[Marpa::R3::Internal_R::REGIX];
1557 1         2 return $regix;
1558             }
1559              
1560             # Dump semantics for diagnostics
1561             sub Marpa::R3::Recognizer::show_semantics {
1562 0     0   0 my ( $slg, @ops ) = @_;
1563 0         0 my @op_descs = ();
1564 0         0 my $op_ix = 0;
1565 0         0 OP: while ( $op_ix < scalar @ops ) {
1566 0         0 my $op = $ops[ $op_ix++ ];
1567              
1568 0         0 my $op_name = $slg->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
1569             <<'END_OF_LUA', 'i', $op );
1570             local grammar, op = ...
1571             return _M.op_names[op]
1572             END_OF_LUA
1573              
1574 0         0 push @op_descs, $op_name;
1575 0 0       0 if ( $op_name eq 'lua' ) {
1576              
1577 0         0 my ($lua_op_name) = op_fn_name_by_key( $slg, $ops[$op_ix] );
1578 0         0 push @op_descs, $lua_op_name;
1579 0         0 $op_ix++;
1580 0 0       0 if ( $lua_op_name eq 'callback' ) {
1581 0         0 push @op_descs, op_fn_name_by_key( $slg, $ops[$op_ix] );
1582             }
1583             else {
1584 0         0 push @op_descs, $ops[$op_ix];
1585             }
1586 0         0 $op_ix++;
1587 0         0 next OP;
1588             }
1589 0 0       0 if ( $op_name eq 'alternative' ) {
1590 0         0 push @op_descs, $ops[$op_ix];
1591 0         0 $op_ix++;
1592 0         0 push @op_descs, $ops[$op_ix];
1593 0         0 $op_ix++;
1594 0         0 next OP;
1595             } ## end if ( $op_name eq 'alternative' )
1596             } ## end OP: while ( $op_ix < scalar @ops )
1597 0         0 return join q{ }, @op_descs;
1598             } ## end sub show_semantics
1599              
1600             # For diagnostics
1601             sub g1_show_rule_list {
1602 0     0   0 my ( $slg, $rule_ids ) = @_;
1603 0         0 my @rules = map { $slg->g1_rule_show($_) } @{$rule_ids};
  0         0  
  0         0  
1604 0         0 return join q{}, map { q{ } . $_ . "\n" } @rules;
  0         0  
1605             }
1606              
1607             sub Marpa::R3::Recognizer::value {
1608 739     739   249568 my ( $slr, $per_parse_arg ) = @_;
1609 739         3955 my $slv = Marpa::R3::Valuer->new( { recognizer => $slr } );
1610 739         2624 my $ambiguity_level = $slv->ambiguity_level();
1611 739 100       3005 return if $ambiguity_level == 0;
1612 719 100       1611 if ( $ambiguity_level != 1 ) {
1613 1         5 my $ambiguous_status = $slv->ambiguous();
1614 1         7 Marpa::R3::exception( "Parse of the input is ambiguous\n",
1615             $ambiguous_status );
1616             }
1617 718         2021 my $value_ref = $slv->value($per_parse_arg);
1618 708 50       1919 Marpa::R3::exception("$slr->value(): No parse\n")
1619             if not $value_ref;
1620 708         2537 return $value_ref;
1621             }
1622              
1623             # INTERNAL OK AFTER HERE _marpa_
1624              
1625             1;
1626              
1627             # vim: expandtab shiftwidth=4: