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   1852 use 5.010001;
  104         337  
15 104     104   529 use strict;
  104         185  
  104         2231  
16 104     104   459 use warnings;
  104         196  
  104         2966  
17              
18 104     104   474 use vars qw($VERSION $STRING_VERSION);
  104         203  
  104         7383  
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_V;
26              
27 104     104   610 use Scalar::Util qw(blessed tainted);
  104         197  
  104         5784  
28 104     104   577 use English qw( -no_match_vars );
  104         649  
  104         688  
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 1144     1144   2274 my ( $slv, $flat_args ) = @_;
35 1144 100       3021 if ( my $value = $flat_args->{'trace_file_handle'} ) {
36 2         4 $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE] = $value;
37             }
38 1144         2222 my $trace_file_handle =
39             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
40 1144         1795 delete $flat_args->{'trace_file_handle'};
41 1144         2041 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   80 if ( scalar @_ == 1 and ref $_[0] ) {
48 2         16 die bless { exception_object => $_[0] }, $CONTEXT_EXCEPTION_CLASS;
49             }
50 2         9 my $error_string = join q{}, @_;
51 2         8 my ( $package, $filename, $line ) = caller;
52 2         6 chomp $error_string;
53 2         36 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   22 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   35 my $slv = $Marpa::R3::Context::valuer;
71 8         21 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         24 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   28 my $args = shift;
97              
98 10         25 my $grammar;
99             my $fatal_error;
100 10         23 my $warnings = [];
101 10         48 my $where = '?where?';
102 10         19 my $long_where;
103 10         20 my @msg = ();
104 10         17 my $eval_value;
105 10         14 my $eval_given = 0;
106              
107 10         35 push @msg, q{=} x 60, "\n";
108 10         15 ARG: for my $arg ( keys %{$args} ) {
  10         46  
109 50         71 my $value = $args->{$arg};
110 50 100       106 if ( $arg eq 'fatal_error' ) { $fatal_error = $value; next ARG }
  10         20  
  10         17  
111 40 50       67 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         16  
  10         132  
113 30 100       59 if ( $arg eq 'long_where' ) { $long_where = $value; next ARG }
  10         17  
  10         20  
114 20 100       48 if ( $arg eq 'warnings' ) { $warnings = $value; next ARG }
  10         183  
  10         190  
115 10 50       26 if ( $arg eq 'eval_ok' ) {
116 10         23 $eval_value = $value;
117 10         14 $eval_given = 1;
118 10         18 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         23 my $fatal_error_ref_type = ref $fatal_error;
  10         21  
125 10 100       34 last GIVEN_FATAL_ERROR_REF_TYPE if not $fatal_error_ref_type;
126 4 50       12 if ( $fatal_error_ref_type eq $CONTEXT_EXCEPTION_CLASS ) {
127 4         11 my $exception_object = $fatal_error->{exception_object};
128 4 100       27 die $exception_object if defined $exception_object;
129 2         5 my $exception_message = $fatal_error->{message};
130 2 50       26 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         14 my @problem_line = ();
142 6         9 my $max_problem_line = -1;
143 6         11 for my $warning_data ( @{$warnings} ) {
  6         20  
144 4         5 my ( $warning, $package, $filename, $problem_line ) = @{$warning_data};
  4         15  
145 4         10 $problem_line[$problem_line] = 1;
146 4         14 $max_problem_line = List::Util::max $problem_line, $max_problem_line;
147             } ## end for my $warning_data ( @{$warnings} )
148              
149 6   33     18 $long_where //= $where;
150              
151 6         10 my $warnings_count = scalar @{$warnings};
  6         14  
152             {
153 6         7 my @problems;
  6         10  
154 6   66     41 my $false_eval = $eval_given && !$eval_value && !$fatal_error;
155 6 50       18 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       14 if ($fatal_error) {
160 4         10 push @problems, '* THE MARPA SEMANTICS PRODUCED A FATAL ERROR';
161             }
162 6 100       15 if ($warnings_count) {
163 2         7 push @problems,
164             "* THERE WERE $warnings_count WARNING(S) IN THE MARPA SEMANTICS:",
165             'Marpa treats warnings as fatal errors';
166             }
167 6 50       15 if ( not scalar @problems ) {
168 0         0 push @msg, '* THERE WAS A FATAL PROBLEM IN THE MARPA SEMANTICS';
169             }
170 6         25 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         23 for my $warning_ix ( 0 .. ( $warnings_count - 1 ) ) {
177 4         24 push @msg, "* WARNING MESSAGE NUMBER $warning_ix:\n";
178 4         9 my $warning_message = $warnings->[$warning_ix]->[0];
179 4         34 $warning_message =~ s/\n*\z/\n/xms;
180 4         13 push @msg, $warning_message;
181             } ## end for my $warning_ix ( 0 .. ( $warnings_count - 1 ) )
182              
183 6 100       16 if ($fatal_error) {
184 4         9 push @msg, "* THIS WAS THE FATAL ERROR MESSAGE:\n";
185 4         10 my $fatal_error_message = $fatal_error;
186 4         50 $fatal_error_message =~ s/\n*\z/\n/xms;
187 4         8 push @msg, $fatal_error_message;
188             } ## end if ($fatal_error)
189              
190 6         31 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 1141     1141   12052 my ( $class, @args ) = @_;
199              
200 1141         2300 my $slv = [];
201              
202             # Set recognizer args to default
203             # Lua equivalent is set below
204              
205 1141         4298 my ( $flat_args, $error_message ) = Marpa::R3::flatten_hash_args( \@args );
206 1141 50       3018 Marpa::R3::exception( sprintf $error_message, '$slv->new' )
207             if not $flat_args;
208 1141         3410 $flat_args = slv_common_set( $slv, $flat_args );
209              
210 1141         2167 my $slr = $flat_args->{recognizer};
211 1141 50       2646 Marpa::R3::exception(
212             qq{Marpa::R3::Valuer::new() called without a "recognizer" argument} )
213             if not defined $slr;
214 1141         2361 $slv->[Marpa::R3::Internal_V::SLR] = $slr;
215 1141         1931 delete $flat_args->{recognizer};
216              
217 1141         1787 my $slr_class = 'Marpa::R3::Recognizer';
218 1141 50 33     11904 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 1141   33     5889 $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE] //=
228             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
229              
230 1141         1882 my $trace_file_handle =
231             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
232              
233 1141         1736 my $lua = $slr->[Marpa::R3::Internal_R::L];
234 1141         1882 $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 1141         10257 <<'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 1141 50       7617 return if $regix < 0;
259 1141         2317 $slv->[Marpa::R3::Internal_V::REGIX] = $regix;
260              
261 1141         4809 return bless $slv, $class;
262             }
263              
264             sub Marpa::R3::Valuer::DESTROY {
265             # say STDERR "In Marpa::R3::Valuer::DESTROY before test";
266 1141     1141   47232 my $slv = shift;
267 1141         2038 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 1141 50       13222 return if not $lua;
277             # say STDERR "In Marpa::R3::Valuer::DESTROY after test";
278              
279 1141         1783 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
280 1141         3462 $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   839 my ( $slv, @args ) = @_;
291              
292 3         11 my ($flat_args, $error_message) = Marpa::R3::flatten_hash_args(\@args);
293 3 50       8 Marpa::R3::exception( sprintf $error_message, '$slv->set()' ) if not $flat_args;
294 3         5 $flat_args = slv_common_set($slv, $flat_args);
295 3         6 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         2 return 'ok';
308             }
309             }
310             },
311 3         21 <<'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         17 return;
319             }
320              
321             # Returns false if no parse
322             sub Marpa::R3::Valuer::value {
323 2488     2488   62875 my ( $slv, $per_parse_arg ) = @_;
324 2488         7200 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
325 2488         3984 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
326              
327 2488   50     8280 my $trace_actions =
328             $slg->[Marpa::R3::Internal_G::TRACE_ACTIONS] // 0;
329 2488         3387 my $trace_file_handle =
330             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
331              
332 2488   100     6618 my $semantics_arg0 = $per_parse_arg // {};
333 2488         3690 my $constants = $slg->[Marpa::R3::Internal_G::CONSTANTS];
334 2488         3264 my $null_values = $slg->[Marpa::R3::Internal_G::NULL_VALUES];
335 2488         3261 my $nulling_closures =
336             $slg->[Marpa::R3::Internal_G::CLOSURE_BY_SYMBOL_ID];
337 2488         3233 my $rule_closures =
338             $slg->[Marpa::R3::Internal_G::CLOSURE_BY_RULE_ID];
339              
340 2488         5042 local $Marpa::R3::Context::rule = undef;
341 2488         3739 local $Marpa::R3::Context::irlid = undef;
342 2488         3160 local $Marpa::R3::Context::grammar = $slg;
343 2488         3145 local $Marpa::R3::Context::recognizer = $slr;
344 2488         3301 local $Marpa::R3::Context::valuer = $slv;
345              
346             my %value_handlers = (
347             trace => sub {
348 108     108   157 my ($msg) = @_;
349 108 50       231 my $nl = ( $msg =~ /\n\z/xms ) ? '' : "\n";
350 108         114 print {$trace_file_handle} $msg, $nl;
  108         297  
351 108         205 return 'ok';
352             },
353             terse_dump => sub {
354 10     10   25 my ($value) = @_;
355 10         48 my $dumped = Data::Dumper->new( [$value] )->Terse(1)->Dump;
356 10         435 chomp $dumped;
357 10         25 return 'ok', $dumped;
358             },
359             constant => sub {
360 5874     5874   7992 my ($constant_ix) = @_;
361 5874         8199 my $constant = $constants->[$constant_ix];
362 5874         12211 return 'sig', [ 'S', $constant ];
363             },
364             perl_undef => sub {
365 2096     2096   4978 return 'sig', [ 'S', undef ];
366             },
367             bless => sub {
368 46767     46767   62991 my ( $value, $blessing_ix ) = @_;
369 46767         63289 my $blessing_data = $constants->[$blessing_ix];
370 46767         49592 my ( $irlid, $lexeme_id, $blessing ) = @{$blessing_data};
  46767         79677  
371 46767         69290 my $lexeme_name;
372 46767 100       75376 if ( defined $lexeme_id ) {
373 9744         29163 $lexeme_name = $slg->g1_symbol_name($lexeme_id);
374             }
375             else {
376 37023         59474 $lexeme_name = "[IRL# $irlid]";
377             }
378              
379             FIND_BASE_BLESSING: {
380 46767 100       51889 if ( $blessing eq '::name' ) {
  46767         77042  
381 9744 50       25148 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 9744         12239 $blessing = $lexeme_name;
388 9744         32108 $blessing =~ s/[ ]/_/gxms;
389 9744         16597 last FIND_BASE_BLESSING;
390             } ## end if ( $default_blessing eq '::name' )
391 37023 50       70071 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 37023 50       78055 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 46767 50       75568 if ( $blessing !~ / :: /xms ) {
408 46767         61272 my $bless_package =
409             $slg->[Marpa::R3::Internal_G::BLESS_PACKAGE];
410 46767 50       73552 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 46767         85367 $blessing = $bless_package . q{::} . $blessing;
416             }
417 46767         146654 return 'sig', [ 'S', ( bless $value, $blessing ) ];
418             },
419             perl_nulling_semantics => sub {
420 147     147   257 my ($token_id) = @_;
421 147         493 my $value_ref = $nulling_closures->[$token_id];
422 147         294 my $result;
423             my @warnings;
424 147         0 my $eval_ok;
425             DO_EVAL: {
426 147         171 local $SIG{__WARN__} = sub {
427 0         0 push @warnings, [ $_[0], ( caller 0 ) ];
428 147         856 };
429 147         381 $eval_ok = eval {
430 147         211 my $irlid = $null_values->[$token_id];
431 147         211 local $Marpa::R3::Context::irlid = $irlid;
432 147         577 local $Marpa::R3::Context::production_id =
433             $slg->g1_rule_to_production_id($irlid);
434 147         532 $result = $value_ref->( $semantics_arg0, [] );
435 147         1248 1;
436             };
437             } ## end DO_EVAL:
438 147 50 33     585 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         393 return 'sig', [ 'S', $result ];
452             },
453             perl_rule_semantics => sub {
454 7512     7512   10717 my ( $irlid, $values ) = @_;
455             # say Data::Dumper::Dumper($values);
456 7512         9986 my $closure = $rule_closures->[$irlid];
457 7512         8142 my $result;
458 7512 50       12566 if ( defined $closure ) {
459 7512         8879 my @warnings;
460             my $eval_ok;
461             local $SIG{__WARN__} = sub {
462 4         75 push @warnings, [ $_[0], ( caller 0 ) ];
463 7512         34586 };
464 7512         11965 local $Marpa::R3::Context::irlid = $irlid;
465 7512         15733 local $Marpa::R3::Context::production_id =
466             $slg->g1_rule_to_production_id($irlid);
467 7512         9060 $eval_ok = eval {
468 7512         13254 $result = $closure->( $semantics_arg0, $values );
469 7504         71073 1;
470             };
471 7512 100 100     41079 if ( not $eval_ok or @warnings ) {
472 10         21 my $fatal_error = $EVAL_ERROR;
473 10         51 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         18451 return 'sig', [ 'S', $result ];
486             }
487 2488         34981 );
488              
489 2488         11947 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 2478 100       9572 return if $cmd ne 'ok';
503 2420         55866 return \($final_value);
504              
505             }
506              
507             # not to be documented
508             sub Marpa::R3::Valuer::call_by_tag {
509 2451     2451   5713 my ( $slv, $tag, $codestr, $signature, @args ) = @_;
510 2451         4330 my $lua = $slv->[Marpa::R3::Internal_V::L];
511 2451         3518 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
512              
513 2451         5134 my @results;
514             my $eval_error;
515 2451         0 my $eval_ok;
516             {
517 2451         3118 local $@;
  2451         3302  
518 2451         3581 $eval_ok = eval {
519 2451         27097 @results =
520             $lua->call_by_tag( $regix, $tag, $codestr, $signature, @args );
521 2451         4967 return 1;
522             };
523 2451         4770 $eval_error = $@;
524             }
525 2451 50       5066 if ( not $eval_ok ) {
526 0         0 Marpa::R3::exception($eval_error);
527             }
528 2451         7319 return @results;
529             }
530              
531             # not to be documented
532             sub Marpa::R3::Valuer::coro_by_tag {
533 2491     2491   5499 my ( $slv, $tag, $args, $codestr ) = @_;
534 2491         3451 my $lua = $slv->[Marpa::R3::Internal_V::L];
535 2491         3444 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
536 2491   50     5933 my $handler = $args->{handlers} // {};
537 2491         4655 my $resume_tag = $tag . '[R]';
538 2491   50     4769 my $signature = $args->{signature} // '';
539 2491   50     4762 my $p_args = $args->{args} // [];
540              
541 2491         4844 my @results;
542             my $eval_error;
543 2491         0 my $eval_ok;
544             {
545 2491         3550 local $@;
  2491         2941  
546 2491         3599 $eval_ok = eval {
547 2491         3478 $lua->call_by_tag( $regix, $tag, $codestr, $signature, @{$p_args} );
  2491         28418  
548 2491         5726 my @resume_args = ('');
549 2491         3557 my $signature = 's';
550 2491         2963 CORO_CALL: while (1) {
551 64996         1964257 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 64996 100       171371 if (not $cmd) {
556 2481         3628 @results = @{$yield_data};
  2481         5512  
557 2481         6837 return 1;
558             }
559 62515         95637 my $handler = $handler->{$cmd};
560 62515 50       92417 Marpa::R3::exception(qq{No coro handler for "$cmd"})
561             if not $handler;
562 62515   50     99190 $yield_data //= [];
563 62515         67846 my ($handler_cmd, $new_resume_args) = $handler->(@{$yield_data});
  62515         106586  
564 62505 50       108152 Marpa::R3::exception(qq{Undefined return command from handler for "$cmd"})
565             if not defined $handler_cmd;
566 62505 100       99476 if ($handler_cmd eq 'ok') {
567 119         129 $signature = 's';
568 119         175 @resume_args = ($new_resume_args);
569 119 50       193 if (scalar @resume_args < 1) {
570 0         0 @resume_args = ('');
571             }
572 119         208 next CORO_CALL;
573             }
574 62386 50       88582 if ($handler_cmd eq 'sig') {
575 62386         64113 @resume_args = @{$new_resume_args};
  62386         108491  
576 62386         82621 $signature = shift @resume_args;
577 62386         128541 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 2491         5140 $eval_error = $@;
584             }
585 2491 100       5187 if ( not $eval_ok ) {
586             # if it's an object, just die
587 10 100       161 die $eval_error if ref $eval_error;
588 8         31 Marpa::R3::exception($eval_error);
589             }
590 2481         7390 return @results;
591             }
592              
593             # not to be documented
594             sub Marpa::R3::Valuer::tree_show {
595 4     4   1458 my ( $slv, $verbose ) = @_;
596 4         7 my $text = q{};
597 4         7 NOOK: for ( my $nook_id = 0; 1; $nook_id++ ) {
598 44         71 my $nook_text = $slv->nook_show( $nook_id, $verbose );
599 44 100       72 last NOOK if not defined $nook_text;
600 40         79 $text .= "$nook_id: $nook_text";
601             }
602 4         20 return $text;
603             }
604              
605             # not to be documented
606             sub Marpa::R3::Valuer::nook_show {
607 44     44   68 my ( $slv, $nook_id, $verbose ) = @_;
608 44         56 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
609              
610 44         74 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       78 return if not defined $or_node_id;
653              
654             DESCRIBE_CHOICES: {
655 40         44 my $this_choice;
  40         42  
656 40         70 ($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         49 CHOICE: for ( my $choice_ix = 0;; $choice_ix++ ) {
662              
663 89         162 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       163 last CHOICE if not defined $and_node_id;
671 49         111 $text .= " o$or_node_id" . '[' . $choice_ix . ']';
672 49 100 66     134 if ( defined $this_choice and $this_choice == $choice_ix ) {
673 40         46 $text .= q{*};
674             }
675 49         73 my $and_node_tag =
676             $slv->and_node_tag( $and_node_id );
677 49         88 $text .= " ::= a$and_node_id $and_node_tag";
678 49         71 $text .= "\n";
679             } ## end CHOICE: for ( my $choice_ix = 0;; $choice_ix++ )
680             } ## end DESCRIBE_CHOICES:
681 40         70 return $text;
682             }
683              
684             # not to be documented
685             sub Marpa::R3::Valuer::and_node_tag {
686 49     49   63 my ( $slv, $and_node_id ) = @_;
687              
688 49         89 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         81 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   10 my ($slv) = @_;
736              
737 3         13 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         15 return $result;
745             }
746              
747             # not to be documented
748             sub Marpa::R3::Valuer::or_nodes_show {
749 4     4   12 my ( $slv ) = @_;
750              
751 4         17 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         24 return $result;
759             }
760              
761             # not to be documented
762             sub Marpa::R3::Valuer::and_nodes_show {
763 4     4   1507 my ( $slv ) = @_;
764 4         18 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         21 return $result;
772             }
773              
774             sub Marpa::R3::Valuer::ambiguous {
775 7     7   1186 my ($slv) = @_;
776 7         20 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
777 7         25 my $ambiguity_level = $slv->ambiguity_level();
778 7 50       26 return q{No parse} if $ambiguity_level <= 0;
779 7 100       28 return q{} if $ambiguity_level == 1;
780             # ASF must be created for end location of SLV (not SLR!)
781 5         20 my $asf = Marpa::R3::ASF2->new( { recognizer => $slr, end => $slv->g1_pos() } );
782 5 50       263 die 'Could not create ASF' if not defined $asf;
783 5         33 my $ambiguities = Marpa::R3::Internal_ASF2::ambiguities($asf);
784 5         17 my @ambiguities = grep {defined} @{$ambiguities}[ 0 .. 1 ];
  10         23  
  5         13  
785 5         34 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 1061     1061   3941 my ($slv) = @_;
790              
791 1061         3789 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 1061         2673 return $metric;
798             }
799              
800             sub Marpa::R3::Valuer::g1_pos {
801 6     6   569 my ( $slv ) = @_;
802 6         21 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 6         64 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: