File Coverage

blib/lib/RPerl/CompileUnit/Program.pm
Criterion Covered Total %
statement 160 203 78.8
branch 36 68 52.9
condition 5 12 41.6
subroutine 7 8 87.5
pod n/a
total 208 291 71.4


line stmt bran cond sub pod time code
1             # [[[ HEADER ]]]
2             package RPerl::CompileUnit::Program;
3 3     3   17 use strict;
  3         7  
  3         70  
4 3     3   14 use warnings;
  3         7  
  3         58  
5 3     3   14 use RPerl::AfterSubclass;
  3         5  
  3         336  
6             our $VERSION = 0.006_000;
7              
8             # [[[ OO INHERITANCE ]]]
9 3     3   18 use parent qw(RPerl::CompileUnit);
  3         4  
  3         15  
10 3     3   153 use RPerl::CompileUnit;
  3         7  
  3         5075  
11              
12             # [[[ CRITICS ]]]
13             ## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
14             ## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
15              
16             # [[[ OO PROPERTIES ]]]
17             our hashref $properties = {};
18              
19             # [[[ SUBROUTINES & OO METHODS ]]]
20              
21             sub ast_to_rperl__generate {
22 482     482   1684 { my string_hashref::method $RETURN_TYPE };
  482         1392  
23 482         1984 ( my object $self, my string_hashref $modes) = @ARG;
24 482         3448 my string_hashref $rperl_source_group = { PMC => q{} };
25 482         1581 my string_hashref $rperl_source_subgroup;
26              
27             # RPerl::diag( 'in Program->ast_to_rperl__generate(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
28             # RPerl::diag('in Program->ast_to_rperl__generate(), received $modes = ' . "\n" . Dumper($modes) . "\n");
29              
30 482         2908 my string $self_class = ref $self;
31              
32             # unwrap Program_18 from CompileUnit_4
33 482 50       3168 if ( ($self_class) eq 'CompileUnit_4' ) {
34 482         1838 $self = $self->{children}->[0];
35 482         1947 $self_class = ref $self;
36             }
37              
38 482 50       3062 if ( ($self_class) ne 'Program_18' ) {
39 0         0 die RPerl::Parser::rperl_rule__replace(
40             'ERROR ECOGEASRP00, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: Grammar rule ' . ($self_class) . ' found where Program_18 expected, dying' )
41             . "\n";
42             }
43              
44             # Program -> SHEBANG Critic? USE_RPERL Header Critic* Include* Constant* Subroutine* Operation+
45 482         1795 my string $shebang = $self->{children}->[0];
46 482         1541 my object $critic_optional = $self->{children}->[1];
47 482         1635 my string $use_rperl = $self->{children}->[2]; # PERLOPS only
48              
49             # Header -> 'use strict;' 'use warnings;' USE_RPERL_AFTER? 'our' VERSION_NUMBER_ASSIGN;
50 482         2285 my object $header = $self->{children}->[3];
51 482         1688 my string $use_strict = $header->{children}->[0]; # PERLOPS only
52 482         1635 my string $use_warnings = $header->{children}->[1]; # PERLOPS only
53 482         1247 my string $use_rperl_after_optional = $header->{children}->[2]; # PERLOPS only
54 482         2261 my string $our_keyword = $header->{children}->[3]; # PERLOPS only
55 482         1958 my string $version_number = $header->{children}->[4];
56              
57 482         1315 my object $critic_star = $self->{children}->[4];
58 482         1642 my object $include_star = $self->{children}->[5];
59 482         1775 my object $constant_star = $self->{children}->[6];
60 482         1716 my object $subroutine_star = $self->{children}->[7];
61 482         1180 my object $operation_plus = $self->{children}->[8];
62              
63 482         1444 $rperl_source_group->{PMC} = $shebang;
64 482 100 66     2862 if ( ( exists $critic_optional->{children}->[0] ) and ( defined $critic_optional->{children}->[0] ) ) {
65 1         8 $rperl_source_group->{PMC} .= q{ };
66 1         31 $rperl_source_subgroup = $critic_optional->{children}->[0]->ast_to_rperl__generate($modes);
67 1         30 RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
68             }
69             else {
70 481         2197 $rperl_source_group->{PMC} .= "\n";
71             }
72              
73 482 50       3001 if ( $modes->{label} eq 'ON' ) {
74 0         0 $rperl_source_group->{PMC} .= '# [[[ HEADER ]]]' . "\n";
75             }
76             # DEV NOTE: now that 'use RPerl;' is a source filter, it is technically not part of the Header grammar rule, instead 'use RPerl::AfterSubclass;' is in Header;
77             # nevertheless, we are treating 'use RPerl;' as part of the header in our RPerl application source code, so it appears under the '# [[[ HEADER ]]]' label
78             # both here in RPerl::CompileUnit::Program, as well as in RPerl::CompileUnit::Module::Header
79 482         2622 $rperl_source_group->{PMC} .= $use_rperl . "\n";
80 482         2164 $rperl_source_group->{PMC} .= $use_strict . "\n";
81 482         2402 $rperl_source_group->{PMC} .= $use_warnings . "\n";
82 482 50 33     3076 if ( ( exists $use_rperl_after_optional->{children}->[0] ) and ( defined $use_rperl_after_optional->{children}->[0] ) ) {
83 0         0 $rperl_source_group->{PMC} .= $use_rperl_after_optional->{children}->[0]->{attr} . "\n";
84             }
85              
86             # DEV NOTE, CORRELATION #rp014: the hard-coded ' $VERSION = ' & ';' below are the only discarded tokens in the RPerl grammar,
87             # due to the need to differentiate between v-numbers and otherwise-identical normal numbers
88 482         2971 $rperl_source_group->{PMC} .= $our_keyword . ' $VERSION = ' . $version_number . q{;} . "\n";
89              
90 482 100       2562 if ( exists $critic_star->{children}->[0] ) {
91 479 50       2032 if ( $modes->{label} eq 'ON' ) {
92 0         0 $rperl_source_group->{PMC} .= '# [[[ CRITICS ]]]' . "\n";
93             }
94             }
95 482         1749 foreach my object $critic ( @{ $critic_star->{children} } ) {
  482         2061  
96 948         23541 $rperl_source_subgroup = $critic->ast_to_rperl__generate($modes);
97 948         20204 RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
98             }
99              
100 482 100       3380 if ( exists $include_star->{children}->[0] ) {
101 62 50       297 if ( $modes->{label} eq 'ON' ) {
102 0         0 $rperl_source_group->{PMC} .= "\n" . '# [[[ INCLUDES ]]]' . "\n";
103             }
104             }
105 482         1457 foreach my object $include ( @{ $include_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
  482         1710  
106 65         1749 $rperl_source_subgroup = $include->ast_to_rperl__generate($modes);
107 65         1288 RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
108             }
109              
110 482 100       2548 if ( exists $constant_star->{children}->[0] ) {
111 4 50       33 if ( $modes->{label} eq 'ON' ) {
112 0         0 $rperl_source_group->{PMC} .= "\n" . '# [[[ CONSTANTS ]]]' . "\n";
113             }
114             }
115 482         1360 foreach my object $constant ( @{ $constant_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
  482         1952  
116 7         206 $rperl_source_subgroup = $constant->ast_to_rperl__generate($modes);
117 7         190 RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
118             }
119              
120 482 100       2474 if ( exists $subroutine_star->{children}->[0] ) {
121 87 50       558 if ( $modes->{label} eq 'ON' ) {
122 0         0 $rperl_source_group->{PMC} .= "\n" . '# [[[ SUBROUTINES ]]]' . "\n";
123             }
124             }
125 482         1381 foreach my object $subroutine ( ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
126 482         2294 @{ $subroutine_star->{children} }
127             )
128             {
129 96         2488 $rperl_source_subgroup = $subroutine->ast_to_rperl__generate($modes);
130 76         1890 RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
131             }
132              
133 462 50       2086 if ( $modes->{label} eq 'ON' ) {
134 0         0 $rperl_source_group->{PMC} .= "\n" . '# [[[ OPERATIONS ]]]' . "\n";
135             }
136 462         920 foreach my object $operation ( ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
137 462         1993 @{ $operation_plus->{children} }
138             )
139             {
140 1918         41996 $rperl_source_subgroup = $operation->ast_to_rperl__generate($modes);
141 1915         41490 RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
142             }
143              
144             # Programs only generate EXE output, not PMC output
145 459         1881 $rperl_source_group->{EXE} = $rperl_source_group->{PMC};
146 459         1381 delete $rperl_source_group->{PMC};
147 459         4679 return $rperl_source_group;
148             }
149              
150              
151             sub ast_to_cpp__generate__CPPOPS_PERLTYPES {
152 0     0   0 { my string_hashref::method $RETURN_TYPE };
  0         0  
153 0         0 ( my object $self, my string_hashref $modes) = @ARG;
154 0         0 my string_hashref $cpp_source_group = {
155             CPP => q{// <<< RP::CU::P __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n",
156             H => q{// <<< RP::CU::P __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n",
157             PMC => q{# <<< RP::CU::P __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n",
158             EXE => q{// <<< RP::CU::P __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n"
159             };
160              
161             #...
162 0         0 return $cpp_source_group;
163             }
164              
165              
166             sub ast_to_cpp__generate__CPPOPS_CPPTYPES {
167 16     16   37 { my string_hashref::method $RETURN_TYPE };
  16         44  
168 16         55 ( my object $self, my string_hashref $modes) = @ARG;
169 16         92 my string_hashref $cpp_source_group = { CPP => q{} };
170 16         34 my string_hashref $cpp_source_subgroup;
171 16         40 my integer $cpp_source_group_CPP_line_count = 0;
172              
173             # RPerl::diag( 'in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
174             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $modes = ' . "\n" . Dumper($modes) . "\n");
175              
176 16         56 my string $self_class = ref $self;
177              
178             # unwrap Program_18 from CompileUnit_4
179 16 50       75 if ( ($self_class) eq 'CompileUnit_4' ) {
180 16         69 $self = $self->{children}->[0];
181 16         56 $self_class = ref $self;
182             }
183              
184 16 50       64 if ( ($self_class) ne 'Program_18' ) {
185 0         0 die RPerl::Parser::rperl_rule__replace(
186             'ERROR ECOGEASRP00, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: Grammar rule ' . ($self_class) . ' found where Program_18 expected, dying' )
187             . "\n";
188             }
189              
190             # Program -> SHEBANG Critic? USE_RPERL Header Critic* Include* Constant* Subroutine* Operation+
191 16         50 my string $shebang = $self->{children}->[0];
192 16         52 my object $critic_optional = $self->{children}->[1];
193 16         39 my string $use_rperl = $self->{children}->[2]; # PERLOPS only
194              
195             # Header -> 'use strict;' 'use warnings;' USE_RPERL_AFTER? 'our' VERSION_NUMBER_ASSIGN;
196 16         40 my object $header = $self->{children}->[3];
197 16         61 my string $use_strict = $header->{children}->[0]; # PERLOPS only
198 16         48 my string $use_warnings = $header->{children}->[1]; # PERLOPS only
199 16         41 my string $use_rperl_after_optional = $header->{children}->[2]; # PERLOPS only
200 16         55 my string $our_keyword = $header->{children}->[3]; # PERLOPS only
201 16         41 my string $version_number = $header->{children}->[4];
202 16         39 my integer $header_line_number = $header->{line_number};
203              
204 16         39 my object $critic_star = $self->{children}->[4];
205 16         30 my object $include_star = $self->{children}->[5];
206 16         29 my object $constant_star = $self->{children}->[6];
207 16         40 my object $subroutine_star = $self->{children}->[7];
208 16         41 my object $operation_plus = $self->{children}->[8];
209              
210             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $include_star = ' . "\n" . RPerl::Parser::rperl_ast__dump($include_star) . "\n");
211             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $subroutine_star = ' . "\n" . RPerl::Parser::rperl_ast__dump($subroutine_star) . "\n");
212              
213             # NEED ANSWER: should we modify the user-provided shebang as done here, or simply replace it with a hard-coded one pointing to /usr/bin? //!/usr/bin/rperl
214 16         69 substr $shebang, 0, 2, '//!';
215 16         38 substr $shebang, -4, 4, 'rperl';
216 16         77 $cpp_source_group->{CPP} = $shebang . "\n";
217              
218 16 50       74 if ( $modes->{label} eq 'ON' ) {
219 0 0       0 if ($header_line_number > 6) {
220 0         0 $cpp_source_group->{CPP} .= "\n" x ($header_line_number - 6);
221             }
222 0         0 $cpp_source_group->{CPP} .= '// [[[ HEADER ]]]' . "\n";
223             }
224 16         57 $cpp_source_group->{CPP} .= '#include <rperlstandalone.h>' . "\n";
225              
226 16         39 my string $file_name_underscores = $modes->{_input_file_name};
227             # $file_name_underscores =~ s/^[\/\\.]*//gxms; # remove leading forward slashes, back slashes, and dots
228 16         51 substr $file_name_underscores, -3, 3, q{}; # remove trailing '.pl'
229              
230 16         483 $file_name_underscores = RPerl::Compiler::post_processor_cpp__header_or_cpp_path('__NEED_CPP_PATH', $file_name_underscores);
231              
232 16         131 $file_name_underscores =~ s/[\/\\]/__/gxms; # replace forward slashes and back slashes with double-underscores
233 16         60 $file_name_underscores =~ s/[.-]/_/gxms; # replace dots and hyphens with underscores
234 16         83 $cpp_source_group->{CPP} .= '#ifndef __CPP__INCLUDED__' . $file_name_underscores . '_cpp' . "\n";
235 16         116 $cpp_source_group->{CPP} .= '#define __CPP__INCLUDED__' . $file_name_underscores . '_cpp ' . $version_number . "\n";
236 16         43 $cpp_source_group->{CPP} .= '# ifdef __CPP__TYPES' . "\n";
237            
238 16 50 33     173 if (( exists $critic_star->{children}->[0] ) and ( $modes->{label} eq 'ON' )) {
239 0         0 $cpp_source_group->{CPP} .= "\n" x (scalar @{ $critic_star->{children} }); # insert one blank line for each Critic
  0         0  
240             }
241              
242 16 50       66 if ( exists $include_star->{children}->[0] ) {
243 0 0       0 if ( $modes->{label} eq 'ON' ) {
244 0         0 $cpp_source_group->{CPP} .= "\n" . '// [[[ INCLUDES ]]]' . "\n";
245             }
246             }
247 16         38 foreach my object $include ( @{ $include_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
  16         81  
248             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $include = ' . "\n" . RPerl::Parser::rperl_ast__dump($include) . "\n");
249 0         0 $cpp_source_subgroup = $include->ast_to_cpp__generate__CPPOPS_CPPTYPES('main', $modes);
250 0         0 RPerl::Generator::source_group_append( $cpp_source_group, $cpp_source_subgroup );
251             }
252             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $cpp_source_group = ' . "\n" . RPerl::Parser::rperl_ast__dump($cpp_source_group) . "\n");
253 16         47 $cpp_source_group->{CPP} .= '#include "__NEED_HEADER_PATH"' . "\n"; # DEV NOTE, CORRELATION #rp033: defer setting header include path until files are saved in Compiler
254              
255 16 50       58 if ( exists $constant_star->{children}->[0] ) {
256 0 0       0 if ( $modes->{label} eq 'ON' ) {
257 0         0 $cpp_source_group->{CPP} .= "\n" . '// [[[ CONSTANTS ]]]' . "\n";
258             }
259             }
260 16         33 foreach my object $constant ( @{ $constant_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
  16         52  
261 0         0 $cpp_source_subgroup = $constant->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
262 0         0 RPerl::Generator::source_group_append( $cpp_source_group, $cpp_source_subgroup );
263             }
264              
265 16 100       52 if ( exists $subroutine_star->{children}->[0] ) {
266 1 50       30 if ( $modes->{label} eq 'ON' ) {
267 0         0 $cpp_source_group->{CPP} .= "\n" . '// [[[ SUBROUTINES ]]]' . "\n";
268             }
269             }
270 16         39 foreach my object $subroutine ( ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
271 16         50 @{ $subroutine_star->{children} }
272             )
273             {
274 1         37 $cpp_source_subgroup = $subroutine->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
275 1         29 RPerl::Generator::source_group_append( $cpp_source_group, $cpp_source_subgroup );
276 1         6 $cpp_source_group->{CPP} .= "\n\n";
277             }
278              
279             # BEGIN C++ main() function wrapper, to contain all operations which are not inside a subroutine
280 16         65 $cpp_source_group->{CPP} .= 'int main() {';
281              
282 16 50       66 if ( $modes->{label} eq 'ON' ) {
283 0         0 $cpp_source_group->{CPP} .= "\n" . ' // [[[ OPERATIONS HEADER ]]]' . "\n";
284             }
285              
286 16         39 my string $CPP_saved = $cpp_source_group->{CPP};
287 16         39 $cpp_source_group->{CPP} = q{};
288              
289 16 50       50 if ( $modes->{label} eq 'ON' ) {
290 0         0 $cpp_source_group->{CPP} .= "\n" . '// [[[ OPERATIONS ]]]' . "\n";
291             }
292              
293 16         39 foreach my object $operation ( ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
294 16         63 @{ $operation_plus->{children} }
295             )
296             {
297 87         1708 $cpp_source_subgroup = $operation->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
298             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $cpp_source_subgroup = ' . "\n" . RPerl::Parser::rperl_ast__dump($cpp_source_subgroup) . "\n");
299 87         1737 RPerl::Generator::source_group_append( $cpp_source_group, $cpp_source_subgroup );
300             }
301              
302 16         43 my integer $num_loop_iterators = 0;
303 16 50 33     96 if ((exists $modes->{_loop_iterators}) and (defined $modes->{_loop_iterators})) {
304 0         0 $num_loop_iterators = scalar keys %{$modes->{_loop_iterators}};
  0         0  
305             }
306              
307             # COMPILE-TIME OPTIMIZATION #02: declare all loop iterators at top of subroutine/method to avoid re-declarations in nested loops
308             # if ((exists $modes->{_loop_iterators}) and (defined $modes->{_loop_iterators})) {
309 16 50       67 if ($num_loop_iterators) { # shortcut
310 0         0 foreach my string $loop_iterator_symbol (sort keys %{$modes->{_loop_iterators}}) {
  0         0  
311 0         0 $CPP_saved .= $modes->{_loop_iterators}->{$loop_iterator_symbol} . q{ } . $loop_iterator_symbol . ';' . "\n";
312             }
313 0         0 delete $modes->{_loop_iterators};
314             }
315              
316 16         71 $cpp_source_group_CPP_line_count = ($cpp_source_group->{CPP} =~ tr/\n//) + 1; # add 1 to count last line which does not have newline
317 16         54 my integer $operations_line_number = $operation_plus->{children}->[0]->{line_number};
318             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $cpp_source_group_CPP_line_count = ' . $cpp_source_group_CPP_line_count . "\n");
319             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $operations_line_number = ' . $operations_line_number . "\n");
320              
321 16 50       91 if ( $modes->{label} eq 'ON' ) {
322 0         0 my integer $newline_count = (($operations_line_number - $cpp_source_group_CPP_line_count) - (2 + $num_loop_iterators));
323 0 0       0 if ($newline_count < 0) { $newline_count = 0; }
  0         0  
324 0         0 $cpp_source_group->{CPP} .= "\n" x $newline_count;
325             }
326              
327 16         73 $CPP_saved .= $cpp_source_group->{CPP};
328 16         68 $cpp_source_group->{CPP} = $CPP_saved;
329            
330 16 50       65 if ( $modes->{label} eq 'ON' ) { $cpp_source_group->{CPP} .= "\n" x 3; }
  0         0  
331 16 50       59 if ( $modes->{label} eq 'ON' ) { $cpp_source_group->{CPP} .= ' // [[[ OPERATIONS FOOTER ]]]' . "\n"; }
  0         0  
332              
333             # END C++ main() function wrapper
334 16         197 $cpp_source_group->{CPP} .= ' return 0;' . "\n" . '}' . "\n\n";
335              
336 16 50       65 if ( $modes->{label} eq 'ON' ) { $cpp_source_group->{CPP} .= '// [[[ FOOTER ]]]' . "\n"; }
  0         0  
337 16         42 $cpp_source_group->{CPP} .= <<EOF;
338             # elif defined __PERL__TYPES
339             Purposefully_die_from_a_compile-time_error,_due_to____PERL__TYPES_being_defined.__We_need_to_define_only___CPP__TYPES_in_this_file!
340             # endif
341             #endif
342             EOF
343              
344             # RPerl::diag('in Program->ast_to_cpp__generate__CPPOPS_CPPTYPES(), about to return $cpp_source_group = ' . "\n" . RPerl::Parser::rperl_ast__dump($cpp_source_group) . "\n");
345 16         176 return $cpp_source_group;
346             }
347              
348             1; # end of class