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   2342 use 5.010001;
  135         478  
19 135     135   681 use warnings;
  135         276  
  135         3452  
20 135     135   766 use strict;
  135         293  
  135         3430  
21              
22 135     135   790 use vars qw($VERSION $STRING_VERSION);
  135         320  
  135         316410  
23             $VERSION = '13.001_000';
24             $STRING_VERSION = $VERSION;
25             $VERSION = eval $VERSION;
26              
27             sub new {
28 734     734 0 2311 my ( $class, $grammar ) = @_;
29 734         1909 my $self = bless {}, $class;
30 734         2349 $self->{g} = $grammar;
31 734         1770 $self->{symbol_by_name} = {};
32 734         1739 $self->{symbol_names} = {};
33 734         2208 return $self;
34             } ## end sub new
35              
36             sub grammar {
37 801     801 0 1809 my ($self) = @_;
38 801         5956 return $self->{g};
39             }
40              
41             sub symbol_by_name {
42 184963     184963 0 282544 my ( $self, $name ) = @_;
43 184963         404243 return $self->{symbol_by_name}->{$name};
44             }
45              
46             sub symbol_name {
47 234205     234205 0 340669 my ( $self, $symbol_id ) = @_;
48 234205         367352 my $symbol_name = $self->{symbol_name}->[$symbol_id];
49 234205 50       393195 $symbol_name = 'R' . $symbol_id if not defined $symbol_name;
50 234205         459538 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 74102 my ( $self, $name, $symbol_id ) = @_;
65 45550         81781 $self->{symbol_name}->[$symbol_id] = $name;
66 45550         87537 $self->{symbol_by_name}->{$name} = $symbol_id;
67 45550         101889 return $symbol_id;
68             } ## end sub symbol_name_set
69              
70             sub symbol_new {
71 45550     45550 0 70800 my ( $self, $name ) = @_;
72 45550         120166 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 80891 my ( $self, $rule_id ) = @_;
94 51444         76394 my $grammar = $self->{g};
95 51444         115923 my $rule_length = $grammar->rule_length($rule_id);
96 51444 50       104176 return if not defined $rule_length;
97 51444         99568 my $lhs = ( $grammar->rule_lhs($rule_id) );
98             return ( $lhs,
99 51444         104473 map { $grammar->rule_rhs( $rule_id, $_ ) }
  78282         231547  
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 1718 my ( $self, $irl_id, $dot_position ) = @_;
170 996         1599 my $grammar_c = $self->{g};
171 996         2046 my $lhs_id = $grammar_c->_marpa_g_irl_lhs($irl_id);
172 996         1914 my $irl_length = $grammar_c->_marpa_g_irl_length($irl_id);
173              
174 996         1728 my $text = $self->isy_name($lhs_id) . q{ ::=};
175              
176 996 100       2040 if ( $dot_position < 0 ) {
177 333         522 $dot_position = $irl_length;
178             }
179              
180 996         1495 my @rhs_names = ();
181 996         1978 for my $ix ( 0 .. $irl_length - 1 ) {
182 1923         3747 my $rhs_nsy_id = $grammar_c->_marpa_g_irl_rhs( $irl_id, $ix );
183 1923         3183 my $rhs_nsy_name = $self->isy_name($rhs_nsy_id);
184 1923         3819 push @rhs_names, $rhs_nsy_name;
185             }
186              
187 996         1955 POSITION: for my $position ( 0 .. scalar @rhs_names ) {
188 2919 100       4938 if ( $position == $dot_position ) {
189 996         1519 $text .= q{ .};
190             }
191 2919         4029 my $name = $rhs_names[$position];
192 2919 100       5243 next POSITION if not defined $name;
193 1923         3314 $text .= " $name";
194             } ## end POSITION: for my $position ( 0 .. scalar @rhs_names )
195              
196 996         2821 return $text;
197              
198             } ## end sub show_dotted_irl
199              
200             sub show_ahm {
201 299     299 0 605 my ( $self, $item_id ) = @_;
202 299         469 my $grammar_c = $self->{g};
203 299         645 my $postdot_id = $grammar_c->_marpa_g_ahm_postdot($item_id);
204 299         593 my $text = "AHM $item_id: ";
205 299         419 my @properties = ();
206 299 100       555 if ( $postdot_id < 0 ) {
207 118         223 push @properties, 'completion';
208             }
209             else {
210 181         363 my $postdot_symbol_name = $self->isy_name($postdot_id);
211 181         425 push @properties, qq{postdot = "$postdot_symbol_name"};
212             }
213 299         660 $text .= join q{; }, @properties;
214 299         450 $text .= "\n" . ( q{ } x 4 );
215 299         559 $text .= $self->show_brief_ahm($item_id) . "\n";
216 299         850 return $text;
217             } ## end sub show_ahm
218              
219             sub show_brief_ahm {
220 299     299 0 503 my ( $self, $item_id ) = @_;
221 299         463 my $grammar_c = $self->{g};
222 299         592 my $postdot_id = $grammar_c->_marpa_g_ahm_postdot($item_id);
223 299         598 my $irl_id = $grammar_c->_marpa_g_ahm_irl($item_id);
224 299         573 my $position = $grammar_c->_marpa_g_ahm_position($item_id);
225 299         525 return $self->show_dotted_irl( $irl_id, $position );
226             } ## end sub show_brief_ahm
227              
228             sub show_ahms {
229 14     14 0 51 my ($self) = @_;
230 14         37 my $grammar_c = $self->{g};
231 14         32 my $text = q{};
232 14         80 my $count = $grammar_c->_marpa_g_ahm_count();
233 14         74 for my $AHFA_item_id ( 0 .. $count - 1 ) {
234 299         595 $text .= $self->show_ahm($AHFA_item_id);
235             }
236 14         143 return $text;
237             } ## end sub show_ahms
238              
239             sub isy_name {
240 3629     3629 0 5641 my ( $self, $id ) = @_;
241 3629         5053 my $grammar_c = $self->{g};
242              
243             # The next is a little roundabout to prevent auto-instantiation
244 3629         5989 my $name = '[ISY' . $id . ']';
245              
246             GEN_NAME: {
247              
248 3629 100       4608 if ( $grammar_c->_marpa_g_nsy_is_start($id) ) {
  3629         8007  
249 90         228 my $source_id = $grammar_c->_marpa_g_source_xsy($id);
250 90         217 $name = $self->symbol_name($source_id);
251 90         175 $name .= q<[']>;
252 90         177 last GEN_NAME;
253             } ## end if ( $grammar_c->_marpa_g_nsy_is_start($id) )
254              
255 3539         6681 my $lhs_xrl = $grammar_c->_marpa_g_nsy_lhs_xrl($id);
256 3539 100 100     8920 if ( defined $lhs_xrl and defined $grammar_c->sequence_min($lhs_xrl) )
257             {
258 33         62 my $original_lhs_id = $grammar_c->rule_lhs($lhs_xrl);
259 33         58 $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         6147 my $xrl_offset = $grammar_c->_marpa_g_nsy_xrl_offset($id);
264 3506 100       5831 if ($xrl_offset) {
265 341         626 my $original_lhs_id = $grammar_c->rule_lhs($lhs_xrl);
266 341         602 $name =
267             $self->symbol_name($original_lhs_id) . '[R'
268             . $lhs_xrl . q{:}
269             . $xrl_offset . ']';
270 341         656 last GEN_NAME;
271             } ## end if ($xrl_offset)
272              
273 3165         5210 my $source_id = $grammar_c->_marpa_g_source_xsy($id);
274 3165         5238 $name = $self->symbol_name($source_id);
275 3165 100       7855 $name .= '[]' if $grammar_c->_marpa_g_nsy_is_nulling($id);
276              
277             } ## end GEN_NAME:
278              
279 3629         6823 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;