File Coverage

blib/lib/Marpa/R3/SLV.pm
Criterion Covered Total %
statement 333 372 89.5
branch 75 106 70.7
condition 20 36 55.5
subroutine 34 38 89.4
pod n/a
total 462 552 83.7


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::Valuer;
13              
14 104     104   1957 use 5.010001;
  104         398  
15 104     104   608 use strict;
  104         238  
  104         2304  
16 104     104   556 use warnings;
  104         229  
  104         3223  
17              
18 104     104   571 use vars qw($VERSION $STRING_VERSION);
  104         239  
  104         8307  
19             $VERSION = '4.001_053';
20             $STRING_VERSION = $VERSION;
21             ## no critic(BuiltinFunctions::ProhibitStringyEval)
22             $VERSION = eval $VERSION;
23             ## use critic
24              
25             package Marpa::R3::Internal_V;
26              
27 104     104   715 use Scalar::Util qw(blessed tainted);
  104         229  
  104         5852  
28 104     104   735 use English qw( -no_match_vars );
  104         241  
  104         773  
29              
30             our $PACKAGE = 'Marpa::R3::Valuer';
31              
32             # Set those common args which are at the Perl level.
33             sub slv_common_set {
34 1142     1142   2290 my ( $slv, $flat_args ) = @_;
35 1142 100       2991 if ( my $value = $flat_args->{'trace_file_handle'} ) {
36 2         4 $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE] = $value;
37             }
38 1142         2135 my $trace_file_handle =
39             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
40 1142         1906 delete $flat_args->{'trace_file_handle'};
41 1142         2219 return $flat_args;
42             }
43              
44             our $CONTEXT_EXCEPTION_CLASS = __PACKAGE__ . '::Context_Exception';
45              
46             sub Marpa::R3::Context::bail { ## no critic (Subroutines::RequireArgUnpacking)
47 4 100 66 4   90 if ( scalar @_ == 1 and ref $_[0] ) {
48 2         16 die bless { exception_object => $_[0] }, $CONTEXT_EXCEPTION_CLASS;
49             }
50 2         11 my $error_string = join q{}, @_;
51 2         12 my ( $package, $filename, $line ) = caller;
52 2         7 chomp $error_string;
53 2         42 die bless { message => qq{User bailed at line $line in file "$filename"\n}
54             . $error_string
55             . "\n" }, $CONTEXT_EXCEPTION_CLASS;
56             } ## end sub Marpa::R3::Context::bail
57             ## use critic
58              
59             sub Marpa::R3::Context::g1_range {
60 2     2   27 my $slv = $Marpa::R3::Context::valuer;
61 2         8 my ( $start, $end ) =
62             $slv->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ), <<'END_OF_LUA', '>*' );
63             local slv = ...
64             return slv:g1_range()
65             END_OF_LUA
66 2         14 return $start, $end;
67             } ## end sub Marpa::R3::Context::g1_range
68              
69             sub Marpa::R3::Context::lc_range {
70 8     8   30 my $slv = $Marpa::R3::Context::valuer;
71 8         20 my ( $lc_range ) =
72             $slv->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ), <<'END_OF_LUA', '>*' );
73             local slv = ...
74             local slr = slv.slr
75             local g1_first, g1_last = slv:g1_range()
76             local l0_first_b, l0_first_p = slr:g1_to_block_first(g1_first)
77             local l0_last_b, l0_last_p = slr:g1_to_block_last(g1_last)
78             return slr:lc_range_brief(l0_first_b, l0_first_p, l0_last_b, l0_last_p)
79             END_OF_LUA
80 8         22 return $lc_range;
81             }
82              
83             sub Marpa::R3::Context::g1_span {
84 0     0   0 my $slv = $Marpa::R3::Context::valuer;
85 0         0 my ( $start, $length ) =
86             $slv->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ), <<'END_OF_LUA', '>*' );
87             local slv = ...
88             local g1_first, g1_last = slv:g1_range()
89             local length = g1_last - g1_first + 1
90             return start, length
91             END_OF_LUA
92 0         0 return $start, $length;
93             }
94              
95             sub code_problems {
96 10     10   24 my $args = shift;
97              
98 10         25 my $grammar;
99             my $fatal_error;
100 10         22 my $warnings = [];
101 10         19 my $where = '?where?';
102 10         18 my $long_where;
103 10         21 my @msg = ();
104 10         19 my $eval_value;
105 10         18 my $eval_given = 0;
106              
107 10         29 push @msg, q{=} x 60, "\n";
108 10         13 ARG: for my $arg ( keys %{$args} ) {
  10         48  
109 50         82 my $value = $args->{$arg};
110 50 100       97 if ( $arg eq 'fatal_error' ) { $fatal_error = $value; next ARG }
  10         19  
  10         20  
111 40 50       81 if ( $arg eq 'grammar' ) { $grammar = $value; next ARG }
  0         0  
  0         0  
112 40 100       72 if ( $arg eq 'where' ) { $where = $value; next ARG }
  10         32  
  10         23  
113 30 100       79 if ( $arg eq 'long_where' ) { $long_where = $value; next ARG }
  10         20  
  10         32  
114 20 100       209 if ( $arg eq 'warnings' ) { $warnings = $value; next ARG }
  10         208  
  10         29  
115 10 50       27 if ( $arg eq 'eval_ok' ) {
116 10         14 $eval_value = $value;
117 10         16 $eval_given = 1;
118 10         145 next ARG;
119             }
120 0         0 push @msg, "Unknown argument to code_problems: $arg";
121             } ## end ARG: for my $arg ( keys %{$args} )
122              
123             GIVEN_FATAL_ERROR_REF_TYPE: {
124 10         25 my $fatal_error_ref_type = ref $fatal_error;
  10         24  
125 10 100       34 last GIVEN_FATAL_ERROR_REF_TYPE if not $fatal_error_ref_type;
126 4 50       13 if ( $fatal_error_ref_type eq $CONTEXT_EXCEPTION_CLASS ) {
127 4         10 my $exception_object = $fatal_error->{exception_object};
128 4 100       29 die $exception_object if defined $exception_object;
129 2         5 my $exception_message = $fatal_error->{message};
130 2 50       29 die $exception_message if defined $exception_message;
131 0         0 die "Internal error: bad $CONTEXT_EXCEPTION_CLASS object";
132             } ## end if ( $fatal_error_ref_type eq $CONTEXT_EXCEPTION_CLASS)
133             $fatal_error =
134 0         0 "Exception thrown as object inside Marpa closure\n"
135             . ( q{ } x 4 )
136             . "This is not allowed\n"
137             . ( q{ } x 4 )
138             . qq{Exception as string is "$fatal_error"};
139             } ## end GIVEN_FATAL_ERROR_REF_TYPE:
140              
141 6         15 my @problem_line = ();
142 6         10 my $max_problem_line = -1;
143 6         11 for my $warning_data ( @{$warnings} ) {
  6         16  
144 4         7 my ( $warning, $package, $filename, $problem_line ) = @{$warning_data};
  4         8  
145 4         9 $problem_line[$problem_line] = 1;
146 4         13 $max_problem_line = List::Util::max $problem_line, $max_problem_line;
147             } ## end for my $warning_data ( @{$warnings} )
148              
149 6   33     16 $long_where //= $where;
150              
151 6         11 my $warnings_count = scalar @{$warnings};
  6         13  
152             {
153 6         8 my @problems;
  6         9  
154 6   66     35 my $false_eval = $eval_given && !$eval_value && !$fatal_error;
155 6 50       23 if ($false_eval) {
156 0         0 push @problems, '* THE MARPA SEMANTICS RETURNED A PERL FALSE',
157             'Marpa::R3 requires its semantics to return a true value';
158             }
159 6 100       15 if ($fatal_error) {
160 4         8 push @problems, '* THE MARPA SEMANTICS PRODUCED A FATAL ERROR';
161             }
162 6 100       17 if ($warnings_count) {
163 2         10 push @problems,
164             "* THERE WERE $warnings_count WARNING(S) IN THE MARPA SEMANTICS:",
165             'Marpa treats warnings as fatal errors';
166             }
167 6 50       16 if ( not scalar @problems ) {
168 0         0 push @msg, '* THERE WAS A FATAL PROBLEM IN THE MARPA SEMANTICS';
169             }
170 6         24 push @msg, ( join "\n", @problems ) . "\n";
171             }
172              
173 6         17 push @msg, "* THIS IS WHAT MARPA WAS DOING WHEN THE PROBLEM OCCURRED:\n"
174             . $long_where . "\n";
175              
176 6         20 for my $warning_ix ( 0 .. ( $warnings_count - 1 ) ) {
177 4         11 push @msg, "* WARNING MESSAGE NUMBER $warning_ix:\n";
178 4         7 my $warning_message = $warnings->[$warning_ix]->[0];
179 4         44 $warning_message =~ s/\n*\z/\n/xms;
180 4         12 push @msg, $warning_message;
181             } ## end for my $warning_ix ( 0 .. ( $warnings_count - 1 ) )
182              
183 6 100       20 if ($fatal_error) {
184 4         10 push @msg, "* THIS WAS THE FATAL ERROR MESSAGE:\n";
185 4         7 my $fatal_error_message = $fatal_error;
186 4         55 $fatal_error_message =~ s/\n*\z/\n/xms;
187 4         12 push @msg, $fatal_error_message;
188             } ## end if ($fatal_error)
189              
190 6         41 Marpa::R3::exception(@msg);
191              
192             # this is to keep perlcritic happy
193 0         0 return 1;
194              
195             }
196              
197             sub Marpa::R3::Valuer::new {
198 1139     1139   8557 my ( $class, @args ) = @_;
199              
200 1139         2270 my $slv = [];
201              
202             # Set recognizer args to default
203             # Lua equivalent is set below
204              
205 1139         4454 my ( $flat_args, $error_message ) = Marpa::R3::flatten_hash_args( \@args );
206 1139 50       3207 Marpa::R3::exception( sprintf $error_message, '$slv->new' )
207             if not $flat_args;
208 1139         3177 $flat_args = slv_common_set( $slv, $flat_args );
209              
210 1139         2120 my $slr = $flat_args->{recognizer};
211 1139 50       2786 Marpa::R3::exception(
212             qq{Marpa::R3::Valuer::new() called without a "recognizer" argument} )
213             if not defined $slr;
214 1139         2306 $slv->[Marpa::R3::Internal_V::SLR] = $slr;
215 1139         2103 delete $flat_args->{recognizer};
216              
217 1139         1873 my $slr_class = 'Marpa::R3::Recognizer';
218 1139 50 33     10626 if ( not blessed $slr or not $slr->isa($slr_class) ) {
219 0         0 my $ref_type = ref $slr;
220 0 0       0 my $desc = $ref_type ? "a ref to $ref_type" : 'not a ref';
221 0         0 Marpa::R3::exception(
222             qq{'recognizer' named argument to new() is $desc\n},
223             " It should be a ref to $slr_class\n"
224             );
225             }
226              
227 1139   33     6003 $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE] //=
228             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
229              
230 1139         1907 my $trace_file_handle =
231             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
232              
233 1139         1838 my $lua = $slr->[Marpa::R3::Internal_R::L];
234 1139         1861 $slv->[Marpa::R3::Internal_V::L] = $lua;
235              
236             my ( $regix ) = $slr->coro_by_tag(
237             ( '@' . __FILE__ . ':' . __LINE__ ),
238             {
239             signature => 's',
240             args => [$flat_args],
241             handlers => {
242             trace => sub {
243 0     0   0 my ($msg) = @_;
244 0         0 say {$trace_file_handle} $msg;
  0         0  
245 0         0 return 'ok';
246             },
247             }
248             },
249 1139         10344 <<'END_OF_LUA');
250             local slr, flat_args = ...
251             _M.wrap(function ()
252             local slv = slr:slv_new(flat_args)
253             if not slv then return 'ok', -1 end
254             return 'ok', slv.regix
255             end)
256             END_OF_LUA
257              
258 1139 50       8076 return if $regix < 0;
259 1139         2512 $slv->[Marpa::R3::Internal_V::REGIX] = $regix;
260              
261 1139         5121 return bless $slv, $class;
262             }
263              
264             sub Marpa::R3::Valuer::DESTROY {
265             # say STDERR "In Marpa::R3::Valuer::DESTROY before test";
266 1139     1139   49881 my $slv = shift;
267 1139         2191 my $lua = $slv->[Marpa::R3::Internal_V::L];
268              
269             # If we are destroying the Perl interpreter, then all the Marpa
270             # objects will be destroyed, including Marpa's Lua interpreter.
271             # We do not need to worry about cleaning up the
272             # recognizer is an orderly manner, because the Lua interpreter
273             # containing the recognizer will be destroyed.
274             # In fact, the Lua interpreter may already have been destroyed,
275             # so this test is necessary to avoid a warning message.
276 1139 50       3411 return if not $lua;
277             # say STDERR "In Marpa::R3::Valuer::DESTROY after test";
278              
279 1139         1887 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
280 1139         4154 $slv->call_by_tag(
281             ('@' . __FILE__ . ':' . __LINE__),
282             <<'END_OF_LUA', '');
283             local slv = ...
284             local regix = slv.regix
285             _M.unregister(_M.registry, regix)
286             END_OF_LUA
287             }
288              
289             sub Marpa::R3::Valuer::set {
290 3     3   966 my ( $slv, @args ) = @_;
291              
292 3         11 my ($flat_args, $error_message) = Marpa::R3::flatten_hash_args(\@args);
293 3 50       10 Marpa::R3::exception( sprintf $error_message, '$slv->set()' ) if not $flat_args;
294 3         8 $flat_args = slv_common_set($slv, $flat_args);
295 3         5 my $trace_file_handle =
296             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
297              
298             $slv->coro_by_tag(
299             ( '@' . __FILE__ . ':' . __LINE__ ),
300             {
301             signature => 's',
302             args => [ $flat_args ],
303             handlers => {
304             trace => sub {
305 1     1   2 my ($msg) = @_;
306 1         2 say {$trace_file_handle} $msg;
  1         4  
307 1         3 return 'ok';
308             }
309             }
310             },
311 3         29 <<'END_OF_LUA');
312             local slv, flat_args = ...
313             return _M.wrap(function ()
314             slv:common_set(flat_args)
315             end
316             )
317             END_OF_LUA
318 3         24 return;
319             }
320              
321             # Returns false if no parse
322             sub Marpa::R3::Valuer::value {
323 2487     2487   58377 my ( $slv, $per_parse_arg ) = @_;
324 2487         4347 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
325 2487         3899 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
326              
327 2487   50     8833 my $trace_actions =
328             $slg->[Marpa::R3::Internal_G::TRACE_ACTIONS] // 0;
329 2487         4009 my $trace_file_handle =
330             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
331              
332 2487   100     7718 my $semantics_arg0 = $per_parse_arg // {};
333 2487         4033 my $constants = $slg->[Marpa::R3::Internal_G::CONSTANTS];
334 2487         3696 my $null_values = $slg->[Marpa::R3::Internal_G::NULL_VALUES];
335 2487         3725 my $nulling_closures =
336             $slg->[Marpa::R3::Internal_G::CLOSURE_BY_SYMBOL_ID];
337 2487         3644 my $rule_closures =
338             $slg->[Marpa::R3::Internal_G::CLOSURE_BY_RULE_ID];
339              
340 2487         3936 local $Marpa::R3::Context::rule = undef;
341 2487         3517 local $Marpa::R3::Context::irlid = undef;
342 2487         3521 local $Marpa::R3::Context::grammar = $slg;
343 2487         3560 local $Marpa::R3::Context::recognizer = $slr;
344 2487         3712 local $Marpa::R3::Context::valuer = $slv;
345              
346             my %value_handlers = (
347             trace => sub {
348 108     108   183 my ($msg) = @_;
349 108 50       280 my $nl = ( $msg =~ /\n\z/xms ) ? '' : "\n";
350 108         143 print {$trace_file_handle} $msg, $nl;
  108         390  
351 108         254 return 'ok';
352             },
353             terse_dump => sub {
354 10     10   27 my ($value) = @_;
355 10         60 my $dumped = Data::Dumper->new( [$value] )->Terse(1)->Dump;
356 10         518 chomp $dumped;
357 10         32 return 'ok', $dumped;
358             },
359             constant => sub {
360 5874     5874   9269 my ($constant_ix) = @_;
361 5874         9785 my $constant = $constants->[$constant_ix];
362 5874         14577 return 'sig', [ 'S', $constant ];
363             },
364             perl_undef => sub {
365 2081     2081   5646 return 'sig', [ 'S', undef ];
366             },
367             bless => sub {
368 46521     46521   72968 my ( $value, $blessing_ix ) = @_;
369 46521         72643 my $blessing_data = $constants->[$blessing_ix];
370 46521         56502 my ( $irlid, $lexeme_id, $blessing ) = @{$blessing_data};
  46521         91344  
371 46521         62909 my $lexeme_name;
372 46521 100       77847 if ( defined $lexeme_id ) {
373 9692         30255 $lexeme_name = $slg->g1_symbol_name($lexeme_id);
374             }
375             else {
376 36829         69402 $lexeme_name = "[IRL# $irlid]";
377             }
378              
379             FIND_BASE_BLESSING: {
380 46521 100       59561 if ( $blessing eq '::name' ) {
  46521         88782  
381 9692 50       28751 if ( $lexeme_name =~ / [^ [:alnum:]] /xms ) {
382 0         0 Marpa::R3::exception(
383             qq{Lexeme blessing by '::name' only allowed if lexeme name is whitespace and alphanumerics\n},
384             qq{ Problematic lexeme was <$lexeme_name>\n}
385             );
386             } ## end if ( $lexeme_name =~ / [^ [:alnum:]] /xms )
387 9692         14236 $blessing = $lexeme_name;
388 9692         35167 $blessing =~ s/[ ]/_/gxms;
389 9692         19055 last FIND_BASE_BLESSING;
390             } ## end if ( $default_blessing eq '::name' )
391 36829 50       83158 if ( $blessing =~ /^ :: /xms ) {
392 0         0 Marpa::R3::exception(
393             qq{Blessing lexeme as '$blessing' is not allowed\n},
394             qq{ It is in pseudo-blessing form, but there is no such psuedo-blessing\n},
395             qq{ Problematic lexeme was <$lexeme_name>\n}
396             );
397             }
398 36829 50       83572 if ( $blessing =~ / [\W] /xms ) {
399 0         0 Marpa::R3::exception(
400             qq{Blessing lexeme as '$blessing' is not allowed\n},
401             qq{ It contained non-word characters and that is not allowed\n},
402             qq{ Problematic lexeme was <$lexeme_name>\n}
403             );
404             } ## end if ( $default_blessing =~ / [\W] /xms )
405             }
406              
407 46521 50       85713 if ( $blessing !~ / :: /xms ) {
408 46521         69896 my $bless_package =
409             $slg->[Marpa::R3::Internal_G::BLESS_PACKAGE];
410 46521 50       78043 if ( not defined $bless_package ) {
411 0         0 Marpa::R3::exception(
412             qq{Blessing package needed, but grammar has none\n},
413             qq{ The blessing was "$blessing"\n} );
414             } ## end if ( not defined $bless_package )
415 46521         89966 $blessing = $bless_package . q{::} . $blessing;
416             }
417 46521         172231 return 'sig', [ 'S', ( bless $value, $blessing ) ];
418             },
419             perl_nulling_semantics => sub {
420 147     147   312 my ($token_id) = @_;
421 147         514 my $value_ref = $nulling_closures->[$token_id];
422 147         339 my $result;
423             my @warnings;
424 147         0 my $eval_ok;
425             DO_EVAL: {
426 147         219 local $SIG{__WARN__} = sub {
427 0         0 push @warnings, [ $_[0], ( caller 0 ) ];
428 147         915 };
429 147         425 $eval_ok = eval {
430 147         259 my $irlid = $null_values->[$token_id];
431 147         229 local $Marpa::R3::Context::irlid = $irlid;
432 147         654 local $Marpa::R3::Context::production_id =
433             $slg->g1_rule_to_production_id($irlid);
434 147         591 $result = $value_ref->( $semantics_arg0, [] );
435 147         1521 1;
436             };
437             } ## end DO_EVAL:
438 147 50 33     715 if ( not $eval_ok or @warnings ) {
439 0         0 my $fatal_error = $EVAL_ERROR;
440 0         0 code_problems(
441             {
442             fatal_error => $fatal_error,
443             eval_ok => $eval_ok,
444             warnings => \@warnings,
445             where => 'computing value',
446             long_where => 'Computing value for null symbol: '
447             . $slg->g1_symbol_display_form($token_id),
448             }
449             );
450             } ## end if ( not $eval_ok or @warnings )
451 147         470 return 'sig', [ 'S', $result ];
452             },
453             perl_rule_semantics => sub {
454 7512     7512   13198 my ( $irlid, $values ) = @_;
455             # say Data::Dumper::Dumper($values);
456 7512         12702 my $closure = $rule_closures->[$irlid];
457 7512         9383 my $result;
458 7512 50       14520 if ( defined $closure ) {
459 7512         10783 my @warnings;
460             my $eval_ok;
461             local $SIG{__WARN__} = sub {
462 4         99 push @warnings, [ $_[0], ( caller 0 ) ];
463 7512         40026 };
464 7512         14863 local $Marpa::R3::Context::irlid = $irlid;
465 7512         20356 local $Marpa::R3::Context::production_id =
466             $slg->g1_rule_to_production_id($irlid);
467 7512         11618 $eval_ok = eval {
468 7512         16832 $result = $closure->( $semantics_arg0, $values );
469 7504         85192 1;
470             };
471 7512 100 100     48992 if ( not $eval_ok or @warnings ) {
472 10         20 my $fatal_error = $EVAL_ERROR;
473 10         52 code_problems(
474             {
475             fatal_error => $fatal_error,
476             eval_ok => $eval_ok,
477             warnings => \@warnings,
478             where => 'computing value',
479             long_where => 'Computing value for rule: '
480             . $slg->g1_rule_show($irlid),
481             }
482             );
483             } ## end if ( not $eval_ok or @warnings )
484             }
485 7502         23695 return 'sig', [ 'S', $result ];
486             }
487 2487         36966 );
488              
489 2487         12811 my ($cmd, $final_value) =
490             $slv->coro_by_tag(
491             ( '@' . __FILE__ . ':' . __LINE__ ),
492             {
493             signature => '',
494             args => [],
495             handlers => \%value_handlers
496             },
497             <<'END_OF_LUA');
498             local slv = ...
499             return slv:value()
500             END_OF_LUA
501              
502 2477 100       10197 return if $cmd ne 'ok';
503 2419         58804 return \($final_value);
504              
505             }
506              
507             # not to be documented
508             sub Marpa::R3::Valuer::call_by_tag {
509 2445     2445   5644 my ( $slv, $tag, $codestr, $signature, @args ) = @_;
510 2445         4638 my $lua = $slv->[Marpa::R3::Internal_V::L];
511 2445         3606 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
512              
513 2445         5184 my @results;
514             my $eval_error;
515 2445         0 my $eval_ok;
516             {
517 2445         3370 local $@;
  2445         3325  
518 2445         3865 $eval_ok = eval {
519 2445         28936 @results =
520             $lua->call_by_tag( $regix, $tag, $codestr, $signature, @args );
521 2445         5318 return 1;
522             };
523 2445         5214 $eval_error = $@;
524             }
525 2445 50       5380 if ( not $eval_ok ) {
526 0         0 Marpa::R3::exception($eval_error);
527             }
528 2445         8289 return @results;
529             }
530              
531             # not to be documented
532             sub Marpa::R3::Valuer::coro_by_tag {
533 2490     2490   5747 my ( $slv, $tag, $args, $codestr ) = @_;
534 2490         3909 my $lua = $slv->[Marpa::R3::Internal_V::L];
535 2490         3796 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
536 2490   50     6087 my $handler = $args->{handlers} // {};
537 2490         5242 my $resume_tag = $tag . '[R]';
538 2490   50     5416 my $signature = $args->{signature} // '';
539 2490   50     5146 my $p_args = $args->{args} // [];
540              
541 2490         5477 my @results;
542             my $eval_error;
543 2490         0 my $eval_ok;
544             {
545 2490         3513 local $@;
  2490         3326  
546 2490         4313 $eval_ok = eval {
547 2490         3950 $lua->call_by_tag( $regix, $tag, $codestr, $signature, @{$p_args} );
  2490         29799  
548 2490         6752 my @resume_args = ('');
549 2490         3981 my $signature = 's';
550 2490         3428 CORO_CALL: while (1) {
551 64734         2188564 my ( $cmd, $yield_data ) =
552             $lua->call_by_tag( $regix, $resume_tag,
553             'local slv, resume_arg = ...; return _M.resume(resume_arg)',
554             $signature, @resume_args ) ;
555 64734 100       197520 if (not $cmd) {
556 2480         3920 @results = @{$yield_data};
  2480         6130  
557 2480         7645 return 1;
558             }
559 62254         108073 my $handler = $handler->{$cmd};
560 62254 50       106695 Marpa::R3::exception(qq{No coro handler for "$cmd"})
561             if not $handler;
562 62254   50     101913 $yield_data //= [];
563 62254         80471 my ($handler_cmd, $new_resume_args) = $handler->(@{$yield_data});
  62254         126995  
564 62244 50       126168 Marpa::R3::exception(qq{Undefined return command from handler for "$cmd"})
565             if not defined $handler_cmd;
566 62244 100       109259 if ($handler_cmd eq 'ok') {
567 119         163 $signature = 's';
568 119         260 @resume_args = ($new_resume_args);
569 119 50       233 if (scalar @resume_args < 1) {
570 0         0 @resume_args = ('');
571             }
572 119         256 next CORO_CALL;
573             }
574 62125 50       104347 if ($handler_cmd eq 'sig') {
575 62125         75465 @resume_args = @{$new_resume_args};
  62125         119769  
576 62125         95902 $signature = shift @resume_args;
577 62125         131831 next CORO_CALL;
578             }
579 0         0 Marpa::R3::exception(qq{Bad return command ("$handler_cmd") from handler for "$cmd"})
580             }
581 0         0 return 1;
582             };
583 2490         5348 $eval_error = $@;
584             }
585 2490 100       5535 if ( not $eval_ok ) {
586             # if it's an object, just die
587 10 100       183 die $eval_error if ref $eval_error;
588 8         32 Marpa::R3::exception($eval_error);
589             }
590 2480         7771 return @results;
591             }
592              
593             # not to be documented
594             sub Marpa::R3::Valuer::tree_show {
595 4     4   1834 my ( $slv, $verbose ) = @_;
596 4         8 my $text = q{};
597 4         9 NOOK: for ( my $nook_id = 0; 1; $nook_id++ ) {
598 44         97 my $nook_text = $slv->nook_show( $nook_id, $verbose );
599 44 100       81 last NOOK if not defined $nook_text;
600 40         193 $text .= "$nook_id: $nook_text";
601             }
602 4         28 return $text;
603             }
604              
605             # not to be documented
606             sub Marpa::R3::Valuer::nook_show {
607 44     44   90 my ( $slv, $nook_id, $verbose ) = @_;
608 44         70 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
609              
610 44         93 my ($or_node_id, $text) = $slv->call_by_tag(
611             ('@' . __FILE__ . ':' . __LINE__),
612             <<'END_OF_LUA', 'i', $nook_id);
613             local slv, nook_id = ...
614             local slr = slv.slr
615             local tree = slv.lmw_t
616             -- print('nook_id', nook_id)
617             local or_node_id = tree:_nook_or_node(nook_id)
618             if not or_node_id then return end
619             local text = 'o' .. or_node_id
620             local parent = tree:_nook_parent(nook_id) or '-'
621             -- print('nook_is_cause', tree:_nook_is_cause(nook_id))
622             if tree:_nook_is_cause(nook_id) ~= 0 then
623             text = text .. '[c' .. parent .. ']'
624             goto CHILD_TYPE_FOUND
625             end
626             if tree:_nook_is_predecessor(nook_id) ~= 0 then
627             text = text .. '[p' .. parent .. ']'
628             goto CHILD_TYPE_FOUND
629             end
630             text = text .. '[-]'
631             ::CHILD_TYPE_FOUND::
632              
633             if not or_node_id then return end
634              
635             local tree = slv.lmw_t
636             text = text .. " " .. slv:or_node_tag(or_node_id) .. ' p'
637             if tree:_nook_predecessor_is_ready(nook_id) ~= 0 then
638             text = text .. '=ok'
639             else
640             text = text .. '-'
641             end
642             text = text .. ' c'
643             if tree:_nook_cause_is_ready(nook_id) ~= 0 then
644             text = text .. '=ok'
645             else
646             text = text .. '-'
647             end
648             text = text .. '\n'
649             return or_node_id, text
650             END_OF_LUA
651              
652 44 100       106 return if not defined $or_node_id;
653              
654             DESCRIBE_CHOICES: {
655 40         270 my $this_choice;
  40         46  
656 40         93 ($this_choice) = $slv->call_by_tag(
657             ('@' . __FILE__ . ':' . __LINE__),
658             'local slv, nook_id = ...; return slv.lmw_t:_nook_choice(nook_id)',
659             'i', $nook_id
660             );
661 40         65 CHOICE: for ( my $choice_ix = 0;; $choice_ix++ ) {
662              
663 89         212 my ($and_node_id) = $slv->call_by_tag(
664             ('@' . __FILE__ . ':' . __LINE__),
665             <<'END_OF_LUA', 'ii>*', $or_node_id, $choice_ix );
666             local slv, or_node_id, choice_ix = ...
667             return slv.lmw_o:_and_order_get(or_node_id+0, choice_ix+0)
668             END_OF_LUA
669              
670 89 100       424 last CHOICE if not defined $and_node_id;
671 49         129 $text .= " o$or_node_id" . '[' . $choice_ix . ']';
672 49 100 66     175 if ( defined $this_choice and $this_choice == $choice_ix ) {
673 40         55 $text .= q{*};
674             }
675 49         87 my $and_node_tag =
676             $slv->and_node_tag( $and_node_id );
677 49         128 $text .= " ::= a$and_node_id $and_node_tag";
678 49         102 $text .= "\n";
679             } ## end CHOICE: for ( my $choice_ix = 0;; $choice_ix++ )
680             } ## end DESCRIBE_CHOICES:
681 40         82 return $text;
682             }
683              
684             # not to be documented
685             sub Marpa::R3::Valuer::and_node_tag {
686 49     49   86 my ( $slv, $and_node_id ) = @_;
687              
688 49         110 my ($tag) = $slv->call_by_tag( ( '@' . __FILE__ . ':' . __LINE__ ),
689             << 'END_OF_LUA', 'i', $and_node_id );
690             local slv, and_node_id=...
691             return slv:and_node_tag(and_node_id)
692             END_OF_LUA
693              
694 49         96 return $tag;
695             }
696              
697             # not to be documented
698             sub Marpa::R3::Valuer::verbose_or_node {
699 0     0   0 my ( $slv, $or_node_id ) = @_;
700 0         0 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
701 0         0 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
702              
703 0         0 my ($text, $nrl_id, $position)
704             = $slv->call_by_tag(
705             ('@' . __FILE__ . ':' . __LINE__),
706             <<'END_OF_LUA', 'i', $or_node_id);
707             local slv, or_node_id = ...
708             local slr = slv.slr
709             local bocage = slv.lmw_b
710             local origin = bocage:_or_node_origin(or_node_id)
711             if not origin then return end
712             local set = bocage:_or_node_set(or_node_id)
713             local position = bocage:_or_node_position(or_node_id)
714             local g1r = slr.g1
715             local origin_earleme = g1r:earleme(origin)
716             local current_earleme = g1r:earleme(set)
717             local text = string.format(
718             'OR-node #%d: R%d:@%d-%d\n',
719             or_node_id,
720             position,
721             origin_earleme,
722             current_earleme,
723             )
724              
725             END_OF_LUA
726 0 0       0 return if not $text;
727              
728 0         0 $text .= ( q{ } x 4 )
729             . $slg->dotted_nrl_show( $nrl_id, $position ) . "\n";
730 0         0 return $text;
731             }
732              
733             # not to be documented
734             sub Marpa::R3::Valuer::bocage_show {
735 3     3   12 my ($slv) = @_;
736              
737 3         15 my ($result) = $slv->call_by_tag(
738             ('@' . __FILE__ . ':' . __LINE__),
739             <<'END_OF_LUA', '');
740             local slv = ...
741             return slv:bocage_show()
742             END_OF_LUA
743              
744 3         17 return $result;
745             }
746              
747             # not to be documented
748             sub Marpa::R3::Valuer::or_nodes_show {
749 4     4   14 my ( $slv ) = @_;
750              
751 4         19 my ($result) = $slv->call_by_tag(
752             ('@' . __FILE__ . ':' . __LINE__),
753             <<'END_OF_LUA', '');
754             local slv = ...
755             return slv:or_nodes_show()
756             END_OF_LUA
757              
758 4         25 return $result;
759             }
760              
761             # not to be documented
762             sub Marpa::R3::Valuer::and_nodes_show {
763 4     4   1887 my ( $slv ) = @_;
764 4         23 my ($result) = $slv->call_by_tag(
765             ('@' . __FILE__ . ':' . __LINE__),
766             <<'END_OF_LUA', '');
767             local slv = ...
768             return slv:and_nodes_show()
769             END_OF_LUA
770              
771 4         26 return $result;
772             }
773              
774             sub Marpa::R3::Valuer::ambiguous {
775 6     6   1523 my ($slv) = @_;
776 6         15 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
777 6         23 my $ambiguity_level = $slv->ambiguity_level();
778 6 50       24 return q{No parse} if $ambiguity_level <= 0;
779 6 100       28 return q{} if $ambiguity_level == 1;
780             # ASF must be created for end location of SLV (not SLR!)
781 4         20 my $asf = Marpa::R3::ASF2->new( { recognizer => $slr, end => $slv->g1_pos() } );
782 4 50       221 die 'Could not create ASF' if not defined $asf;
783 4         27 my $ambiguities = Marpa::R3::Internal_ASF2::ambiguities($asf);
784 4         16 my @ambiguities = grep {defined} @{$ambiguities}[ 0 .. 1 ];
  8         23  
  4         18  
785 4         24 return Marpa::R3::Internal_ASF2::ambiguities_show( $asf, \@ambiguities );
786             } ## end sub Marpa::R3::Recognizer::ambiguous
787              
788             sub Marpa::R3::Valuer::ambiguity_level {
789 1058     1058   4585 my ($slv) = @_;
790              
791 1058         3783 my ($metric) = $slv->call_by_tag(
792             ('@' . __FILE__ . ':' . __LINE__),
793             <<'END__OF_LUA', '>*' );
794             local slv = ...
795             return slv:ambiguity_level()
796             END__OF_LUA
797 1058         2631 return $metric;
798             }
799              
800             sub Marpa::R3::Valuer::g1_pos {
801 5     5   718 my ( $slv ) = @_;
802 5         23 my ($g1_pos) = $slv->call_by_tag(
803             ('@' . __FILE__ . ':' . __LINE__),
804             <<'END__OF_LUA', '>*' );
805             local slv = ...
806             return slv:g1_pos()
807             END__OF_LUA
808 5         74 return $g1_pos;
809             }
810              
811             # not to be documented
812             sub Marpa::R3::Valuer::regix {
813 0     0     my ( $slv ) = @_;
814 0           my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
815 0           return $regix;
816             }
817              
818             1;
819              
820             # vim: expandtab shiftwidth=4: