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 135     135   2392 use 5.010001;
  135         478  
19 135     135   743 use warnings;
  135         267  
  135         3443  
20 135     135   780 use strict;
  135         324  
  135         3540  
21              
22 135     135   725 use vars qw($VERSION $STRING_VERSION);
  135         355  
  135         318003  
23             $VERSION = '13.002_000';
24             $STRING_VERSION = $VERSION;
25             $VERSION = eval $VERSION;
26              
27             sub new {
28 734     734 0 2259 my ( $class, $grammar ) = @_;
29 734         1903 my $self = bless {}, $class;
30 734         2355 $self->{g} = $grammar;
31 734         1689 $self->{symbol_by_name} = {};
32 734         1741 $self->{symbol_names} = {};
33 734         2198 return $self;
34             } ## end sub new
35              
36             sub grammar {
37 801     801 0 1799 my ($self) = @_;
38 801         6320 return $self->{g};
39             }
40              
41             sub symbol_by_name {
42 184963     184963 0 283445 my ( $self, $name ) = @_;
43 184963         406093 return $self->{symbol_by_name}->{$name};
44             }
45              
46             sub symbol_name {
47 234205     234205 0 341182 my ( $self, $symbol_id ) = @_;
48 234205         362362 my $symbol_name = $self->{symbol_name}->[$symbol_id];
49 234205 50       400881 $symbol_name = 'R' . $symbol_id if not defined $symbol_name;
50 234205         453207 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 45550     45550 0 75067 my ( $self, $name, $symbol_id ) = @_;
65 45550         81426 $self->{symbol_name}->[$symbol_id] = $name;
66 45550         88416 $self->{symbol_by_name}->{$name} = $symbol_id;
67 45550         103649 return $symbol_id;
68             } ## end sub symbol_name_set
69              
70             sub symbol_new {
71 45550     45550 0 71281 my ( $self, $name ) = @_;
72 45550         122159 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 51444     51444 0 81184 my ( $self, $rule_id ) = @_;
94 51444         80274 my $grammar = $self->{g};
95 51444         117527 my $rule_length = $grammar->rule_length($rule_id);
96 51444 50       101164 return if not defined $rule_length;
97 51444         93370 my $lhs = ( $grammar->rule_lhs($rule_id) );
98             return ( $lhs,
99 51444         103708 map { $grammar->rule_rhs( $rule_id, $_ ) }
  78282         224172  
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 1769 my ( $self, $irl_id, $dot_position ) = @_;
170 996         1490 my $grammar_c = $self->{g};
171 996         2090 my $lhs_id = $grammar_c->_marpa_g_irl_lhs($irl_id);
172 996         1964 my $irl_length = $grammar_c->_marpa_g_irl_length($irl_id);
173              
174 996         1760 my $text = $self->isy_name($lhs_id) . q{ ::=};
175              
176 996 100       2132 if ( $dot_position < 0 ) {
177 333         487 $dot_position = $irl_length;
178             }
179              
180 996         1496 my @rhs_names = ();
181 996         2024 for my $ix ( 0 .. $irl_length - 1 ) {
182 1923         3712 my $rhs_nsy_id = $grammar_c->_marpa_g_irl_rhs( $irl_id, $ix );
183 1923         3204 my $rhs_nsy_name = $self->isy_name($rhs_nsy_id);
184 1923         3827 push @rhs_names, $rhs_nsy_name;
185             }
186              
187 996         1918 POSITION: for my $position ( 0 .. scalar @rhs_names ) {
188 2919 100       5018 if ( $position == $dot_position ) {
189 996         1501 $text .= q{ .};
190             }
191 2919         4017 my $name = $rhs_names[$position];
192 2919 100       5224 next POSITION if not defined $name;
193 1923         3318 $text .= " $name";
194             } ## end POSITION: for my $position ( 0 .. scalar @rhs_names )
195              
196 996         2889 return $text;
197              
198             } ## end sub show_dotted_irl
199              
200             sub show_ahm {
201 299     299 0 508 my ( $self, $item_id ) = @_;
202 299         474 my $grammar_c = $self->{g};
203 299         646 my $postdot_id = $grammar_c->_marpa_g_ahm_postdot($item_id);
204 299         628 my $text = "AHM $item_id: ";
205 299         450 my @properties = ();
206 299 100       559 if ( $postdot_id < 0 ) {
207 118         214 push @properties, 'completion';
208             }
209             else {
210 181         354 my $postdot_symbol_name = $self->isy_name($postdot_id);
211 181         421 push @properties, qq{postdot = "$postdot_symbol_name"};
212             }
213 299         653 $text .= join q{; }, @properties;
214 299         452 $text .= "\n" . ( q{ } x 4 );
215 299         607 $text .= $self->show_brief_ahm($item_id) . "\n";
216 299         872 return $text;
217             } ## end sub show_ahm
218              
219             sub show_brief_ahm {
220 299     299 0 496 my ( $self, $item_id ) = @_;
221 299         467 my $grammar_c = $self->{g};
222 299         584 my $postdot_id = $grammar_c->_marpa_g_ahm_postdot($item_id);
223 299         597 my $irl_id = $grammar_c->_marpa_g_ahm_irl($item_id);
224 299         612 my $position = $grammar_c->_marpa_g_ahm_position($item_id);
225 299         553 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         41 my $grammar_c = $self->{g};
231 14         37 my $text = q{};
232 14         71 my $count = $grammar_c->_marpa_g_ahm_count();
233 14         69 for my $AHFA_item_id ( 0 .. $count - 1 ) {
234 299         611 $text .= $self->show_ahm($AHFA_item_id);
235             }
236 14         135 return $text;
237             } ## end sub show_ahms
238              
239             sub isy_name {
240 3629     3629 0 5644 my ( $self, $id ) = @_;
241 3629         5049 my $grammar_c = $self->{g};
242              
243             # The next is a little roundabout to prevent auto-instantiation
244 3629         6516 my $name = '[ISY' . $id . ']';
245              
246             GEN_NAME: {
247              
248 3629 100       4546 if ( $grammar_c->_marpa_g_nsy_is_start($id) ) {
  3629         8062  
249 90         217 my $source_id = $grammar_c->_marpa_g_source_xsy($id);
250 90         220 $name = $self->symbol_name($source_id);
251 90         190 $name .= q<[']>;
252 90         178 last GEN_NAME;
253             } ## end if ( $grammar_c->_marpa_g_nsy_is_start($id) )
254              
255 3539         6021 my $lhs_xrl = $grammar_c->_marpa_g_nsy_lhs_xrl($id);
256 3539 100 100     8721 if ( defined $lhs_xrl and defined $grammar_c->sequence_min($lhs_xrl) )
257             {
258 33         102 my $original_lhs_id = $grammar_c->rule_lhs($lhs_xrl);
259 33         70 $name = $self->symbol_name($original_lhs_id) . '[Seq]';
260 33         60 last GEN_NAME;
261             } ## end if ( defined $lhs_xrl and defined $grammar_c->sequence_min...)
262              
263 3506         6132 my $xrl_offset = $grammar_c->_marpa_g_nsy_xrl_offset($id);
264 3506 100       5907 if ($xrl_offset) {
265 341         636 my $original_lhs_id = $grammar_c->rule_lhs($lhs_xrl);
266 341         608 $name =
267             $self->symbol_name($original_lhs_id) . '[R'
268             . $lhs_xrl . q{:}
269             . $xrl_offset . ']';
270 341         592 last GEN_NAME;
271             } ## end if ($xrl_offset)
272              
273 3165         5381 my $source_id = $grammar_c->_marpa_g_source_xsy($id);
274 3165         5173 $name = $self->symbol_name($source_id);
275 3165 100       7625 $name .= '[]' if $grammar_c->_marpa_g_nsy_is_nulling($id);
276              
277             } ## end GEN_NAME:
278              
279 3629         6883 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;