line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# [[[ HEADER ]]] |
2
|
|
|
|
|
|
|
package RPerl::Parser; |
3
|
4
|
|
|
4
|
|
1265
|
use strict; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
98
|
|
4
|
4
|
|
|
4
|
|
18
|
use warnings; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
82
|
|
5
|
4
|
|
|
4
|
|
19
|
use RPerl::AfterSubclass; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
460
|
|
6
|
|
|
|
|
|
|
our $VERSION = 0.009_000; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# [[[ OO INHERITANCE ]]] |
9
|
|
|
|
|
|
|
#use RPerl::CompileUnit::Module::Class; |
10
|
|
|
|
|
|
|
#use parent qw(RPerl::CompileUnit::Module::Class); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# [[[ CRITICS ]]] |
13
|
|
|
|
|
|
|
## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator |
14
|
|
|
|
|
|
|
## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers) # USER DEFAULT 3: allow constants |
15
|
|
|
|
|
|
|
## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if |
16
|
|
|
|
|
|
|
## no critic qw(ProhibitBacktickOperators) ## SYSTEM SPECIAL 11: allow system command execution |
17
|
|
|
|
|
|
|
## no critic qw(RequireCarping) # SYSTEM SPECIAL 13: allow die instead of croak |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# [[[ INCLUDES ]]] |
20
|
4
|
|
|
4
|
|
1815
|
use Perl::Critic; |
|
4
|
|
|
|
|
3082255
|
|
|
4
|
|
|
|
|
181
|
|
21
|
4
|
|
|
4
|
|
4242
|
use RPerl::Grammar; |
|
4
|
|
|
|
|
19
|
|
|
4
|
|
|
|
|
255
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# [[[ CONSTANTS ]]] |
24
|
4
|
|
|
4
|
|
42
|
use constant MAX_SINGLE_ERROR_LINE_LENGTH => my integer $TYPED_MAX_SINGLE_ERROR_LINE_LENGTH = 120; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
5963
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# [[[ SUBROUTINES ]]] |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Parse from Human-Readable RPerl Source Code File to Eyapp-Parsed RPerl AST Object |
29
|
|
|
|
|
|
|
our object $rperl_to_ast__parse = sub { |
30
|
|
|
|
|
|
|
( my string $rperl_source__file_name) = @_; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# [[[ PARSE PHASE 0: CHECK PERL SYNTAX ]]] |
33
|
|
|
|
|
|
|
# [[[ PARSE PHASE 0: CHECK PERL SYNTAX ]]] |
34
|
|
|
|
|
|
|
# [[[ PARSE PHASE 0: CHECK PERL SYNTAX ]]] |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
rperl_source__check_syntax($rperl_source__file_name); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# [[[ PARSE PHASE 1: CRITICIZE PERL SYNTAX ]]] |
39
|
|
|
|
|
|
|
# [[[ PARSE PHASE 1: CRITICIZE PERL SYNTAX ]]] |
40
|
|
|
|
|
|
|
# [[[ PARSE PHASE 1: CRITICIZE PERL SYNTAX ]]] |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
rperl_source__criticize($rperl_source__file_name); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# [[[ PARSE PHASE 2: PARSE RPERL SYNTAX ]]] |
45
|
|
|
|
|
|
|
# [[[ PARSE PHASE 2: PARSE RPERL SYNTAX ]]] |
46
|
|
|
|
|
|
|
# [[[ PARSE PHASE 2: PARSE RPERL SYNTAX ]]] |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
return ( rperl_source__parse($rperl_source__file_name) ); |
49
|
|
|
|
|
|
|
}; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Check Perl Syntax Using Perl Interpreter |
52
|
|
|
|
|
|
|
our void $rperl_source__check_syntax = sub { |
53
|
|
|
|
|
|
|
( my string $rperl_source__file_name) = @_; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
RPerl::verbose('PARSE PHASE 0: Check Perl syntax... '); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my string $nul = $OSNAME eq 'MSWin32' ? 'NUL' : '/dev/null'; |
58
|
|
|
|
|
|
|
my string $rperl_source__perl_syntax_command |
59
|
|
|
|
|
|
|
# DEV NOTE: inclusion of '-Mstrict' alters propagation of error messages through eval() to die() |
60
|
|
|
|
|
|
|
= $EXECUTABLE_NAME . q{ -Iblib/lib -M"warnings FATAL=>q(all)" -Mstrict -cw } |
61
|
|
|
|
|
|
|
# = $EXECUTABLE_NAME . q{ -Iblib/lib -M"warnings FATAL=>q(all)" -cw } |
62
|
|
|
|
|
|
|
. $rperl_source__file_name; |
63
|
|
|
|
|
|
|
my string $rperl_source__perl_syntax_command__no_output |
64
|
|
|
|
|
|
|
= $rperl_source__perl_syntax_command . ' > '.$nul.' 2> '.$nul; |
65
|
|
|
|
|
|
|
my string $rperl_source__perl_syntax_command__all_output |
66
|
|
|
|
|
|
|
= $rperl_source__perl_syntax_command . ' 2>&1'; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
#my string $rperl_source__perl_syntax_command = q{perl -Iblib/lib -cw } . $rperl_source__file_name; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$rperl_source__perl_syntax_command =\n$rperl_source__perl_syntax_command\n"); |
71
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$rperl_source__perl_syntax_command__no_output =\n$rperl_source__perl_syntax_command__no_output\n\n"); |
72
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$rperl_source__perl_syntax_command__all_output =\n$rperl_source__perl_syntax_command__all_output\n\n"); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
#my integer $rperl_source__perl_syntax_retval = system $rperl_source__perl_syntax_command; |
75
|
|
|
|
|
|
|
my integer $rperl_source__perl_syntax_retval |
76
|
|
|
|
|
|
|
= system $rperl_source__perl_syntax_command__no_output; # don't want any messages printed here |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
#my string $rperl_source__perl_syntax_retstring = `echo HOWDY`; |
79
|
|
|
|
|
|
|
#my string $rperl_source__perl_syntax_retstring = `$rperl_source__perl_syntax_command`; |
80
|
|
|
|
|
|
|
my string $rperl_source__perl_syntax_retstring |
81
|
|
|
|
|
|
|
= `$rperl_source__perl_syntax_command__all_output`; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$rperl_source__perl_syntax_retval = $rperl_source__perl_syntax_retval\n"); |
84
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$rperl_source__perl_syntax_retstring =\n$rperl_source__perl_syntax_retstring\n"); |
85
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$OS_ERROR = $OS_ERROR\n"); # $OS_ERROR seems to contain random error messages that I can't trace? |
86
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__check_syntax(), have \$? = $?\n"); |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# NEED ADD ERROR CHECKING: ECOPAPL00 FILE DOES NOT EXIST, ECOPAPL01 FILE IS EMPTY |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
if ( $rperl_source__perl_syntax_retval != 0 ) { |
91
|
|
|
|
|
|
|
my $error_pretty = "\n\n" |
92
|
|
|
|
|
|
|
. 'ERROR ECOPAPL02, RPERL PARSER, PERL SYNTAX ERROR' . "\n" |
93
|
|
|
|
|
|
|
. 'Failed normal Perl strictures-and-fatal-warnings syntax check with the following information:' . "\n\n" |
94
|
|
|
|
|
|
|
. ' File Name: ' . $rperl_source__file_name . "\n" |
95
|
|
|
|
|
|
|
. ' Return Value: ' . ( $rperl_source__perl_syntax_retval >> 8 ) . "\n" |
96
|
|
|
|
|
|
|
. ' Error Message(s): '; |
97
|
|
|
|
|
|
|
if ( (length $rperl_source__perl_syntax_retstring) < MAX_SINGLE_ERROR_LINE_LENGTH() ) { |
98
|
|
|
|
|
|
|
$error_pretty .= $rperl_source__perl_syntax_retstring . "\n\n"; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
else { |
101
|
|
|
|
|
|
|
$error_pretty .= "\n\n" . $rperl_source__perl_syntax_retstring . "\n\n"; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
die $error_pretty; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my string_arrayref $rperl_source__perl_syntax_retstring_lines; |
108
|
|
|
|
|
|
|
@{$rperl_source__perl_syntax_retstring_lines} = split /\n/xms, |
109
|
|
|
|
|
|
|
$rperl_source__perl_syntax_retstring; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# RPerl::diag('in rperl_source__check_syntax(), have $rperl_source__perl_syntax_retstring_lines = ' . "\n" . Dumper($rperl_source__perl_syntax_retstring_lines) . "\n"); |
112
|
|
|
|
|
|
|
my string_arrayref $rperl_source__perl_syntax_retstring_warnings = []; |
113
|
|
|
|
|
|
|
foreach my string $rperl_source__perl_syntax_retstring_line ( |
114
|
|
|
|
|
|
|
@{$rperl_source__perl_syntax_retstring_lines} ) |
115
|
|
|
|
|
|
|
{ |
116
|
|
|
|
|
|
|
if (( $rperl_source__perl_syntax_retstring_line !~ m/WARNING\sW/xms ) # RPerl Warning |
117
|
|
|
|
|
|
|
and |
118
|
|
|
|
|
|
|
( $rperl_source__perl_syntax_retstring_line !~ m/ERROR\sE/xms ) # RPerl Error |
119
|
|
|
|
|
|
|
and |
120
|
|
|
|
|
|
|
( $rperl_source__perl_syntax_retstring_line !~ m/\[\[\[\ BEGIN\s/xms ) # RPerl Non-Error Debug Info |
121
|
|
|
|
|
|
|
and |
122
|
|
|
|
|
|
|
( $rperl_source__perl_syntax_retstring_line !~ m/\[\[\[\ END\s/xms ) # RPerl Non-Error Debug Info |
123
|
|
|
|
|
|
|
and |
124
|
|
|
|
|
|
|
( $rperl_source__perl_syntax_retstring_line !~ m/syntax\sOK/xms ) # Perl Non-Error |
125
|
|
|
|
|
|
|
) |
126
|
|
|
|
|
|
|
{ |
127
|
|
|
|
|
|
|
push @{$rperl_source__perl_syntax_retstring_warnings}, |
128
|
|
|
|
|
|
|
$rperl_source__perl_syntax_retstring_line; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
if ( ( scalar @{$rperl_source__perl_syntax_retstring_warnings} ) != 0 ) { |
133
|
|
|
|
|
|
|
my $error_pretty = "\n" |
134
|
|
|
|
|
|
|
. 'ERROR ECOPAPL03, RPERL PARSER, PERL SYNTAX WARNING' . "\n" |
135
|
|
|
|
|
|
|
. 'Failed normal Perl strictures-and-fatal-warnings syntax check with the following information:' . "\n\n" |
136
|
|
|
|
|
|
|
. ' File Name: ' . $rperl_source__file_name . "\n" |
137
|
|
|
|
|
|
|
. ' Warning Message(s): '; |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
if ( ( ( scalar @{$rperl_source__perl_syntax_retstring_warnings} ) == 1 ) |
140
|
|
|
|
|
|
|
and ( (length $rperl_source__perl_syntax_retstring_warnings->[0]) < MAX_SINGLE_ERROR_LINE_LENGTH() ) ) { |
141
|
|
|
|
|
|
|
$error_pretty .= $rperl_source__perl_syntax_retstring_warnings->[0] . "\n\n"; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
else { |
144
|
|
|
|
|
|
|
$error_pretty .= "\n\n" . ( join "\n", @{$rperl_source__perl_syntax_retstring_warnings} ) . "\n\n"; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
die $error_pretty; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
RPerl::verbose(' done.' . "\n"); |
150
|
|
|
|
|
|
|
}; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Criticize Perl Syntax Using Perl::Critic |
153
|
|
|
|
|
|
|
our void $rperl_source__criticize = sub { |
154
|
|
|
|
|
|
|
( my string $rperl_source__file_name) = @_; |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
RPerl::verbose('PARSE PHASE 1: Criticize Perl syntax... '); |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# pre-critic error, begin check to ensure file ends with newline character or all-whitespace line |
159
|
|
|
|
|
|
|
if ( not -f $rperl_source__file_name ) { |
160
|
|
|
|
|
|
|
die 'ERROR ECOPAPC10, RPERL PARSER, PERL CRITIC VIOLATION: File not found, ' . q{'} . $rperl_source__file_name . q{'} . ', dying' . "\n"; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
open my filehandleref $FILE_HANDLE, '<', $rperl_source__file_name |
164
|
|
|
|
|
|
|
or die 'ERROR ECOPAPC11, RPERL PARSER, PERL CRITIC VIOLATION: Cannot open file ' . q{'} . $rperl_source__file_name . q{'} . ' for reading, ' . $OS_ERROR . ', dying' . "\n"; |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
my string $file_line = undef; |
167
|
|
|
|
|
|
|
my string $file_line_last = undef; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
while ( $file_line = <$FILE_HANDLE> ) { |
170
|
|
|
|
|
|
|
# RPerl::diag('in rperl_source__criticize(), top of while loop, have $file_line = ' . q{'} . $file_line . q{'} . "\n"); |
171
|
|
|
|
|
|
|
$file_line_last = $file_line; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# RPerl::diag('in rperl_source__criticize(), have last $file_line = ' . q{'} . $file_line . q{'} . "\n"); |
175
|
|
|
|
|
|
|
# RPerl::diag('in rperl_source__criticize(), have $file_line_last = ' . q{'} . $file_line_last . q{'} . "\n"); |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
close $FILE_HANDLE or die 'ERROR ECOPAPC12, RPERL PARSER, PERL CRITIC VIOLATION: Cannot close file ' . q{'} . $rperl_source__file_name . q{'} . ' after reading, ' . $OS_ERROR . ', dying' . "\n"; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# DEV NOTE: the last line of all RPerl input files must either end with a newline character or be all-whitespace characters, |
180
|
|
|
|
|
|
|
# in order to avoid false positives triggered by Perl::Critic |
181
|
|
|
|
|
|
|
if (((substr $file_line_last, -1, 1) ne "\n") and ( $file_line_last !~ m/^\s+$/xms )) { |
182
|
|
|
|
|
|
|
die 'ERROR ECOPAPC13, RPERL PARSER, PERL CRITIC VIOLATION: RPerl source code input file ' . q{'} . $rperl_source__file_name . q{'} . ' does not end with newline character or line of all-whitespace characters, dying' . "\n"; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# DEV NOTE: disable RequireTidyCode because perltidy may not be stable |
186
|
|
|
|
|
|
|
# my object $rperl_source__critic = Perl::Critic->new( -severity => 'brutal' ); |
187
|
|
|
|
|
|
|
# my object $rperl_source__critic = Perl::Critic->new( -exclude => ['RequireTidyCode'] -severity => 'brutal' ); # DEV NOTE: Perl::Critic's own docs-recommended syntax throws a violation |
188
|
|
|
|
|
|
|
my object $rperl_source__critic = Perl::Critic->new( |
189
|
|
|
|
|
|
|
# DEV NOTE: disable RequireTidyCode because Perl::Tidy is not perfect and may complain even if the code is tidy; |
190
|
|
|
|
|
|
|
# disable PodSpelling because calling the external spellchecker can cause errors such as aspell's "No word lists can be found for the language FOO"; |
191
|
|
|
|
|
|
|
# disable RequireExplicitPackage because 'use RPerl;' comes before package name(s), and Grammar.eyp will catch any other violations |
192
|
|
|
|
|
|
|
# NEED REMOVE HARD-CODED TEMPORARY WORK-AROUND: https://github.com/autinitysystems/Perl-Critic-Policy-Documentation-RequirePod/issues/1 |
193
|
|
|
|
|
|
|
# NEED REMOVE HARD-CODED TEMPORARY WORK-AROUND: https://github.com/petdance/perl-critic-bangs/issues/16 |
194
|
|
|
|
|
|
|
# disable RequirePod because it is not part of Perl::Critic & wrongly includes itself in themes 'core' & 'php' & 'maintenance' |
195
|
|
|
|
|
|
|
# disable all non-core additional policies which may be installed, such as Perlsecret, etc. |
196
|
|
|
|
|
|
|
'-exclude' => ['RequireTidyCode', 'PodSpelling', 'RequireExplicitPackage', 'RequirePod', 'ProhibitBitwiseOperators'], |
197
|
|
|
|
|
|
|
'-severity' => 'brutal', |
198
|
|
|
|
|
|
|
'-theme' => 'core' |
199
|
|
|
|
|
|
|
); |
200
|
|
|
|
|
|
|
my @rperl_source__critic_violations |
201
|
|
|
|
|
|
|
= $rperl_source__critic->critique($rperl_source__file_name); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
my integer $rperl_source__critic_num_violations |
204
|
|
|
|
|
|
|
= scalar @rperl_source__critic_violations; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__criticize(), have \$rperl_source__critic_num_violations = $rperl_source__critic_num_violations\n"); |
207
|
|
|
|
|
|
|
# my string $rperl_source__critic_dumperified_violations = Dumper( \@rperl_source__critic_violations ); |
208
|
|
|
|
|
|
|
#RPerl::diag("in rperl_source__criticize(), have Dumper(\\\@rperl_source__critic_violations) =\n" . $rperl_source__critic_dumperified_violations . "\n"); |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# NEED ADD ERROR CHECKING: ECOPAPC00 FILE DOES NOT EXIST, ECOPAPC01 FILE IS EMPTY; or would that be redundant with ECOPAPL0x error checking when added above? |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
if ( $rperl_source__critic_num_violations > 0 ) { |
213
|
|
|
|
|
|
|
my string $violation_pretty = q{}; |
214
|
|
|
|
|
|
|
foreach my object $violation (@rperl_source__critic_violations) { |
215
|
|
|
|
|
|
|
$violation_pretty .= ' File Name: ' . $rperl_source__file_name . "\n"; |
216
|
|
|
|
|
|
|
$violation_pretty .= ' Line number: ' . $violation->{_location}->[0] . "\n"; |
217
|
|
|
|
|
|
|
$violation_pretty .= ' Policy: ' . $violation->{_policy} . "\n"; |
218
|
|
|
|
|
|
|
$violation_pretty .= ' Description: ' . $violation->{_description} . "\n"; |
219
|
|
|
|
|
|
|
if ( ref( $violation->{_explanation} ) eq 'ARRAY' ) { |
220
|
|
|
|
|
|
|
$violation_pretty .= ' Explanation: See Perl Best Practices page(s) ' . join( ', ', @{ $violation->{_explanation} } ) . "\n\n"; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
else { |
223
|
|
|
|
|
|
|
$violation_pretty .= ' Explanation: ' . $violation->{_explanation} . "\n\n"; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
die "\n" |
227
|
|
|
|
|
|
|
. 'ERROR ECOPAPC02, RPERL PARSER, PERL CRITIC VIOLATION' |
228
|
|
|
|
|
|
|
. "\n" |
229
|
|
|
|
|
|
|
. 'Failed Perl::Critic brutal review with the following information:' |
230
|
|
|
|
|
|
|
. "\n\n" |
231
|
|
|
|
|
|
|
. $violation_pretty; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
else { |
234
|
|
|
|
|
|
|
RPerl::verbose(' done.' . "\n"); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
}; |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# Die On RPerl Grammar Error |
239
|
|
|
|
|
|
|
our void $rperl_grammar_error = sub { |
240
|
|
|
|
|
|
|
( my array $argument ) = @_; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
my string $value = $argument->YYCurval; |
243
|
|
|
|
|
|
|
if ( not( defined $value ) ) { |
244
|
|
|
|
|
|
|
$value = '<<< NO TOKEN FOUND >>>'; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
my string $helpful_hint = q{}; |
247
|
|
|
|
|
|
|
if ( $value =~ /\d/xms ) { |
248
|
|
|
|
|
|
|
$helpful_hint |
249
|
|
|
|
|
|
|
= q{ Helpful Hint: Possible case of PBP RequireNumberSeparators (see below)} . "\n" |
250
|
|
|
|
|
|
|
. q{ Policy: Perl::Critic::Policy::ValuesAndExpressions::RequireNumberSeparators} . "\n" |
251
|
|
|
|
|
|
|
. q{ Description: Long number not separated with underscores} . "\n" |
252
|
|
|
|
|
|
|
. q{ Explanation: See Perl Best Practices page(s) 59} . "\n"; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
my integer $line_number = $argument->{TOKENLINE}; |
256
|
|
|
|
|
|
|
my string $rperl_source__file_name = $argument->{rperl_source__file_name}; |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# die( "\n" . 'ERROR ECOPARP00, RPERL PARSER, SYNTAX ERROR; have $argument =' . "\n" . Dumper($argument) . "\n" ); |
259
|
|
|
|
|
|
|
# die( "\n" . 'ERROR ECOPARP00, RPERL PARSER, SYNTAX ERROR; have $argument->{rperl_source__file_name} = ' . $argument->{rperl_source__file_name} . "\n" ); |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my $current_state_num = $argument->{STACK}[-1][0]; |
262
|
|
|
|
|
|
|
my $current_state = $argument->{STATES}[$current_state_num]; |
263
|
|
|
|
|
|
|
my $expected_tokens = q{}; |
264
|
|
|
|
|
|
|
my number $is_first_expected = 1; |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
foreach my $expected_token ( sort keys %{ $current_state->{ACTIONS} } ) { |
267
|
|
|
|
|
|
|
if ($is_first_expected) { |
268
|
|
|
|
|
|
|
$is_first_expected = 0; |
269
|
|
|
|
|
|
|
$expected_tokens .= $expected_token . "\n"; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
else { |
272
|
|
|
|
|
|
|
$expected_tokens |
273
|
|
|
|
|
|
|
.= q{ } . $expected_token . "\n"; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
die "\n" |
278
|
|
|
|
|
|
|
. 'ERROR ECOPARP00, RPERL PARSER, RPERL SYNTAX ERROR' . "\n" |
279
|
|
|
|
|
|
|
. 'Failed RPerl grammar syntax check with the following information:' |
280
|
|
|
|
|
|
|
. "\n\n" |
281
|
|
|
|
|
|
|
. ' File Name: ' . $rperl_source__file_name . "\n" |
282
|
|
|
|
|
|
|
. ' Line Number: ' . $line_number . "\n" |
283
|
|
|
|
|
|
|
. ' Unexpected Token: ' . $value . "\n" |
284
|
|
|
|
|
|
|
. ' Expected Token(s): ' . $expected_tokens |
285
|
|
|
|
|
|
|
. $helpful_hint . "\n"; |
286
|
|
|
|
|
|
|
}; |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# Parse RPerl Syntax Using Eyapp Grammar |
289
|
|
|
|
|
|
|
our void $rperl_source__parse = sub { |
290
|
|
|
|
|
|
|
( my string $rperl_source__file_name) = @_; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
RPerl::verbose('PARSE PHASE 2: Parse RPerl syntax... '); |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
my object $eyapp_parser = RPerl::Grammar->new(); |
295
|
|
|
|
|
|
|
$eyapp_parser->{rperl_source__file_name} = $rperl_source__file_name; |
296
|
|
|
|
|
|
|
$eyapp_parser->YYSlurpFile($rperl_source__file_name); |
297
|
|
|
|
|
|
|
my object $rperl_ast = $eyapp_parser->YYParse( |
298
|
|
|
|
|
|
|
yydebug => 0x00, # disable eyapp DBG DEBUGGING |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# yydebug => 0xFF, # full eyapp DBG DEBUGGING, USE FOR DEBUGGING GRAMMAR |
301
|
|
|
|
|
|
|
yyerror => $rperl_grammar_error |
302
|
|
|
|
|
|
|
); |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
RPerl::verbose(' done.' . "\n"); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# RPerl::diag("in rperl_source__parse(), have \$rperl_ast->str() =\n" . $rperl_ast->str() . "\n\n"); |
307
|
|
|
|
|
|
|
# RPerl::diag("in rperl_source__parse(), have \$rperl_ast =\n" . rperl_ast__dump($rperl_ast) . "\n\n"); |
308
|
|
|
|
|
|
|
# die 'TMP DEBUG'; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
return ($rperl_ast); |
311
|
|
|
|
|
|
|
}; |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# condense AST dump, replace all instances of RPerl rule(s) with more meaningful RPerl class(es) |
314
|
|
|
|
|
|
|
our string $rperl_ast__dump = sub { |
315
|
|
|
|
|
|
|
( my object $rperl_ast) = @_; |
316
|
|
|
|
|
|
|
$Data::Dumper::Indent = 1; # do not attempt to align hash values based on hash key length |
317
|
|
|
|
|
|
|
my string $rperl_ast_dumped = Dumper($rperl_ast); |
318
|
|
|
|
|
|
|
$Data::Dumper::Indent = 2; # restore default |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# $rperl_ast_dumped =~ s/\ \ /\ \ \ \ /gxms; # set tabs from 2 to 4 spaces |
321
|
|
|
|
|
|
|
$rperl_ast_dumped =~ s/[ ]{2}/ /gxms; # set tabs from 2 to 4 spaces |
322
|
|
|
|
|
|
|
my string $replacee; |
323
|
|
|
|
|
|
|
my string $replacer; |
324
|
|
|
|
|
|
|
foreach my string $rule ( sort keys %{$RPerl::Grammar::RULES} ) { |
325
|
|
|
|
|
|
|
$replacee = q{'} . $rule . q{'}; |
326
|
|
|
|
|
|
|
$replacer |
327
|
|
|
|
|
|
|
= q{'} . $rule . ' ISA ' . $RPerl::Grammar::RULES->{$rule} . q{'}; |
328
|
|
|
|
|
|
|
$rperl_ast_dumped =~ s/$replacee/$replacer/gxms; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
return $rperl_ast_dumped; |
331
|
|
|
|
|
|
|
}; |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# replace all instances of RPerl rule(s) with more meaningful RPerl class(es) |
334
|
|
|
|
|
|
|
our string $rperl_rule__replace = sub { |
335
|
|
|
|
|
|
|
( my string $rperl_rule_string) = @_; |
336
|
|
|
|
|
|
|
my string $replacer; |
337
|
|
|
|
|
|
|
foreach my string $rule ( sort keys %{$RPerl::Grammar::RULES} ) { |
338
|
|
|
|
|
|
|
if ( $RPerl::Grammar::RULES->{$rule} ne 'RPerl::NonGenerator' ) { |
339
|
|
|
|
|
|
|
$replacer |
340
|
|
|
|
|
|
|
= q{(} |
341
|
|
|
|
|
|
|
. $rule . ' ISA ' |
342
|
|
|
|
|
|
|
. $RPerl::Grammar::RULES->{$rule} . q{)}; |
343
|
|
|
|
|
|
|
$replacer =~ s/RPerl:://gxms; |
344
|
|
|
|
|
|
|
$rperl_rule_string =~ s/$rule/$replacer/gxms; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
return $rperl_rule_string; |
348
|
|
|
|
|
|
|
}; |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
1; # end of class |