File Coverage

blib/lib/Marpa/R3/SLV.pm
Criterion Covered Total %
statement 333 372 89.5
branch 76 106 71.7
condition 20 36 55.5
subroutine 34 38 89.4
pod n/a
total 463 552 83.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::Valuer;
13              
14 101     101   2200 use 5.010001;
  101         421  
15 101     101   667 use strict;
  101         245  
  101         2807  
16 101     101   600 use warnings;
  101         257  
  101         4145  
17              
18 101     101   654 use vars qw($VERSION $STRING_VERSION);
  101         248  
  101         9243  
19             $VERSION = '4.001_052';
20             $STRING_VERSION = $VERSION;
21             ## no critic(BuiltinFunctions::ProhibitStringyEval)
22             $VERSION = eval $VERSION;
23             ## use critic
24              
25             package Marpa::R3::Internal_V;
26              
27 101     101   796 use Scalar::Util qw(blessed tainted);
  101         260  
  101         7297  
28 101     101   748 use English qw( -no_match_vars );
  101         259  
  101         831  
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 1131     1131   2806 my ( $slv, $flat_args ) = @_;
35 1131 100       3800 if ( my $value = $flat_args->{'trace_file_handle'} ) {
36 2         6 $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE] = $value;
37             }
38 1131         2575 my $trace_file_handle =
39             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
40 1131         2129 delete $flat_args->{'trace_file_handle'};
41 1131         2461 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   86 if ( scalar @_ == 1 and ref $_[0] ) {
48 2         17 die bless { exception_object => $_[0] }, $CONTEXT_EXCEPTION_CLASS;
49             }
50 2         10 my $error_string = join q{}, @_;
51 2         10 my ( $package, $filename, $line ) = caller;
52 2         7 chomp $error_string;
53 2         39 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   26 my $slv = $Marpa::R3::Context::valuer;
61 2         10 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         17 return $start, $end;
67             } ## end sub Marpa::R3::Context::g1_range
68              
69             sub Marpa::R3::Context::lc_range {
70 8     8   43 my $slv = $Marpa::R3::Context::valuer;
71 8         26 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         30 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   30 my $args = shift;
97              
98 10         28 my $grammar;
99             my $fatal_error;
100 10         30 my $warnings = [];
101 10         26 my $where = '?where?';
102 10         20 my $long_where;
103 10         28 my @msg = ();
104 10         27 my $eval_value;
105 10         26 my $eval_given = 0;
106              
107 10         50 push @msg, q{=} x 60, "\n";
108 10         24 ARG: for my $arg ( keys %{$args} ) {
  10         58  
109 50         108 my $value = $args->{$arg};
110 50 100       131 if ( $arg eq 'fatal_error' ) { $fatal_error = $value; next ARG }
  10         25  
  10         21  
111 40 50       96 if ( $arg eq 'grammar' ) { $grammar = $value; next ARG }
  0         0  
  0         0  
112 40 100       95 if ( $arg eq 'where' ) { $where = $value; next ARG }
  10         24  
  10         28  
113 30 100       83 if ( $arg eq 'long_where' ) { $long_where = $value; next ARG }
  10         29  
  10         25  
114 20 100       62 if ( $arg eq 'warnings' ) { $warnings = $value; next ARG }
  10         25  
  10         167  
115 10 50       40 if ( $arg eq 'eval_ok' ) {
116 10         24 $eval_value = $value;
117 10         23 $eval_given = 1;
118 10         27 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         26 my $fatal_error_ref_type = ref $fatal_error;
  10         29  
125 10 100       49 last GIVEN_FATAL_ERROR_REF_TYPE if not $fatal_error_ref_type;
126 4 50       14 if ( $fatal_error_ref_type eq $CONTEXT_EXCEPTION_CLASS ) {
127 4         11 my $exception_object = $fatal_error->{exception_object};
128 4 100       35 die $exception_object if defined $exception_object;
129 2         220 my $exception_message = $fatal_error->{message};
130 2 50       137 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         21 my @problem_line = ();
142 6         15 my $max_problem_line = -1;
143 6         13 for my $warning_data ( @{$warnings} ) {
  6         21  
144 4         9 my ( $warning, $package, $filename, $problem_line ) = @{$warning_data};
  4         15  
145 4         13 $problem_line[$problem_line] = 1;
146 4         21 $max_problem_line = List::Util::max $problem_line, $max_problem_line;
147             } ## end for my $warning_data ( @{$warnings} )
148              
149 6   33     27 $long_where //= $where;
150              
151 6         15 my $warnings_count = scalar @{$warnings};
  6         18  
152             {
153 6         17 my @problems;
  6         15  
154 6   66     49 my $false_eval = $eval_given && !$eval_value && !$fatal_error;
155 6 50       26 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       19 if ($fatal_error) {
160 4         9 push @problems, '* THE MARPA SEMANTICS PRODUCED A FATAL ERROR';
161             }
162 6 100       22 if ($warnings_count) {
163 2         13 push @problems,
164             "* THERE WERE $warnings_count WARNING(S) IN THE MARPA SEMANTICS:",
165             'Marpa treats warnings as fatal errors';
166             }
167 6 50       29 if ( not scalar @problems ) {
168 0         0 push @msg, '* THERE WAS A FATAL PROBLEM IN THE MARPA SEMANTICS';
169             }
170 6         34 push @msg, ( join "\n", @problems ) . "\n";
171             }
172              
173 6         29 push @msg, "* THIS IS WHAT MARPA WAS DOING WHEN THE PROBLEM OCCURRED:\n"
174             . $long_where . "\n";
175              
176 6         26 for my $warning_ix ( 0 .. ( $warnings_count - 1 ) ) {
177 4         17 push @msg, "* WARNING MESSAGE NUMBER $warning_ix:\n";
178 4         13 my $warning_message = $warnings->[$warning_ix]->[0];
179 4         59 $warning_message =~ s/\n*\z/\n/xms;
180 4         19 push @msg, $warning_message;
181             } ## end for my $warning_ix ( 0 .. ( $warnings_count - 1 ) )
182              
183 6 100       26 if ($fatal_error) {
184 4         11 push @msg, "* THIS WAS THE FATAL ERROR MESSAGE:\n";
185 4         11 my $fatal_error_message = $fatal_error;
186 4         60 $fatal_error_message =~ s/\n*\z/\n/xms;
187 4         14 push @msg, $fatal_error_message;
188             } ## end if ($fatal_error)
189              
190 6         34 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 1128     1128   7485 my ( $class, @args ) = @_;
199              
200 1128         3033 my $slv = [];
201              
202             # Set recognizer args to default
203             # Lua equivalent is set below
204              
205 1128         5579 my ( $flat_args, $error_message ) = Marpa::R3::flatten_hash_args( \@args );
206 1128 50       3652 Marpa::R3::exception( sprintf $error_message, '$slv->new' )
207             if not $flat_args;
208 1128         4008 $flat_args = slv_common_set( $slv, $flat_args );
209              
210 1128         2515 my $slr = $flat_args->{recognizer};
211 1128 50       3341 Marpa::R3::exception(
212             qq{Marpa::R3::Valuer::new() called without a "recognizer" argument} )
213             if not defined $slr;
214 1128         2778 $slv->[Marpa::R3::Internal_V::SLR] = $slr;
215 1128         2487 delete $flat_args->{recognizer};
216              
217 1128         2286 my $slr_class = 'Marpa::R3::Recognizer';
218 1128 50 33     12703 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 1128   33     7353 $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE] //=
228             $slr->[Marpa::R3::Internal_R::TRACE_FILE_HANDLE];
229              
230 1128         2347 my $trace_file_handle =
231             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
232              
233 1128         2237 my $lua = $slr->[Marpa::R3::Internal_R::L];
234 1128         2256 $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 1128         13038 <<'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 1128 50       9114 return if $regix < 0;
259 1128         3095 $slv->[Marpa::R3::Internal_V::REGIX] = $regix;
260              
261 1128         5594 return bless $slv, $class;
262             }
263              
264             sub Marpa::R3::Valuer::DESTROY {
265             # say STDERR "In Marpa::R3::Valuer::DESTROY before test";
266 1128     1128   46479 my $slv = shift;
267 1128         2575 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 1128 50       4087 return if not $lua;
277             # say STDERR "In Marpa::R3::Valuer::DESTROY after test";
278              
279 1128         2316 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
280 1128         4523 $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   971 my ( $slv, @args ) = @_;
291              
292 3         14 my ($flat_args, $error_message) = Marpa::R3::flatten_hash_args(\@args);
293 3 50       11 Marpa::R3::exception( sprintf $error_message, '$slv->set()' ) if not $flat_args;
294 3         10 $flat_args = slv_common_set($slv, $flat_args);
295 3         8 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   3 my ($msg) = @_;
306 1         2 say {$trace_file_handle} $msg;
  1         5  
307 1         4 return 'ok';
308             }
309             }
310             },
311 3         33 <<'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         26 return;
319             }
320              
321             # Returns false if no parse
322             sub Marpa::R3::Valuer::value {
323 2446     2446   62559 my ( $slv, $per_parse_arg ) = @_;
324 2446         4959 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
325 2446         4600 my $slg = $slr->[Marpa::R3::Internal_R::SLG];
326              
327 2446   50     9564 my $trace_actions =
328             $slg->[Marpa::R3::Internal_G::TRACE_ACTIONS] // 0;
329 2446         4453 my $trace_file_handle =
330             $slv->[Marpa::R3::Internal_V::TRACE_FILE_HANDLE];
331              
332 2446   100     8454 my $semantics_arg0 = $per_parse_arg // {};
333 2446         4843 my $constants = $slg->[Marpa::R3::Internal_G::CONSTANTS];
334 2446         4130 my $null_values = $slg->[Marpa::R3::Internal_G::NULL_VALUES];
335 2446         4406 my $nulling_closures =
336             $slg->[Marpa::R3::Internal_G::CLOSURE_BY_SYMBOL_ID];
337 2446         4282 my $rule_closures =
338             $slg->[Marpa::R3::Internal_G::CLOSURE_BY_RULE_ID];
339              
340 2446         4454 local $Marpa::R3::Context::rule = undef;
341 2446         3852 local $Marpa::R3::Context::irlid = undef;
342 2446         4067 local $Marpa::R3::Context::grammar = $slg;
343 2446         3977 local $Marpa::R3::Context::recognizer = $slr;
344 2446         4097 local $Marpa::R3::Context::valuer = $slv;
345              
346             my %value_handlers = (
347             trace => sub {
348 111     111   187 my ($msg) = @_;
349 111 100       316 my $nl = ( $msg =~ /\n\z/xms ) ? '' : "\n";
350 111         159 print {$trace_file_handle} $msg, $nl;
  111         368  
351 111         266 return 'ok';
352             },
353             terse_dump => sub {
354 10     10   20 my ($value) = @_;
355 10         66 my $dumped = Data::Dumper->new( [$value] )->Terse(1)->Dump;
356 10         471 chomp $dumped;
357 10         29 return 'ok', $dumped;
358             },
359             constant => sub {
360 5874     5874   11307 my ($constant_ix) = @_;
361 5874         12513 my $constant = $constants->[$constant_ix];
362 5874         18380 return 'sig', [ 'S', $constant ];
363             },
364             perl_undef => sub {
365 2049     2049   5945 return 'sig', [ 'S', undef ];
366             },
367             bless => sub {
368 46338     46338   79974 my ( $value, $blessing_ix ) = @_;
369 46338         80106 my $blessing_data = $constants->[$blessing_ix];
370 46338         61287 my ( $irlid, $lexeme_id, $blessing ) = @{$blessing_data};
  46338         100437  
371 46338         68316 my $lexeme_name;
372 46338 100       85749 if ( defined $lexeme_id ) {
373 9653         34973 $lexeme_name = $slg->g1_symbol_name($lexeme_id);
374             }
375             else {
376 36685         76055 $lexeme_name = "[IRL# $irlid]";
377             }
378              
379             FIND_BASE_BLESSING: {
380 46338 100       66107 if ( $blessing eq '::name' ) {
  46338         96029  
381 9653 50       30445 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 9653         15804 $blessing = $lexeme_name;
388 9653         37854 $blessing =~ s/[ ]/_/gxms;
389 9653         20701 last FIND_BASE_BLESSING;
390             } ## end if ( $default_blessing eq '::name' )
391 36685 50       88309 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 36685 50       96167 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 46338 50       97121 if ( $blessing !~ / :: /xms ) {
408 46338         79017 my $bless_package =
409             $slg->[Marpa::R3::Internal_G::BLESS_PACKAGE];
410 46338 50       84632 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 46338         100344 $blessing = $bless_package . q{::} . $blessing;
416             }
417 46338         183656 return 'sig', [ 'S', ( bless $value, $blessing ) ];
418             },
419             perl_nulling_semantics => sub {
420 147     147   655 my ($token_id) = @_;
421 147         302 my $value_ref = $nulling_closures->[$token_id];
422 147         386 my $result;
423             my @warnings;
424 147         0 my $eval_ok;
425             DO_EVAL: {
426 147         226 local $SIG{__WARN__} = sub {
427 0         0 push @warnings, [ $_[0], ( caller 0 ) ];
428 147         1306 };
429 147         428 $eval_ok = eval {
430 147         303 my $irlid = $null_values->[$token_id];
431 147         260 local $Marpa::R3::Context::irlid = $irlid;
432 147         604 local $Marpa::R3::Context::production_id =
433             $slg->g1_rule_to_production_id($irlid);
434 147         746 $result = $value_ref->( $semantics_arg0, [] );
435 147         1825 1;
436             };
437             } ## end DO_EVAL:
438 147 50 33     803 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         614 return 'sig', [ 'S', $result ];
452             },
453             perl_rule_semantics => sub {
454 7512     7512   12799 my ( $irlid, $values ) = @_;
455             # say Data::Dumper::Dumper($values);
456 7512         11758 my $closure = $rule_closures->[$irlid];
457 7512         9072 my $result;
458 7512 50       13513 if ( defined $closure ) {
459 7512         10280 my @warnings;
460             my $eval_ok;
461             local $SIG{__WARN__} = sub {
462 4         113 push @warnings, [ $_[0], ( caller 0 ) ];
463 7512         39928 };
464 7512         13420 local $Marpa::R3::Context::irlid = $irlid;
465 7512         21407 local $Marpa::R3::Context::production_id =
466             $slg->g1_rule_to_production_id($irlid);
467 7512         10667 $eval_ok = eval {
468 7512         15865 $result = $closure->( $semantics_arg0, $values );
469 7504         82583 1;
470             };
471 7512 100 100     48619 if ( not $eval_ok or @warnings ) {
472 10         28 my $fatal_error = $EVAL_ERROR;
473 10         65 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         23456 return 'sig', [ 'S', $result ];
486             }
487 2446         44025 );
488              
489 2446         14984 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 2436 100       11704 return if $cmd ne 'ok';
503 2385         69301 return \($final_value);
504              
505             }
506              
507             # not to be documented
508             sub Marpa::R3::Valuer::call_by_tag {
509 2450     2450   7047 my ( $slv, $tag, $codestr, $signature, @args ) = @_;
510 2450         5387 my $lua = $slv->[Marpa::R3::Internal_V::L];
511 2450         4268 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
512              
513 2450         6259 my @results;
514             my $eval_error;
515 2450         0 my $eval_ok;
516             {
517 2450         3829 local $@;
  2450         3968  
518 2450         4706 $eval_ok = eval {
519 2450         35256 @results =
520             $lua->call_by_tag( $regix, $tag, $codestr, $signature, @args );
521 2450         6648 return 1;
522             };
523 2450         6074 $eval_error = $@;
524             }
525 2450 50       6438 if ( not $eval_ok ) {
526 0         0 Marpa::R3::exception($eval_error);
527             }
528 2450         9596 return @results;
529             }
530              
531             # not to be documented
532             sub Marpa::R3::Valuer::coro_by_tag {
533 2449     2449   6593 my ( $slv, $tag, $args, $codestr ) = @_;
534 2449         4875 my $lua = $slv->[Marpa::R3::Internal_V::L];
535 2449         4197 my $regix = $slv->[Marpa::R3::Internal_V::REGIX];
536 2449   50     6817 my $handler = $args->{handlers} // {};
537 2449         5900 my $resume_tag = $tag . '[R]';
538 2449   50     5900 my $signature = $args->{signature} // '';
539 2449   50     6025 my $p_args = $args->{args} // [];
540              
541 2449         5964 my @results;
542             my $eval_error;
543 2449         0 my $eval_ok;
544             {
545 2449         3805 local $@;
  2449         3649  
546 2449         4703 $eval_ok = eval {
547 2449         4307 $lua->call_by_tag( $regix, $tag, $codestr, $signature, @{$p_args} );
  2449         34461  
548 2449         7681 my @resume_args = ('');
549 2449         4362 my $signature = 's';
550 2449         3930 CORO_CALL: while (1) {
551 64481         2477973 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 64481 100       215359 if (not $cmd) {
556 2439         4267 @results = @{$yield_data};
  2439         6592  
557 2439         8543 return 1;
558             }
559 62042         125508 my $handler = $handler->{$cmd};
560 62042 50       117121 Marpa::R3::exception(qq{No coro handler for "$cmd"})
561             if not $handler;
562 62042   50     112047 $yield_data //= [];
563 62042         87178 my ($handler_cmd, $new_resume_args) = $handler->(@{$yield_data});
  62042         135345  
564 62032 50       136876 Marpa::R3::exception(qq{Undefined return command from handler for "$cmd"})
565             if not defined $handler_cmd;
566 62032 100       118965 if ($handler_cmd eq 'ok') {
567 122         171 $signature = 's';
568 122         220 @resume_args = ($new_resume_args);
569 122 50       234 if (scalar @resume_args < 1) {
570 0         0 @resume_args = ('');
571             }
572 122         250 next CORO_CALL;
573             }
574 61910 50       113413 if ($handler_cmd eq 'sig') {
575 61910         80607 @resume_args = @{$new_resume_args};
  61910         133270  
576 61910         104636 $signature = shift @resume_args;
577 61910         148375 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 2449         5967 $eval_error = $@;
584             }
585 2449 100       6095 if ( not $eval_ok ) {
586             # if it's an object, just die
587 10 100       47 die $eval_error if ref $eval_error;
588 8         35 Marpa::R3::exception($eval_error);
589             }
590 2439         9309 return @results;
591             }
592              
593             # not to be documented
594             sub Marpa::R3::Valuer::tree_show {
595 4     4   1550 my ( $slv, $verbose ) = @_;
596 4         8 my $text = q{};
597 4         9 NOOK: for ( my $nook_id = 0; 1; $nook_id++ ) {
598 48         108 my $nook_text = $slv->nook_show( $nook_id, $verbose );
599 48 100       103 last NOOK if not defined $nook_text;
600 44         129 $text .= "$nook_id: $nook_text";
601             }
602 4         35 return $text;
603             }
604              
605             # not to be documented
606             sub Marpa::R3::Valuer::nook_show {
607 48     48   72 my ( $slv, $nook_id, $verbose ) = @_;
608 48         85 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
609              
610 48         99 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 48 100       130 return if not defined $or_node_id;
653              
654             DESCRIBE_CHOICES: {
655 44         62 my $this_choice;
  44         52  
656 44         102 ($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 44         75 CHOICE: for ( my $choice_ix = 0;; $choice_ix++ ) {
662              
663 97         236 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 97 100       227 last CHOICE if not defined $and_node_id;
671 53         144 $text .= " o$or_node_id" . '[' . $choice_ix . ']';
672 53 100 66     193 if ( defined $this_choice and $this_choice == $choice_ix ) {
673 44         61 $text .= q{*};
674             }
675 53         106 my $and_node_tag =
676             $slv->and_node_tag( $and_node_id );
677 53         140 $text .= " ::= a$and_node_id $and_node_tag";
678 53         96 $text .= "\n";
679             } ## end CHOICE: for ( my $choice_ix = 0;; $choice_ix++ )
680             } ## end DESCRIBE_CHOICES:
681 44         92 return $text;
682             }
683              
684             # not to be documented
685             sub Marpa::R3::Valuer::and_node_tag {
686 53     53   84 my ( $slv, $and_node_id ) = @_;
687              
688 53         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 53         99 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   9 my ($slv) = @_;
736              
737 3         14 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         20 return $result;
745             }
746              
747             # not to be documented
748             sub Marpa::R3::Valuer::or_nodes_show {
749 4     4   13 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         27 return $result;
759             }
760              
761             # not to be documented
762             sub Marpa::R3::Valuer::and_nodes_show {
763 4     4   1968 my ( $slv ) = @_;
764 4         19 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   1698 my ($slv) = @_;
776 6         20 my $slr = $slv->[Marpa::R3::Internal_V::SLR];
777 6         24 my $ambiguity_level = $slv->ambiguity_level();
778 6 50       31 return q{No parse} if $ambiguity_level <= 0;
779 6 100       32 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       22 die 'Could not create ASF' if not defined $asf;
783 4         21 my $ambiguities = Marpa::R3::Internal_ASF2::ambiguities($asf);
784 4         16 my @ambiguities = grep {defined} @{$ambiguities}[ 0 .. 1 ];
  8         22  
  4         12  
785 4         21 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 1054     1054   4912 my ($slv) = @_;
790              
791 1054         4707 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 1054         3289 return $metric;
798             }
799              
800             sub Marpa::R3::Valuer::g1_pos {
801 5     5   1135 my ( $slv ) = @_;
802 5         25 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         53 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: