File Coverage

blib/lib/Marpa/R2/Thin/Trace.pm
Criterion Covered Total %
statement 106 179 59.2
branch 18 44 40.9
condition 3 12 25.0
subroutine 16 25 64.0
pod 0 21 0.0
total 143 281 50.8


line stmt bran cond sub pod time code
1             # Copyright 2022 Jeffrey Kegler
2             # This file is part of Marpa::R2. Marpa::R2 is free software: you can
3             # redistribute it and/or modify it under the terms of the GNU Lesser
4             # General Public License as published by the Free Software Foundation,
5             # either version 3 of the License, or (at your option) any later version.
6             #
7             # Marpa::R2 is distributed in the hope that it will be useful,
8             # but WITHOUT ANY WARRANTY; without even the implied warranty of
9             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10             # Lesser General Public License for more details.
11             #
12             # You should have received a copy of the GNU Lesser
13             # General Public License along with Marpa::R2. If not, see
14             # http://www.gnu.org/licenses/.
15              
16             package Marpa::R2::Thin::Trace;
17              
18 132     132   2213 use 5.010001;
  132         445  
19 132     132   698 use warnings;
  132         277  
  132         3179  
20 132     132   722 use strict;
  132         271  
  132         3449  
21              
22 132     132   769 use vars qw($VERSION $STRING_VERSION);
  132         305  
  132         305519  
23             $VERSION = '12.000000';
24             $STRING_VERSION = $VERSION;
25             $VERSION = eval $VERSION;
26              
27             sub new {
28 720     720 0 2129 my ( $class, $grammar ) = @_;
29 720         1819 my $self = bless {}, $class;
30 720         2175 $self->{g} = $grammar;
31 720         1724 $self->{symbol_by_name} = {};
32 720         1643 $self->{symbol_names} = {};
33 720         2107 return $self;
34             } ## end sub new
35              
36             sub grammar {
37 780     780 0 1737 my ($self) = @_;
38 780         5703 return $self->{g};
39             }
40              
41             sub symbol_by_name {
42 180127     180127 0 271989 my ( $self, $name ) = @_;
43 180127         390879 return $self->{symbol_by_name}->{$name};
44             }
45              
46             sub symbol_name {
47 109058     109058 0 156665 my ( $self, $symbol_id ) = @_;
48 109058         161609 my $symbol_name = $self->{symbol_name}->[$symbol_id];
49 109058 50       178598 $symbol_name = 'R' . $symbol_id if not defined $symbol_name;
50 109058         197956 return $symbol_name;
51             } ## end sub symbol_name
52              
53             sub formatted_symbol_name {
54 0     0 0 0 my ( $self, $symbol_id ) = @_;
55 0         0 my $symbol_name = $self->symbol_name($symbol_id);
56             # As-is if all word characters
57 0 0       0 return $symbol_name if $symbol_name =~ m/ \A \w* \z/xms;
58             # As-is if ends in right bracket
59 0 0       0 return $symbol_name if $symbol_name =~ m/ \] \z/xms;
60 0         0 return '<' . $symbol_name . '>';
61             }
62              
63             sub symbol_name_set {
64 44456     44456 0 71752 my ( $self, $name, $symbol_id ) = @_;
65 44456         81586 $self->{symbol_name}->[$symbol_id] = $name;
66 44456         84827 $self->{symbol_by_name}->{$name} = $symbol_id;
67 44456         99417 return $symbol_id;
68             } ## end sub symbol_name_set
69              
70             sub symbol_new {
71 44456     44456 0 67888 my ( $self, $name ) = @_;
72 44456         116210 return $self->symbol_name_set( $name, $self->{g}->symbol_new() );
73             }
74              
75             sub symbol_force {
76 0     0 0 0 my ( $self, $name ) = @_;
77 0   0     0 return $self->{symbol_by_name}->{$name} // $self->symbol_new($name);
78             }
79              
80             sub rule {
81 0     0 0 0 my ( $self, $rule_id ) = @_;
82 0         0 my $grammar = $self->{g};
83 0         0 my $rule_length = $grammar->rule_length($rule_id);
84 0         0 my $lhs = $self->symbol_name( $grammar->rule_lhs($rule_id) );
85             my @rhs =
86 0         0 map { $self->symbol_name( $grammar->rule_rhs( $rule_id, $_ ) ) }
  0         0  
87             ( 0 .. $rule_length - 1 );
88 0         0 return ($lhs, @rhs);
89             }
90              
91             # Expand a rule into a list of symbol IDs
92             sub rule_expand {
93 1908     1908 0 3117 my ( $self, $rule_id ) = @_;
94 1908         2942 my $grammar = $self->{g};
95 1908         3861 my $rule_length = $grammar->rule_length($rule_id);
96 1908 50       3773 return if not defined $rule_length;
97 1908         3649 my $lhs = ( $grammar->rule_lhs($rule_id) );
98             return ( $lhs,
99 1908         4023 map { $grammar->rule_rhs( $rule_id, $_ ) }
  4042         9494  
100             ( 0 .. $rule_length - 1 ) );
101             } ## end sub rule_expand
102              
103             sub dotted_rule {
104 0     0 0 0 my ( $self, $rule_id, $dot_position ) = @_;
105 0         0 my $grammar = $self->{g};
106 0         0 my $rule_length = $grammar->rule_length($rule_id);
107 0 0       0 $dot_position = $rule_length if $dot_position < 0;
108 0         0 my $lhs = $self->formatted_symbol_name( $grammar->rule_lhs($rule_id) );
109             my @rhs =
110 0         0 map { $self->formatted_symbol_name( $grammar->rule_rhs( $rule_id, $_ ) ) }
  0         0  
111             ( 0 .. $rule_length - 1 );
112 0 0       0 $dot_position = 0 if $dot_position < 0;
113 0         0 splice( @rhs, $dot_position, 0, q{.} );
114 0         0 return join q{ }, $lhs, q{::=}, @rhs;
115             } ## end sub dotted_rule
116              
117             sub brief_rule {
118 0     0 0 0 my ( $self, $rule_id ) = @_;
119 0         0 my $grammar = $self->{g};
120 0         0 my $rule_length = $grammar->rule_length($rule_id);
121 0         0 my $lhs = $self->formatted_symbol_name( $grammar->rule_lhs($rule_id) );
122             my @rhs =
123 0         0 map { $self->formatted_symbol_name( $grammar->rule_rhs( $rule_id, $_ ) ) }
  0         0  
124             ( 0 .. $rule_length - 1 );
125 0         0 my $minimum = $grammar->sequence_min($rule_id);
126 0         0 my @quantifier = ();
127 0 0       0 if (defined $minimum) {
128 0 0       0 push @quantifier, ($minimum <= 0 ? q{ *} : q{ +});
129             }
130 0         0 return join q{ }, $lhs, q{::=}, @rhs, @quantifier;
131             } ## end sub dotted_rule
132              
133             sub progress_report {
134 0     0 0 0 my ( $self, $recce, $ordinal ) = @_;
135 0         0 my $result = q{};
136 0   0     0 $ordinal //= $recce->latest_earley_set();
137 0         0 $recce->progress_report_start($ordinal);
138 0         0 ITEM: while (1) {
139 0         0 my ( $rule_id, $dot_position, $origin ) = $recce->progress_item();
140 0 0       0 last ITEM if not defined $rule_id;
141 0         0 $result
142             .= q{@}
143             . $origin . q{: }
144             . $self->dotted_rule( $rule_id, $dot_position ) . "\n";
145             } ## end ITEM: while (1)
146 0         0 $recce->progress_report_finish();
147 0         0 return $result;
148             } ## end sub progress_report
149              
150             sub lexer_progress_report {
151 0     0 0 0 my ( $self, $slr, $ordinal ) = @_;
152 0         0 my $thin_slr = $slr->[Marpa::R2::Internal::Scanless::R::C];
153 0         0 my $result = q{};
154 0   0     0 $ordinal //= $thin_slr->lexer_latest_earley_set();
155 0         0 $thin_slr->lexer_progress_report_start($ordinal);
156 0         0 ITEM: while (1) {
157 0         0 my ( $rule_id, $dot_position, $origin ) = $thin_slr->lexer_progress_item();
158 0 0       0 last ITEM if not defined $rule_id;
159 0         0 $result
160             .= q{@}
161             . $origin . q{: }
162             . $self->dotted_rule( $rule_id, $dot_position ) . "\n";
163             } ## end ITEM: while (1)
164 0         0 $thin_slr->lexer_progress_report_finish();
165 0         0 return $result;
166             } ## end sub progress_report
167              
168             sub show_dotted_irl {
169 996     996 0 1685 my ( $self, $irl_id, $dot_position ) = @_;
170 996         1550 my $grammar_c = $self->{g};
171 996         2090 my $lhs_id = $grammar_c->_marpa_g_irl_lhs($irl_id);
172 996         1947 my $irl_length = $grammar_c->_marpa_g_irl_length($irl_id);
173              
174 996         1825 my $text = $self->isy_name($lhs_id) . q{ ::=};
175              
176 996 100       1995 if ( $dot_position < 0 ) {
177 333         502 $dot_position = $irl_length;
178             }
179              
180 996         1495 my @rhs_names = ();
181 996         2448 for my $ix ( 0 .. $irl_length - 1 ) {
182 1923         3767 my $rhs_nsy_id = $grammar_c->_marpa_g_irl_rhs( $irl_id, $ix );
183 1923         3273 my $rhs_nsy_name = $self->isy_name($rhs_nsy_id);
184 1923         3733 push @rhs_names, $rhs_nsy_name;
185             }
186              
187 996         1938 POSITION: for my $position ( 0 .. scalar @rhs_names ) {
188 2919 100       4899 if ( $position == $dot_position ) {
189 996         1467 $text .= q{ .};
190             }
191 2919         4040 my $name = $rhs_names[$position];
192 2919 100       5194 next POSITION if not defined $name;
193 1923         3321 $text .= " $name";
194             } ## end POSITION: for my $position ( 0 .. scalar @rhs_names )
195              
196 996         2872 return $text;
197              
198             } ## end sub show_dotted_irl
199              
200             sub show_ahm {
201 299     299 0 499 my ( $self, $item_id ) = @_;
202 299         838 my $grammar_c = $self->{g};
203 299         653 my $postdot_id = $grammar_c->_marpa_g_ahm_postdot($item_id);
204 299         600 my $text = "AHM $item_id: ";
205 299         411 my @properties = ();
206 299 100       553 if ( $postdot_id < 0 ) {
207 118         209 push @properties, 'completion';
208             }
209             else {
210 181         320 my $postdot_symbol_name = $self->isy_name($postdot_id);
211 181         413 push @properties, qq{postdot = "$postdot_symbol_name"};
212             }
213 299         618 $text .= join q{; }, @properties;
214 299         442 $text .= "\n" . ( q{ } x 4 );
215 299         562 $text .= $self->show_brief_ahm($item_id) . "\n";
216 299         808 return $text;
217             } ## end sub show_ahm
218              
219             sub show_brief_ahm {
220 299     299 0 515 my ( $self, $item_id ) = @_;
221 299         451 my $grammar_c = $self->{g};
222 299         573 my $postdot_id = $grammar_c->_marpa_g_ahm_postdot($item_id);
223 299         625 my $irl_id = $grammar_c->_marpa_g_ahm_irl($item_id);
224 299         586 my $position = $grammar_c->_marpa_g_ahm_position($item_id);
225 299         545 return $self->show_dotted_irl( $irl_id, $position );
226             } ## end sub show_brief_ahm
227              
228             sub show_ahms {
229 14     14 0 47 my ($self) = @_;
230 14         48 my $grammar_c = $self->{g};
231 14         31 my $text = q{};
232 14         72 my $count = $grammar_c->_marpa_g_ahm_count();
233 14         65 for my $AHFA_item_id ( 0 .. $count - 1 ) {
234 299         582 $text .= $self->show_ahm($AHFA_item_id);
235             }
236 14         146 return $text;
237             } ## end sub show_ahms
238              
239             sub isy_name {
240 3629     3629 0 5682 my ( $self, $id ) = @_;
241 3629         4933 my $grammar_c = $self->{g};
242              
243             # The next is a little roundabout to prevent auto-instantiation
244 3629         6076 my $name = '[ISY' . $id . ']';
245              
246             GEN_NAME: {
247              
248 3629 100       4595 if ( $grammar_c->_marpa_g_nsy_is_start($id) ) {
  3629         8066  
249 90         219 my $source_id = $grammar_c->_marpa_g_source_xsy($id);
250 90         215 $name = $self->symbol_name($source_id);
251 90         231 $name .= q<[']>;
252 90         184 last GEN_NAME;
253             } ## end if ( $grammar_c->_marpa_g_nsy_is_start($id) )
254              
255 3539         6009 my $lhs_xrl = $grammar_c->_marpa_g_nsy_lhs_xrl($id);
256 3539 100 100     8826 if ( defined $lhs_xrl and defined $grammar_c->sequence_min($lhs_xrl) )
257             {
258 33         60 my $original_lhs_id = $grammar_c->rule_lhs($lhs_xrl);
259 33         58 $name = $self->symbol_name($original_lhs_id) . '[Seq]';
260 33         62 last GEN_NAME;
261             } ## end if ( defined $lhs_xrl and defined $grammar_c->sequence_min...)
262              
263 3506         5966 my $xrl_offset = $grammar_c->_marpa_g_nsy_xrl_offset($id);
264 3506 100       5864 if ($xrl_offset) {
265 341         648 my $original_lhs_id = $grammar_c->rule_lhs($lhs_xrl);
266 341         585 $name =
267             $self->symbol_name($original_lhs_id) . '[R'
268             . $lhs_xrl . q{:}
269             . $xrl_offset . ']';
270 341         600 last GEN_NAME;
271             } ## end if ($xrl_offset)
272              
273 3165         5237 my $source_id = $grammar_c->_marpa_g_source_xsy($id);
274 3165         5166 $name = $self->symbol_name($source_id);
275 3165 100       7515 $name .= '[]' if $grammar_c->_marpa_g_nsy_is_nulling($id);
276              
277             } ## end GEN_NAME:
278              
279 3629         6996 return $name;
280             } ## end sub isy_name
281              
282             sub show_rule {
283 0     0 0   my ( $self, $rule_id ) = @_;
284              
285 0           my $grammar = $self->{g};
286 0           my @comment = ();
287              
288 0 0         $grammar->rule_length($rule_id) == 0 and push @comment, 'empty';
289 0 0         $grammar->rule_is_productive($rule_id) or push @comment, 'unproductive';
290 0 0         $grammar->rule_is_accessible($rule_id) or push @comment, 'inaccessible';
291              
292 0           my $text = $self->brief_rule($rule_id);
293              
294              
295 0 0         if (@comment) {
296 0           $text .= q{ } . ( join q{ }, q{/*}, @comment, q{*/} );
297             }
298              
299 0           return $text .= "\n";
300              
301             } # sub show_rule
302              
303             sub show_rules {
304 0     0 0   my ($self) = @_;
305 0           my $grammar = $self->{g};
306 0           my $text;
307              
308 0           my $highest_rule_id = $grammar->highest_rule_id();
309             RULE:
310 0           for ( my $rule_id = 0; $rule_id <= $highest_rule_id; $rule_id++ ) {
311 0           $text .= $self->show_rule($rule_id);
312             }
313 0           return $text;
314             } ## end sub show_rules
315              
316             1;