File Coverage

blib/lib/RPerl.pm
Criterion Covered Total %
statement 103 103 100.0
branch 14 16 87.5
condition 10 18 55.5
subroutine 12 12 100.0
pod 0 1 0.0
total 139 150 92.6


line stmt bran cond sub pod time code
1 3     3   2689 use rperltypesconv; # DEV NOTE, CORRELATION #rp008: import from Exporter for code outside of a package or class
  3         8  
  3         905  
2              
3             # [[[ HEADER SPECIAL ]]]
4             package RPerl;
5 3     3   25 use strict;
  3         6  
  3         59  
6 3     3   14 use warnings;
  3         9  
  3         165  
7              
8             # DEV NOTE, CORRELATION #rp016: CPAN's underscore-is-beta (NOT RPerl's underscore-is-comma) numbering scheme utilized here, to preserve trailing zeros
9             our $VERSION = '2.800000';
10              
11             #our $VERSION = 20170616; # NON-RELEASE VERSION NUMBER, OFFICIAL LONGDATE
12             #our $VERSION = 2017.167; # NON-RELEASE VERSION NUMBER, OFFICIAL STARDATE
13              
14             # [[[ CRITICS ]]]
15             ## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
16             ## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers) # USER DEFAULT 3: allow constants
17             ## no critic qw(ProhibitExplicitStdin) # USER DEFAULT 4: allow <STDIN> prompt
18             ## no critic qw(ProhibitStringyEval) # SYSTEM DEFAULT 1: allow eval()
19             ## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
20              
21             # [[[ INCLUDES ]]]
22              
23             # NEED FIX: pre-load all RPerl deps instead of only these?
24             # force pre-loading so they make it into $inc_skip
25 3     3   16 use parent qw();
  3         6  
  3         50  
26 3     3   15 use IPC::Cmd;
  3         11  
  3         133  
27             #use re 'strict'; # doesn't work in all versions of Perl
28 3     3   19 use re 'taint'; # hopefully doesn't actually do anything!
  3         7  
  3         154  
29              
30             # actually used in this file
31 3     3   16 use Data::Dumper;
  3         12  
  3         128  
32              
33 3     3   1530 use Filter::Simple;
  3         36884  
  3         17  
34              
35             $Data::Dumper::Sortkeys = 1; # Dumper() output must be sorted for lib/RPerl/Tests/Type_Types/* etc.
36              
37             FILTER { $_ = filter($_) };
38              
39 3     3   328 use rperlnamespaces;
  3         9  
  3         86  
40              
41             # DEV NOTE: causes circular (or other weird) dependencies, error "Subroutine import redefined...",
42             # so we can't use RPerl::diag, RPerl types, or subroutines in this files;
43             # UPDATE: and yet now it works (and in fact seems required) after further development, gotta love unpredictable high-magic code! :-/
44 3     3   19 use RPerl::AfterSubclass;
  3         7  
  3         389  
45              
46 3     3   1713 use Module::ScanDeps;
  3         42453  
  3         2556  
47              
48             our $INC_SCANNED = {}; # global variable to avoid repeated calls to scan_deps()
49              
50             sub filter {
51 24     24 0 144 ( my $input ) = @_;
52              
53 24         121 my $output = q{};
54 24         98 my $namespace_root;
55 24         107 my $package = q{};
56 24         103 my $package_line = q{};
57 24         158 my $post_package_lines = q{};
58 24         122 my $use_parent_line = q{};
59              
60 24         60 my $dependencies;
61             # my $dependencies_rperl = {};
62             # my $dependencies_rperl_package_names = [];
63             # my $dependencies_nonsystem = {};
64             # my $dependencies_nonsystem_package_names = [];
65 24         111 my $inc_skip = {};
66              
67 24         221 my $rand_serial = rand();
68              
69             # pre-generate $inc_skip to use in this file and in Module::ScanDeps::scan_deps()
70 24         14234 foreach my $included_filename_short ( sort keys %INC ) {
71             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', top of $inc_skip loop, have $included_filename_short = ' . $included_filename_short . "\n";
72 16416         40517 $namespace_root = filename_short_to_namespace_root_guess($included_filename_short);
73             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, have $namespace_root = ' . $namespace_root . "\n";
74 16416 100 100     105730 if (( $namespace_root ne q{} )
      100        
75             and ( ( exists $rperlnamespaces_generated::CORE->{$namespace_root} )
76             or ( exists $rperlnamespaces_generated::RPERL_DEPS->{$namespace_root} )
77             or ( exists $rperlnamespaces_generated::RPERL->{$namespace_root} ) )
78             )
79             {
80             # DEV NOTE, CORRELATION #rp019: need remove hard-coded allowance of RPerl::Test namespace, at least move to rperlnamespaces.pm or friends
81 15680 100       30471 if ( $namespace_root eq 'RPerl::' ) {
82             # $package = filename_short_to_package_guess($included_filename_short);
83             # if ( $package !~ /^RPerl::Test/xms ) {
84 3570 100       12078 if ( $included_filename_short !~ /^RPerl[\\\/]Test/xms ) {
85             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, noting-to-skip RPerl non-RPerl::Test $included_filename_short = ' . $included_filename_short . "\n";
86 3299         14853 $inc_skip->{$included_filename_short} = $INC{$included_filename_short};
87             }
88             }
89             else {
90             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, noting-to-skip non-RPerl $included_filename_short = ' . $included_filename_short . "\n";
91 12110         50610 $inc_skip->{$included_filename_short} = $INC{$included_filename_short};
92             }
93             }
94             # else { print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, NOT noting-to-skip $included_filename_short = ' . $included_filename_short . "\n"; }
95             }
96 24         2671 $inc_skip = { %{$inc_skip}, %{$INC_SCANNED} };
  24         3057  
  24         12418  
97 24         3633 $package = q{};
98              
99             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', have $INC_SCANNED = ' . Dumper( $INC_SCANNED ) . "\n";
100             # print {*STDERR} 'in RPerl::filter(), have $inc_skip = ' . Dumper( $inc_skip ) . "\n";
101             # print {*STDERR} 'in RPerl::filter(), have [sort keys %{$inc_skip}] = ' . Dumper( [ sort keys %{$inc_skip} ] ) . "\n";
102              
103             # ORIGINAL PURPOSE: generate $dependencies_rperl & $dependencies_nonsystem
104             # NEW PURPOSE: recursively filter all non-skipped dependencies and sub-dependencies
105 24         14393 foreach my $included_filename_short ( sort keys %INC ) {
106 16416 100       5030475 if ( not exists $inc_skip->{$included_filename_short} ) {
107 110         920 $INC_SCANNED->{$included_filename_short} = $INC{$included_filename_short};
108              
109             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', SCANNING non-system $included_filename_short = ' . $included_filename_short . "\n";
110              
111             # DEV NOTE: Easter Egg!! scan_deps() plus filter() equals recursive source filtering!!!
112 110         452 $dependencies = scan_deps( files => [ $INC{$included_filename_short} ], skip => { reverse %{$inc_skip} }, recurse => 1, execute => 0 );
  110         67454  
113             # scan_deps( files => [ $INC{$included_filename_short} ], skip => { reverse %{$inc_skip} }, recurse => 1, execute => 0 );
114              
115             # print {*STDERR} 'in RPerl::filter(), have $INC{$included_filename_short} = ' . $INC{$included_filename_short} . ' and $dependencies = ' . Dumper($dependencies) . "\n";
116             # print {*STDERR} 'in RPerl::filter(), have $INC{$included_filename_short} = ' . $INC{$included_filename_short} . ' and [sort keys %{$dependencies}] = ' . Dumper( [ sort keys %{$dependencies} ] ) . "\n";
117              
118             }
119             # else { print {*STDERR} 'in RPerl::filter(), SKIPPING system $included_filename_short = ' . $included_filename_short . "\n"; }
120             }
121              
122             # print {*STDERR} 'in RPerl::filter(), have $INC_SCANNED = ' . Dumper( $INC_SCANNED ) . "\n";
123             # print {*STDERR} 'in RPerl::filter(), have %INC = ' . Dumper( \%INC ) . "\n";
124             # print {*STDERR} 'in RPerl::filter(), have [sort keys %{$dependencies_rperl}] = ' . Dumper( [ sort keys %{$dependencies_rperl} ] ) . "\n";
125             # print {*STDERR} 'in RPerl::filter(), have [sort keys %{$dependencies_nonsystem}] = ' . Dumper( [ sort keys %{$dependencies_nonsystem} ] ) . "\n";
126              
127             # print {*STDERR} 'in RPerl::filter(), have $dependencies_rperl = ' . Dumper($dependencies_rperl) . "\n";
128             # print {*STDERR} 'in RPerl::filter(), have $dependencies_nonsystem = ' . Dumper($dependencies_nonsystem) . "\n";
129              
130             # print {*STDERR} "\n" . 'in RPerl::filter(), have pre-modification $input = ' . "\n" . '<<<<<<<<<<<<<<<<================ BEGIN INPUT FILE ================>>>>>>>>>>>>>>' . "\n" . $input . "\n" . '<<<<<<<<<<<<<<<<================ END INPUT FILE ================>>>>>>>>>>>>>>' . "\n\n";
131              
132             # look for all user-defined classes, create subclasses
133 24         2177 foreach my $input_line ( split /\n/, $input ) {
134             # print {*STDERR} 'in RPerl::filter(), have $input_line = ' . $input_line . "\n";
135            
136 1431 100 66     5125 if ( $input_line =~ /^\s*package\s+(.*)\s*;/xms ) {
    100          
    100          
137             # not all packages are classes
138 34         103 $package_line = $input_line;
139 34         166 $package = $1;
140 34         115 $post_package_lines = q{};
141 34         102 $output .= '# [[[ HEADER, PART 1 ]]]' . "\n";
142 34         165 $output .= $input_line . "\n";
143 34         132 $output .= 'use rperltypesconv;' . "\n"; # DEV NOTE, CORRELATION #rp008: import from Exporter for code inside of a package or class
144 34         83 $output .= 'use RPerl::Config;' . "\n"; # DEV NOTE, CORRELATION #rp034: enable @ARG in all packages (class & non-class)
145              
146             # print {*STDERR} 'in RPerl::filter(), found $package_line = ' . $package_line . "\n";
147             # print {*STDERR} 'in RPerl::filter(), found $package = ' . $package . "\n";
148             }
149             elsif ( ( $input_line =~ /^\s*use\s+parent/xms ) and ( $package ne q{} ) ) {
150             # all classes are packages
151 32         93 $use_parent_line = $input_line;
152 32         217 $namespace_root = package_to_namespace_root($package);
153              
154             # print {*STDERR} q{in RPerl::filter(), have $package = '} . $package . "'\n";
155             # print {*STDERR} q{in RPerl::filter(), have $namespace_root = '} . $namespace_root . "'\n";
156             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::CORE = ' . Dumper($rperlnamespaces_generated::CORE) . "\n";
157             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL_DEPS = ' . Dumper($rperlnamespaces_generated::RPERL_DEPS) . "\n";
158             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL = ' . Dumper($rperlnamespaces_generated::RPERL) . "\n";
159             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::CORE->{' . $namespace_root . '} = ' . Dumper($rperlnamespaces_generated::CORE->{$namespace_root}) . "\n";
160             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL_DEPS->{' . $namespace_root . '} = ' . Dumper($rperlnamespaces_generated::RPERL_DEPS->{$namespace_root}) . "\n";
161             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL->{' . $namespace_root . '} = ' . Dumper($rperlnamespaces_generated::RPERL->{$namespace_root}) . "\n";
162              
163             # DEV NOTE, CORRELATION #rp019: need remove hard-coded allowance of RPerl::Test namespace, at least move to rperlnamespaces.pm or friends
164 32 0 33     222 if (
      0        
      33        
165             ($package =~ /RPerl::Test/xms) or
166             ($package eq 'RPerl::CompileUnit::Module::Class::Template') or (
167             ( not exists $rperlnamespaces_generated::CORE->{$namespace_root} ) and
168             ( not exists $rperlnamespaces_generated::RPERL_DEPS->{$namespace_root} ) and
169             ( not exists $rperlnamespaces_generated::RPERL->{$namespace_root} ) ) )
170             {
171             # print {*STDERR} 'in RPerl::filter(), enabling subclasses for $package = ' . $package . "\n";
172              
173 32         111 my $input_line_prepend = q{};
174 32         79 $input_line_prepend .= '# <<<=== BEGIN $input_line_prepend ===>>>' . "\n";
175             # $input_line_prepend .= 'use RPerl::Config;' . "\n"; # DEV NOTE, CORRELATION #rp034: enable @ARG in all packages (class & non-class)
176 32         75 $input_line_prepend .= 'use RPerl::AfterSubclass;' . "\n";
177 32         77 $input_line_prepend .= '1; # end class, original' . "\n";
178 32         389 my $subclasses = {
179             '_raw' => [ 'RPerl::DataType::Modifier::Reference', 'ref' ],
180             '_arrayref' => [ 'RPerl::DataStructure::Array', 'arrayref' ],
181             '_hashref' => [ 'RPerl::DataStructure::Hash', 'hashref' ],
182             '::method' => [ 'RPerl::CodeBlock::Subroutine::Method', 'method' ],
183             '_arrayref::method' => [ 'RPerl::CodeBlock::Subroutine::Method', 'method' ],
184             '_hashref::method' => [ 'RPerl::CodeBlock::Subroutine::Method', 'method' ],
185             };
186 32         98 $input_line_prepend .= "\n" . '# [[[ SUBCLASSES, AUTO-GENERATED ]]]' . "\n";
187 32         65 foreach my $subclass_key ( sort keys %{$subclasses} ) {
  32         235  
188 192         428 $input_line_prepend .= 'package ' . $package . $subclass_key . ';' . "\n";
189              
190             # $input_line_prepend .= 'use strict;' . "\n";
191             # $input_line_prepend .= 'use warnings;' . "\n";
192             # $input_line_prepend .= 'use RPerl::AfterSubclass;' . "\n";
193 192         404 $input_line_prepend .= 'use ' . $subclasses->{$subclass_key}->[0] . ';' . "\n";
194 192         335 $input_line_prepend .= 'use parent -norequire, qw(' . $subclasses->{$subclass_key}->[1] . ');' . "\n";
195 192         360 $input_line_prepend .= '1; # end class, auto-generated subclass' . "\n";
196             }
197 32         93 $input_line_prepend .= '# <<<=== END $input_line_prepend ===>>>' . "\n";
198 32         171 $input_line = $input_line_prepend . "\n";
199 32         130 $input_line .= '# [[[ HEADER, PART 2 ]]]' . "\n";
200 32         143 $input_line .= $package_line . "\n";
201 32         91 $input_line .= '# <<<=== BEGIN $post_package_lines ===>>>' . "\n";
202 32         70 $input_line .= $post_package_lines; # append even if we don't enable subclasses
203 32         79 $input_line .= '# <<<=== END $post_package_lines ===>>>' . "\n";
204 32         139 $input_line .= $use_parent_line . "\n";
205              
206             # DEV NOTE: perl calls filter() but perlcritic does not, '## no critic...' & 'use strict' can be passed to perl but not perlcritic,
207             # so we must still put critics & strict in every RPerl file;
208             # 'use warnings' is checked by perl but not perlcritic, so it can be passed to perl and not put in every RPerl file;
209             # $input_line .= 'use strict;' . "\n";
210             # $input_line .= 'use warnings;' . "\n";
211 32         89 $input_line .= 'use RPerl::Config;' . "\n";
212 32         146 $input_line .= 'use RPerl::AfterSubclass;';
213              
214             # print {*STDERR} 'in RPerl::filter(), have modified $input_line = ' . "\n" . $input_line . "\n";
215             }
216             # else { print {*STDERR} 'in RPerl::filter(), NOT enabling subclasses or RPerl::AfterSubclass for $package = ' . $package . "\n"; }
217 32         97 $output .= $input_line . "\n";
218 32         98 $package = q{};
219 32         110 $package_line = q{};
220 32         102 $post_package_lines = q{};
221             }
222             elsif ( $package ne q{} ) {
223 156         356 $post_package_lines .= $input_line . "\n";
224             }
225             else {
226 1209         2091 $output .= $input_line . "\n";
227             }
228             }
229              
230             # package but not a class
231 24         155 $output .= $post_package_lines;
232            
233             # replace fake SSE infix operators with their actually-overloaded single-character selves
234 24         281 foreach my $sse_define_pair (['sse_add', '+'], ['sse_sub', '-'], ['sse_mul', '*'], ['sse_div', '/']) {
235 96         1210 $output =~ s/$sse_define_pair->[0]/$sse_define_pair->[1]/gxms;
236             }
237              
238             # print {*STDERR} "\n" . 'in RPerl::filter(), have post-modification $output = ' . "\n" . '<<<<<<<<<<<<<<<<================ BEGIN OUTPUT FILE ================>>>>>>>>>>>>>>' . "\n" . $output . '<<<<<<<<<<<<<<<<================ END OUTPUT FILE ================>>>>>>>>>>>>>>' . "\n\n";
239              
240 24         4280 return $output;
241             }
242              
243             1; # end of class
244              
245             __END__
246             =head1 NAME
247              
248             RPerl Back-End Module
249              
250             Restricted Perl, The Optimizing Perl 5 Compiler
251              
252             =head1 SYNOPSIS
253              
254             use RPerl;
255              
256             =head1 DESCRIPTION
257              
258             B<RPerl> is a compiler. For more info:
259              
260             L<https://github.com/wbraswell/rperl/blob/master/README.md>
261              
262             =head1 SEE ALSO
263              
264             L<rperl>
265              
266             =head1 AUTHOR
267              
268             B<William N. Braswell, Jr.>
269              
270             L<mailto:wbraswell@NOSPAM.cpan.org>
271              
272             =cut