File Coverage

blib/lib/RPerl/CompileUnit/Module/Class/Generator.pm
Criterion Covered Total %
statement 24 24 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 32 32 100.0


line stmt bran cond sub pod time code
1             # [[[ HEADER ]]]
2             package RPerl::CompileUnit::Module::Class::Generator;
3 4     4   27 use strict;
  4         12  
  4         121  
4 4     4   22 use warnings;
  4         9  
  4         113  
5 4     4   22 use RPerl::AfterSubclass;
  4         8  
  4         611  
6             our $VERSION = 0.010_000;
7              
8             # [[[ OO INHERITANCE ]]]
9 4     4   28 use parent qw(RPerl::CompileUnit::Module::Class);
  4         9  
  4         43  
10 4     4   273 use RPerl::CompileUnit::Module::Class;
  4         16  
  4         81  
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             # [[[ INCLUDES ]]]
17 4     4   22 use RPerl::Parser;
  4         7  
  4         81  
18 4     4   25 use RPerl::Generator;
  4         14  
  4         87  
19 4     4   21 use Storable qw(dclone);
  4         8  
  4         23531  
20              
21             # [[[ OO PROPERTIES ]]]
22             our hashref $properties = {};
23              
24             # [[[ SUBROUTINES & OO METHODS ]]]
25              
26             our string_hashref::method $ast_to_rperl__generate = sub {
27             ( my object $self, my string $package_name_underscores, my string_hashref $modes ) = @ARG;
28             my string_hashref $rperl_source_group = {};
29              
30             # RPerl::diag( 'in Class::Generator->ast_to_rperl__generate(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
31              
32             my string $self_class = ref $self;
33              
34             # unwrap Class_61 from Module_25
35             if ( ($self_class) eq 'Module_25' ) {
36             $self = $self->{children}->[0];
37             $self_class = ref $self;
38             }
39              
40             if ( ($self_class) ne 'Class_61' ) {
41             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASRP00, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: Grammar rule '
42             . ($self_class)
43             . ' found where Module_25 or Class_61 expected, dying' )
44             . "\n";
45             }
46              
47             # Class: 'use parent qw(' WordScoped ')' ';' Include Critic* Include* Constant* Properties MethodOrSubroutine* LITERAL_NUMBER ';' ;
48             # Class -> 'use parent qw(' WordScoped ')' ';' Include STAR-20 STAR-21 STAR-22 Properties STAR-23 LITERAL_NUMBER ';'
49             my string $use_parent_qw_keyword = $self->{children}->[0];
50             my string $parent_name = $self->{children}->[1]->{children}->[0];
51             my string $right_parenthesis = $self->{children}->[2];
52             my string $use_parent_semicolon = $self->{children}->[3];
53             my object $parent_include = $self->{children}->[4];
54             my object $critic_star = $self->{children}->[5];
55             my object $include_star = $self->{children}->[6];
56             my object $constant_star = $self->{children}->[7];
57             my object $properties = $self->{children}->[8];
58             my object $method_or_subroutine_star = $self->{children}->[9];
59             my string $retval_literal_number = $self->{children}->[10];
60             my string $retval_semicolon = $self->{children}->[11];
61              
62             $rperl_source_group->{PMC} = q{};
63             if ( $modes->{label} eq 'ON' ) {
64             $rperl_source_group->{PMC} .= '# [[[ OO INHERITANCE ]]]' . "\n";
65             }
66             $rperl_source_group->{PMC} .= $use_parent_qw_keyword . $parent_name . $right_parenthesis . $use_parent_semicolon . "\n";
67              
68             my string_hashref $rperl_source_subgroup = $parent_include->ast_to_rperl__generate($modes);
69             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
70              
71             if ( exists $critic_star->{children}->[0] ) {
72             if ( $modes->{label} eq 'ON' ) {
73             $rperl_source_group->{PMC} .= '# [[[ CRITICS ]]]' . "\n";
74             }
75             }
76             foreach my object $critic ( @{ $critic_star->{children} } ) {
77             $rperl_source_subgroup = $critic->ast_to_rperl__generate($modes);
78             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
79             }
80              
81             if ( exists $include_star->{children}->[0] ) {
82             if ( $modes->{label} eq 'ON' ) {
83             $rperl_source_group->{PMC} .= "\n" . '# [[[ INCLUDES ]]]' . "\n";
84             }
85             }
86             foreach my object $include ( @{ $include_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
87             $rperl_source_subgroup = $include->ast_to_rperl__generate($modes);
88             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
89             }
90              
91             if ( exists $constant_star->{children}->[0] ) {
92             if ( $modes->{label} eq 'ON' ) {
93             $rperl_source_group->{PMC} .= "\n" . '# [[[ CONSTANTS ]]]' . "\n";
94             }
95             }
96             foreach my object $constant ( @{ $constant_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
97             $rperl_source_subgroup = $constant->ast_to_rperl__generate($modes);
98             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
99             }
100              
101             if ( $modes->{label} eq 'ON' ) {
102             $rperl_source_group->{PMC} .= "\n" . '# [[[ OO PROPERTIES ]]]' . "\n";
103             }
104              
105             # prepare for later use in:
106             # disallow name masking of inherited $properties, AND
107             # generate accessors & mutators for inherited $properties
108             my string $package_name_colons = $package_name_underscores;
109             $package_name_colons =~ s/__/::/gxms;
110             my $parent_package_names = RPerl::CompileUnit::Module::Class::parent_and_grandparent_package_names($package_name_colons);
111             # RPerl::diag( 'in Class::Generator->ast_to_rperl__generate(), have $parent_package_names = ' . Dumper($parent_package_names) . "\n" );
112              
113             if ( ref $properties eq 'Properties_65' ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
114             # non-empty $properties
115             my string $properties_our_hashref = $properties->{children}->[0];
116             my string $properties_equal = $properties->{children}->[1];
117             my string $properties_left_brace = $properties->{children}->[2];
118             my object $property_0 = $properties->{children}->[3];
119             my object $properties_1_to_n = $properties->{children}->[4];
120             my string $properties_right_brace = $properties->{children}->[5];
121             my string $properties_semicolon = $properties->{children}->[6];
122              
123             $rperl_source_group->{PMC} .= $properties_our_hashref . q{ } . $properties_equal . q{ } . $properties_left_brace . "\n";
124              
125             my string $property_key;
126             my string $property_fat_arrow;
127             my object $property_type_inner;
128             my string $property_my;
129             my string $property_type;
130             my string $property_TYPED;
131             my string $property_name;
132             my string $property_arrayref_thinarrow;
133             my object $property_arrayref_index_max;
134             my string $property_arrayref_rightbracket;
135             my string $property_assign;
136             my object $property_subexpression;
137             my string $property_subexpression_string;
138              
139             $property_key = $property_0->{children}->[0]->{children}->[0];
140             $property_key =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
141             if ( $property_key !~ /^[a-z]/ ) {
142             die 'ERROR ECOGEASRP24, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: invalid OO properties name (hash key) ' . q{'}
143             . $property_key . q{'}
144             . ' does not start with a lowercase letter a-z, dying' . "\n";
145             }
146             $property_fat_arrow = $property_0->{children}->[1];
147             $property_type_inner = $property_0->{children}->[2];
148             $property_name = $property_type_inner->{children}->[3]->{children}->[0];
149             $property_name =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
150              
151             # DEV NOTE: we can do error checking once here instead of twice for TypeInnerProperties_224 & TypeInnerProperties_225 below
152             # because they both have OpStringOrWord as sub-element 3, grabbed as $property_name above
153             if ( $property_name ne $property_key ) {
154             die 'ERROR ECOGEASRP21, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: redundant name mismatch, inner type name ' . q{'}
155             . $property_name . q{'}
156             . ' does not equal OO properties key ' . q{'}
157             . $property_key . q{'}
158             . ', dying' . "\n";
159             }
160              
161             # TypeInnerProperties -> MY Type '$TYPED_' OpStringOrWord OP19_VARIABLE_ASSIGN SubExpression
162             if ( ref $property_type_inner eq 'TypeInnerProperties_224' ) {
163             $property_my = $property_type_inner->{children}->[0];
164             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
165             $property_TYPED = $property_type_inner->{children}->[2];
166             $property_assign = $property_type_inner->{children}->[4];
167             $property_subexpression = $property_type_inner->{children}->[5];
168              
169             $rperl_source_group->{PMC}
170             .= $property_key . q{ }
171             . $property_fat_arrow . q{ }
172             . $property_my . q{ }
173             . $property_type . q{ }
174             . $property_TYPED
175             . $property_name . q{ }
176             . $property_assign . q{ };
177              
178             $rperl_source_subgroup = $property_subexpression->ast_to_rperl__generate($modes);
179             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
180             }
181              
182             # TypeInnerProperties -> MY Type '$TYPED_' OpStringOrWord OP02_ARRAY_THINARROW SubExpression ']' OP19_VARIABLE_ASSIGN 'undef'
183             elsif ( ref $property_type_inner eq 'TypeInnerProperties_225' ) {
184             $property_my = $property_type_inner->{children}->[0];
185             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
186             $property_TYPED = $property_type_inner->{children}->[2];
187             $property_arrayref_thinarrow = $property_type_inner->{children}->[4];
188             $property_arrayref_index_max = $property_type_inner->{children}->[5];
189             $property_arrayref_rightbracket = $property_type_inner->{children}->[6];
190             $property_assign = $property_type_inner->{children}->[7];
191             $property_subexpression_string = $property_type_inner->{children}->[8];
192              
193             $rperl_source_group->{PMC}
194             .= $property_key . q{ }
195             . $property_fat_arrow . q{ }
196             . $property_my . q{ }
197             . $property_type . q{ }
198             . $property_TYPED
199             . $property_name
200             . $property_arrayref_thinarrow;
201              
202             $rperl_source_subgroup = $property_arrayref_index_max->ast_to_rperl__generate($modes);
203             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
204              
205             $rperl_source_group->{PMC} .= $property_arrayref_rightbracket . q{ } . $property_assign . q{ } . $property_subexpression_string;
206             }
207             else {
208             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP00, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule '
209             . ( ref $self )
210             . ' found where TypeInnerProperties_224 or TypeInnerProperties_225 expected, dying' )
211             . "\n";
212             }
213              
214             # CREATE SYMBOL TABLE ENTRY
215             if ( exists $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key} ) {
216             die 'ERROR ECOGEASRP10, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: OO property '
217             . q{'} . $property_key . q{'}
218             . ' already declared in this scope, namespace '
219             . q{'} . $modes->{_symbol_table}->{_namespace} . q{'}
220             . ', dying' . "\n";
221             }
222              
223             # RPerl::diag( 'in Class::Generator->ast_to_rperl__generate(), property 0, have $parent_package_names = ' . "\n" . Dumper($parent_package_names) . "\n" ) if (scalar @{$parent_package_names});
224              
225             # disallow name masking of inherited $properties, causes mismatching behavior in PERLOPS_PERLTYPES vs CPPOPS_CPPTYPES
226             foreach my $parent_package_name (@{$parent_package_names}) {
227             if ( exists $modes->{_symbol_table}->{ $parent_package_name . q{::} }->{_properties}->{$property_key} ) {
228             die 'ERROR ECOGEASRP11, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: OO property '
229             . q{'} . $property_key . q{'}
230             . ' already declared in parent namespace '
231             . q{'} . $parent_package_name . q{::} . q{'}
232             . ', name masking disallowed, dying' . "\n";
233             }
234             }
235              
236             $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}
237             = { isa => 'RPerl::DataStructure::Hash::Properties', type => $property_type };
238              
239             my integer $i = 0;
240             foreach my object $property ( @{ $properties_1_to_n->{children} } ) {
241             if ( ( ref $property ) eq 'TERMINAL' ) {
242             $rperl_source_group->{PMC} .= $property->{attr}; # comma between properties
243             }
244             else {
245             $i++;
246             $property_key = $property->{children}->[0]->{children}->[0];
247             $property_key =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
248             if ( $property_key !~ /^[a-z]/ ) {
249             die 'ERROR ECOGEASRP24, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: invalid OO properties name (hash key) ' . q{'}
250             . $property_key . q{'}
251             . ' does not start with a lowercase letter a-z, dying' . "\n";
252             }
253             $property_fat_arrow = $property->{children}->[1];
254             $property_type_inner = $property->{children}->[2];
255             $property_name = $property_type_inner->{children}->[3]->{children}->[0];
256             $property_name =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
257              
258             if ( $property_name ne $property_key ) {
259             die 'ERROR ECOGEASRP21, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: redundant name mismatch, inner type name ' . q{'}
260             . $property_name . q{'}
261             . ' does not equal OO properties key ' . q{'}
262             . $property_key . q{'}
263             . ', dying' . "\n";
264             }
265              
266             # TypeInnerProperties -> MY Type '$TYPED_' WORD OP19_VARIABLE_ASSIGN SubExpression
267             if ( ref $property_type_inner eq 'TypeInnerProperties_224' ) {
268             $property_my = $property_type_inner->{children}->[0];
269             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
270             $property_TYPED = $property_type_inner->{children}->[2];
271             $property_assign = $property_type_inner->{children}->[4];
272             $property_subexpression = $property_type_inner->{children}->[5];
273              
274             $rperl_source_group->{PMC}
275             .= $property_key . q{ }
276             . $property_fat_arrow . q{ }
277             . $property_my . q{ }
278             . $property_type . q{ }
279             . $property_TYPED
280             . $property_name . q{ }
281             . $property_assign . q{ };
282              
283             $rperl_source_subgroup = $property_subexpression->ast_to_rperl__generate($modes);
284             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
285             }
286              
287             # TypeInnerProperties -> MY Type '$TYPED_' WORD OP02_ARRAY_THINARROW SubExpression ']' OP19_VARIABLE_ASSIGN 'undef'
288             elsif ( ref $property_type_inner eq 'TypeInnerProperties_225' ) {
289             $property_my = $property_type_inner->{children}->[0];
290             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
291             $property_TYPED = $property_type_inner->{children}->[2];
292             $property_arrayref_thinarrow = $property_type_inner->{children}->[4];
293             $property_arrayref_index_max = $property_type_inner->{children}->[5];
294             $property_arrayref_rightbracket = $property_type_inner->{children}->[6];
295             $property_assign = $property_type_inner->{children}->[7];
296             $property_subexpression_string = $property_type_inner->{children}->[8];
297              
298             $rperl_source_group->{PMC}
299             .= $property_key . q{ }
300             . $property_fat_arrow . q{ }
301             . $property_my . q{ }
302             . $property_type . q{ }
303             . $property_TYPED
304             . $property_name
305             . $property_arrayref_thinarrow;
306              
307             $rperl_source_subgroup = $property_arrayref_index_max->ast_to_rperl__generate($modes);
308             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
309              
310             $rperl_source_group->{PMC} .= $property_arrayref_rightbracket . q{ } . $property_assign . q{ } . $property_subexpression_string;
311             }
312             else {
313             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP00, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule '
314             . ( ref $self )
315             . ' found where TypeInnerProperties_224 or TypeInnerProperties_225 expected, dying' )
316             . "\n";
317             }
318              
319             # CREATE SYMBOL TABLE ENTRY
320             if ( exists $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key} ) {
321             die 'ERROR ECOGEASRP10, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: OO property '
322             . $property_key
323             . ' already declared in this scope, namespace '
324             . $modes->{_symbol_table}->{_namespace}
325             . ', dying' . "\n";
326             }
327              
328             # RPerl::diag( 'in Class::Generator->ast_to_rperl__generate(), property ' . $i . ', have $parent_package_names = ' . "\n" . Dumper($parent_package_names) . "\n" ) if (scalar @{$parent_package_names});
329              
330             # disallow name masking of inherited $properties, causes mismatching behavior in PERLOPS_PERLTYPES vs CPPOPS_CPPTYPES
331             foreach my $parent_package_name (@{$parent_package_names}) {
332             if ( exists $modes->{_symbol_table}->{ $parent_package_name . q{::} }->{_properties}->{$property_key} ) {
333             die 'ERROR ECOGEASRP11, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: OO property '
334             . q{'} . $property_key . q{'}
335             . ' already declared in parent namespace '
336             . q{'} . $parent_package_name . q{::} . q{'}
337             . ', name masking disallowed, dying' . "\n";
338             }
339             }
340              
341             $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}
342             = { isa => 'RPerl::DataStructure::Hash::Properties', type => $property_type };
343             }
344             }
345             $rperl_source_group->{PMC} .= "\n" . $properties_right_brace . $properties_semicolon . "\n";
346             }
347             else { # ( ref $properties eq 'Properties_66' ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
348             # empty $properties
349             my string $properties_our_hashref = $properties->{children}->[0];
350             my string $properties_equal = $properties->{children}->[1];
351             my string $properties_left_brace = $properties->{children}->[2];
352             my string $properties_right_brace = $properties->{children}->[3];
353             my string $properties_semicolon = $properties->{children}->[4];
354             $rperl_source_group->{PMC}
355             .= $properties_our_hashref . q{ } . $properties_equal . q{ } . $properties_left_brace . $properties_right_brace . $properties_semicolon . "\n";
356             }
357              
358             if ( exists $method_or_subroutine_star->{children}->[0] ) {
359             if ( $modes->{label} eq 'ON' ) {
360             $rperl_source_group->{PMC} .= "\n" . '# [[[ SUBROUTINES & OO METHODS ]]]' . "\n\n";
361             }
362             }
363             foreach my object $method_or_subroutine ( ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
364             @{ $method_or_subroutine_star->{children} }
365             )
366             {
367             $rperl_source_subgroup = $method_or_subroutine->ast_to_rperl__generate($modes);
368             RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
369             }
370              
371             if ( $modes->{label} eq 'ON' ) {
372             $rperl_source_group->{PMC} .= "\n" . $retval_literal_number . $retval_semicolon . ' # end of class' . "\n";
373             }
374             else {
375             $rperl_source_group->{PMC} .= $retval_literal_number . $retval_semicolon . "\n";
376             }
377              
378             return $rperl_source_group;
379             };
380              
381             our string_hashref::method $ast_to_cpp__generate__CPPOPS_PERLTYPES = sub {
382             ( my object $self, my string $package_name_underscores, my string_hashref $modes ) = @ARG;
383             my string_hashref $cpp_source_group = {
384             CPP => q{// <<< RP::CU::M::C::G __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n",
385             H => q{// <<< RP::CU::M::C::G __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n",
386             PMC => q{# <<< RP::CU::M::C::G __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>} . "\n"
387             };
388              
389             #...
390             return $cpp_source_group;
391             };
392              
393             our string_hashref::method $ast_to_cpp__generate__CPPOPS_CPPTYPES = sub {
394             ( my object $self, my string $package_name_underscores, my string_hashref $modes ) = @ARG;
395             my string_hashref $cpp_source_group = { H_INCLUDES => q{}, H => q{}, CPP => q{} };
396              
397             #RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
398             #RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $package_name_underscores = ' . $package_name_underscores . "\n");
399             #RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $modes = ' . "\n" . Dumper($modes) . "\n");
400             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $modes->{_symbol_table} = ' . "\n" . Dumper($modes->{_symbol_table}) . "\n");
401              
402             my string $self_class = ref $self;
403              
404             # unwrap Class_61 from Module_25
405             if ( ($self_class) eq 'Module_25' ) {
406             $self = $self->{children}->[0];
407             $self_class = ref $self;
408             }
409              
410             if ( ($self_class) ne 'Class_61' ) {
411             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP00, CODE GENERATOR, ABSTRACT SYNTAX TO C++, CPPOPS_CPPTYPES: Grammar rule '
412             . ($self_class)
413             . ' found where Module_25 or Class_61 expected, dying' )
414             . "\n";
415             }
416              
417             # Class: 'use parent qw(' WordScoped ')' ';' Include Critic* Include* Constant* Properties MethodOrSubroutine* LITERAL_NUMBER ';' ;
418             # Class -> 'use parent qw(' WordScoped ')' ';' Include STAR-20 STAR-21 STAR-22 Properties STAR-23 LITERAL_NUMBER ';'
419             my string $parent_name = $self->{children}->[1]->{children}->[0];
420             my string $use_keyword = $self->{children}->[4]->{children}->[0];
421             my object $include_star = $self->{children}->[6];
422             my object $constant_star = $self->{children}->[7];
423             my object $properties = $self->{children}->[8];
424             my object $method_or_subroutine_star = $self->{children}->[9];
425              
426             if ( $modes->{label} eq 'ON' ) {
427             $cpp_source_group->{H_INCLUDES} .= '// [[[ INCLUDES & OO INHERITANCE INCLUDES ]]]' . "\n";
428             $cpp_source_group->{CPP} .= '// [[[ INCLUDES ]]]' . "\n";
429             $cpp_source_group->{H_INCLUDES} .= <<EOL;
430             #include <RPerl.cpp> // -> RPerl.h -> (rperltypes_mode.h; rperloperations.h; rperltypes.h; HelperFunctions.cpp)
431             EOL
432             }
433             else {
434             $cpp_source_group->{H_INCLUDES} .= <<EOL;
435             #include <RPerl.cpp>
436             EOL
437             }
438              
439             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $modes->{_enable_sse} = ' . Dumper($modes->{_enable_sse}) . "\n");
440             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $modes->{_enable_gmp} = ' . Dumper($modes->{_enable_gmp}) . "\n");
441              
442             # NEED FIX WIN32: change hard-coded forward-slash in generated path name below?
443             # NEED FIX: handle absolute vs relative include paths
444             my string $module_file_name = $package_name_underscores;
445             $module_file_name =~ s/__/\//gxms;
446             $module_file_name .= '.pm';
447              
448             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $module_file_name = ' . $module_file_name . "\n");
449              
450             if ( ( exists $modes->{_enable_sse} ) and ( defined $modes->{_enable_sse} ) ) {
451             foreach my string $module_path_name ( keys %{ $modes->{_enable_sse} } ) {
452             if ( ( $module_path_name =~ /$module_file_name$/xms ) and ( $modes->{_enable_sse}->{$module_path_name} ) ) {
453             $cpp_source_group->{H_INCLUDES} .= '#include <rperlsse.h>' . "\n";
454             }
455             }
456             }
457              
458             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $modes->{_enable_gmp} = ' . Dumper($modes->{_enable_gmp}) . "\n");
459             if ( ( exists $modes->{_enable_gmp} ) and ( defined $modes->{_enable_gmp} ) ) {
460             foreach my string $module_path_name ( keys %{ $modes->{_enable_gmp} } ) {
461             if ( ( $module_path_name =~ /$module_file_name$/xms ) and ( $modes->{_enable_gmp}->{$module_path_name} ) ) {
462             $cpp_source_group->{H_INCLUDES} .= '#include <rperlgmp.h>' . "\n";
463             }
464             }
465             }
466              
467             # NEED FIX WIN32: change hard-coded forward-slash in generated path name below?
468             # NEED FIX: handle absolute vs relative include paths
469             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $parent_name = ' . $parent_name . "\n");
470             my string $parent_name_path = $parent_name;
471             $parent_name_path =~ s/::/\//gxms;
472             $parent_name_path .= '.cpp';
473             if ( $parent_name =~ /^\w+Perl::Config$/ ) { # DEV NOTE, CORRELATION #rp027: MathPerl::Config, PhysicsPerl::Config, etc
474              
475             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), skipping system config file $parent_name = ' . $parent_name . "\n");
476             }
477             elsif ( ( ( substr $parent_name_path, 0, 5 ) ne 'RPerl' ) and ( ( substr $parent_name_path, 0, 5 ) ne 'rperl' ) ) {
478             # non-RPerl user module, wrapped in double-quotes " " to denote user nature
479             $cpp_source_group->{H_INCLUDES} .= '#include "' . $parent_name_path . '"' . "\n";
480             }
481             else {
482             # RPerl system module, wrapped in angle-brackets < > to denote system nature
483             $cpp_source_group->{H_INCLUDES} .= '#include <' . $parent_name_path . '>' . "\n";
484             }
485             $cpp_source_group->{CPP} .= '#include "__NEED_HEADER_PATH"' . "\n"; # defer setting header include path until files are saved in Compiler
486              
487             my string_hashref $cpp_source_subgroup;
488              
489             foreach my object $include ( @{ $include_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
490             $cpp_source_subgroup = $include->ast_to_cpp__generate__CPPOPS_CPPTYPES( $package_name_underscores, $modes );
491             RPerl::Generator::source_group_append( $cpp_source_group, $cpp_source_subgroup );
492             }
493              
494             my string $cpp_source_tmp = <<EOL;
495              
496             # ifdef __PERL__TYPES
497              
498             Purposefully_die_from_a_compile-time_error,_due_to____PERL__TYPES_being_defined.__We_need_to_define_only___CPP__TYPES_in_this_file!
499              
500             # elif defined __CPP__TYPES
501              
502             EOL
503              
504             $cpp_source_group->{H} .= $cpp_source_tmp;
505             $cpp_source_group->{CPP} .= $cpp_source_tmp;
506              
507             if ( $modes->{label} eq 'ON' ) {
508             $cpp_source_tmp = ( ( '// [[[<<< BEGIN CPP TYPES >>>]]]' . "\n" ) x 3 ) . "\n";
509             $cpp_source_group->{H} .= $cpp_source_tmp;
510             $cpp_source_group->{CPP} .= $cpp_source_tmp;
511             }
512              
513             if ( exists $constant_star->{children}->[0] ) {
514             if ( $modes->{label} eq 'ON' ) {
515             $cpp_source_group->{H} .= '// [[[ CONSTANTS ]]]' . "\n";
516             }
517             foreach my object $constant ( @{ $constant_star->{children} } ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
518             $cpp_source_subgroup = $constant->ast_to_cpp__generate__CPPOPS_CPPTYPES( $package_name_underscores, $modes );
519             $cpp_source_group->{H} .= $cpp_source_subgroup->{H};
520             $cpp_source_group->{_H_constants_shims}->{$package_name_underscores} .= $cpp_source_subgroup->{_H_constants_shims}->{$package_name_underscores};
521             }
522             $cpp_source_group->{H} .= "\n";
523             }
524              
525             if ( $modes->{label} eq 'ON' ) {
526             $cpp_source_group->{H} .= '// [[[ OO INHERITANCE ]]]' . "\n";
527             }
528             my string $parent_name_underscores = $parent_name;
529             $parent_name_underscores =~ s/::/__/gxms;
530              
531             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $parent_name_underscores = ' . $parent_name_underscores . "\n");
532              
533             # DEV NOTE: avoid namespace clobbering of CPPOPS base class over PERLOPS base class
534             if ( $parent_name_underscores eq 'RPerl__CompileUnit__Module__Class' ) {
535             $parent_name_underscores .= '__CPP';
536             }
537              
538             $cpp_source_group->{H} .= 'class ' . $package_name_underscores . ' : public ' . $parent_name_underscores . ' {' . "\n";
539             $cpp_source_group->{H} .= 'public:' . "\n";
540              
541             my string_arrayref $properties_accessors_mutators = [];
542             my string_arrayref $properties_accessors_mutators_shims = [];
543             my string_arrayref $properties_declarations = [];
544             my string_arrayref $properties_initializations = [];
545             my string $property_declaration;
546              
547             # prepare for later use in:
548             # disallow name masking of inherited $properties, AND
549             # generate accessors & mutators for inherited $properties
550             my string $package_name_colons = $package_name_underscores;
551             $package_name_colons =~ s/__/::/gxms;
552             my $parent_package_names = RPerl::CompileUnit::Module::Class::parent_and_grandparent_package_names($package_name_colons);
553             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $parent_package_names = ' . Dumper($parent_package_names) . "\n" );
554              
555             # non-empty $properties
556             # Properties -> 'our hashref $properties' OP19_VARIABLE_ASSIGN LBRACE HashEntryProperties STAR-27 '}' ';'
557             # HashEntryProperties -> WORD OP20_HASH_FATARROW TypeInnerProperties
558             if ( ref $properties eq 'Properties_65' ) { ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
559             $modes->{_inside_class_properties} = 1;
560             $property_declaration = q{};
561             my object $property_0 = $properties->{children}->[3];
562             my object $properties_1_to_n = $properties->{children}->[4];
563              
564             my string $property_key = $property_0->{children}->[0]->{children}->[0];
565             $property_key =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
566             if ( $property_key !~ /^[a-z]/ ) {
567             die 'ERROR ECOGEASCP24, CODE GENERATOR, ABSTRACT SYNTAX TO C++: invalid OO properties name (hash key) ' . q{'}
568             . $property_key . q{'}
569             . ' does not start with a lowercase letter a-z, dying' . "\n";
570             }
571             my object $property_type_inner = $property_0->{children}->[2];
572             my string $property_type = undef;
573             my object $property_subexpression = undef;
574             my object $property_arrayref_index_max = undef;
575             my string $property_name = $property_type_inner->{children}->[3]->{children}->[0];
576             $property_name =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
577              
578             # DEV NOTE: we can do error checking once here instead of twice for TypeInnerProperties_224 & TypeInnerProperties_225 below
579             # because they both have OpStringOrWord as sub-element 3, grabbed as $property_name above
580             if ( $property_name ne $property_key ) {
581             # DEV NOTE, CORRELATION #rp030: matches numbering of ECOGEPPRP20 in RPerl/CompileUnit/Module/Class.pm
582             die 'ERROR ECOGEASCP21, CODE GENERATOR, ABSTRACT SYNTAX TO C++: redundant name mismatch, inner type name ' . q{'}
583             . $property_name . q{'}
584             . ' does not equal OO properties key ' . q{'}
585             . $property_key . q{'}
586             . ', dying' . "\n";
587             }
588              
589             # TypeInnerProperties -> MY Type '$TYPED_' WORD OP19_VARIABLE_ASSIGN SubExpression
590             if ( ref $property_type_inner eq 'TypeInnerProperties_224' ) {
591             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
592             $property_subexpression = $property_type_inner->{children}->[5];
593             }
594              
595             # TypeInnerProperties -> MY Type '$TYPED_' WORD OP02_ARRAY_THINARROW SubExpression ']' OP19_VARIABLE_ASSIGN 'undef'
596             elsif ( ref $property_type_inner eq 'TypeInnerProperties_225' ) {
597             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
598             $property_arrayref_index_max = $property_type_inner->{children}->[5];
599             }
600             else {
601             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP00, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule '
602             . ( ref $self )
603             . ' found where TypeInnerProperties_224 or TypeInnerProperties_225 expected, dying' )
604             . "\n";
605             }
606              
607             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property 0, have $property_key = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_key) . "\n" );
608             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property 0, have $property_type_inner = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_type_inner) . "\n" );
609             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property 0, have $property_subexpression = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_subexpression) . "\n" );
610             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property 0, have $property_type = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_type) . "\n" );
611             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property 0, have $property_arrayref_index_max = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_arrayref_index_max) . "\n" );
612              
613             # CREATE SYMBOL TABLE ENTRY
614             if ( exists $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key} ) {
615             die 'ERROR ECOGEASCP10, CODE GENERATOR, ABSTRACT SYNTAX TO C++: OO property '
616             . q{'} . $property_key . q{'}
617             . ' already declared in this scope, namespace '
618             . q{'} . $modes->{_symbol_table}->{_namespace} . q{'}
619             . ', dying' . "\n";
620             }
621              
622             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property 0, have $parent_package_names = ' . "\n" . Dumper($parent_package_names) . "\n" ) if (scalar @{$parent_package_names});
623              
624             # disallow name masking of inherited $properties, causes mismatching behavior in PERLOPS_PERLTYPES vs CPPOPS_CPPTYPES
625             foreach my $parent_package_name (@{$parent_package_names}) {
626             if ( exists $modes->{_symbol_table}->{ $parent_package_name . q{::} }->{_properties}->{$property_key} ) {
627             die 'ERROR ECOGEASCP11, CODE GENERATOR, ABSTRACT SYNTAX TO C++: OO property '
628             . q{'} . $property_key . q{'}
629             . ' already declared in parent namespace '
630             . q{'} . $parent_package_name . q{::} . q{'}
631             . ', name masking disallowed, dying' . "\n";
632             }
633             }
634              
635             $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}
636             = { isa => 'RPerl::DataStructure::Hash::Properties', type => $property_type };
637              
638             $property_type = RPerl::Generator::type_convert_perl_to_cpp( $property_type, 1 ); # $pointerify_classes = 1
639             $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}->{type_cpp} = $property_type; # add converted C++ type to symtab entry
640              
641             if ( defined $property_arrayref_index_max ) {
642             my string $property_arrayref_index_max_address = "$property_arrayref_index_max";
643             $property_arrayref_index_max = RPerl::Generator::arrayref_convert_index_max_to_size($property_arrayref_index_max);
644             $cpp_source_subgroup = $property_arrayref_index_max->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
645             if ( $property_arrayref_index_max_address eq "$property_arrayref_index_max" ) { # not compensated automatically, must compensate manually
646             $cpp_source_subgroup->{CPP} = q{(} . $cpp_source_subgroup->{CPP} . q{) + 1};
647             }
648             push @{$properties_initializations}, ( q{ } . 'this->' . $property_key . '.resize(' . $cpp_source_subgroup->{CPP} . ');' );
649             }
650              
651             $property_declaration = q{ } . $property_type . q{ } . $property_key;
652              
653             # SubExpression_136 ISA RPerl::Operation::Expression::SubExpression::Literal::Undefined,
654             # don't perform any C++ initialization for properties initialized to 'undef' in Perl
655             if ( ( defined $property_subexpression ) and ( ( ref $property_subexpression ) ne 'SubExpression_136' ) ) {
656             $cpp_source_subgroup = $property_subexpression->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
657             $property_declaration .= ' = ' . $cpp_source_subgroup->{CPP};
658             }
659              
660             $property_declaration .= ';';
661             push @{$properties_declarations}, $property_declaration;
662              
663             $cpp_source_subgroup = ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES( $property_key, $modes->{_symbol_table}->{_namespace}, $modes );
664             if ( $cpp_source_subgroup->{H} ne q{} ) {
665             push @{$properties_accessors_mutators}, $cpp_source_subgroup->{H};
666             }
667             if ((exists $cpp_source_subgroup->{PMC}) and (defined $cpp_source_subgroup->{PMC}) and ($cpp_source_subgroup->{PMC} ne q{})) {
668             push @{$properties_accessors_mutators_shims}, $cpp_source_subgroup->{PMC};
669             }
670              
671             my integer $i = 0;
672             foreach my object $property ( @{ $properties_1_to_n->{children} } ) {
673             if ( ( ref $property ) eq 'TERMINAL' ) { # skip comma between properties
674             next;
675             }
676             $i++;
677              
678             $property_subexpression = undef;
679             $property_arrayref_index_max = undef;
680              
681             $property_key = $property->{children}->[0]->{children}->[0];
682             $property_key =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
683             if ( $property_key !~ /^[a-z]/ ) {
684             die 'ERROR ECOGEASCP24, CODE GENERATOR, ABSTRACT SYNTAX TO C++: invalid OO properties name (hash key) ' . q{'}
685             . $property_key . q{'}
686             . ' does not start with a lowercase letter a-z, dying' . "\n";
687             }
688             $property_type_inner = $property->{children}->[2];
689             $property_name = $property_type_inner->{children}->[3]->{children}->[0];
690             $property_name =~ s/^(\w+)\s*$/$1/gxms; # strip trailing whitespace, caused by grammar matching operator names with trailing spaces
691              
692             # DEV NOTE: we can do error checking once here instead of twice for TypeInnerProperties_224 & TypeInnerProperties_225 below
693             # because they both have OpStringOrWord as sub-element 3, grabbed as $property_name above
694             if ( $property_name ne $property_key ) {
695             # DEV NOTE, CORRELATION #rp030: matches numbering of ECOGEPPRP20 in RPerl/CompileUnit/Module/Class.pm
696             die 'ERROR ECOGEASCP21, CODE GENERATOR, ABSTRACT SYNTAX TO C++: redundant name mismatch, inner type name ' . q{'}
697             . $property_name . q{'}
698             . ' does not equal OO properties key ' . q{'}
699             . $property_key . q{'}
700             . ', dying' . "\n";
701             }
702              
703             # TypeInnerProperties -> MY Type '$TYPED_' WORD OP19_VARIABLE_ASSIGN SubExpression
704             if ( ref $property_type_inner eq 'TypeInnerProperties_224' ) {
705             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
706             $property_subexpression = $property_type_inner->{children}->[5];
707             }
708              
709             # TypeInnerProperties -> MY Type '$TYPED_' WORD OP02_ARRAY_THINARROW SubExpression ']' OP19_VARIABLE_ASSIGN 'undef'
710             elsif ( ref $property_type_inner eq 'TypeInnerProperties_225' ) {
711             $property_type = $property_type_inner->{children}->[1]->{children}->[0];
712             $property_arrayref_index_max = $property_type_inner->{children}->[5];
713             }
714             else {
715             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP00, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule '
716             . ( ref $self )
717             . ' found where TypeInnerProperties_224 or TypeInnerProperties_225 expected, dying' )
718             . "\n";
719             }
720              
721             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property ' . $i . ', have $property_key = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_key) . "\n" );
722             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property ' . $i . ', have $property_type_inner = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_type_inner) . "\n" );
723             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property ' . $i . ', have $property_subexpression = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_subexpression) . "\n" );
724             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property ' . $i . ', have $property_type = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_type) . "\n" );
725             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property ' . $i . ', have $property_arrayref_index_max = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_arrayref_index_max) . "\n" );
726              
727             # CREATE SYMBOL TABLE ENTRY
728             if ( exists $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key} ) {
729             die 'ERROR ECOGEASCP10, CODE GENERATOR, ABSTRACT SYNTAX TO C++: OO property '
730             . $property_key
731             . ' already declared in this scope, namespace '
732             . $modes->{_symbol_table}->{_namespace}
733             . ', dying' . "\n";
734             }
735              
736             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), property ' . $i . ', have $parent_package_names = ' . "\n" . Dumper($parent_package_names) . "\n" ) if (scalar @{$parent_package_names});
737            
738             # disallow name masking of inherited $properties, causes mismatching behavior in PERLOPS_PERLTYPES vs CPPOPS_CPPTYPES
739             foreach my $parent_package_name (@{$parent_package_names}) {
740             if ( exists $modes->{_symbol_table}->{ $parent_package_name . q{::} }->{_properties}->{$property_key} ) {
741             die 'ERROR ECOGEASCP11, CODE GENERATOR, ABSTRACT SYNTAX TO C++: OO property '
742             . q{'} . $property_key . q{'}
743             . ' already declared in parent namespace '
744             . q{'} . $parent_package_name . q{::} . q{'}
745             . ', name masking disallowed, dying' . "\n";
746             }
747             }
748              
749             $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}
750             = { isa => 'RPerl::DataStructure::Hash::Properties', type => $property_type };
751              
752             $property_type = RPerl::Generator::type_convert_perl_to_cpp( $property_type, 1 ); # $pointerify_classes = 1
753             $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}->{type_cpp} = $property_type; # add converted C++ type to symtab entry
754              
755             if ( defined $property_arrayref_index_max ) {
756             my string $property_arrayref_index_max_address = "$property_arrayref_index_max";
757             $property_arrayref_index_max = RPerl::Generator::arrayref_convert_index_max_to_size($property_arrayref_index_max);
758             $cpp_source_subgroup = $property_arrayref_index_max->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
759             if ( $property_arrayref_index_max_address eq "$property_arrayref_index_max" ) { # not compensated automatically, must compensate manually
760             $cpp_source_subgroup->{CPP} = q{(} . $cpp_source_subgroup->{CPP} . q{) + 1};
761             }
762             push @{$properties_initializations}, ( q{ } . 'this->' . $property_key . '.resize(' . $cpp_source_subgroup->{CPP} . ');' );
763             }
764              
765             $property_declaration = q{ } . $property_type . q{ } . $property_key;
766              
767             # SubExpression_136 ISA RPerl::Operation::Expression::SubExpression::Literal::Undefined,
768             # don't perform any C++ initialization for properties initialized to 'undef' in Perl
769             if ( ( defined $property_subexpression ) and ( ( ref $property_subexpression ) ne 'SubExpression_136' ) ) {
770             $cpp_source_subgroup = $property_subexpression->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
771             $property_declaration .= ' = ' . $cpp_source_subgroup->{CPP};
772             }
773              
774             $property_declaration .= ';';
775             push @{$properties_declarations}, $property_declaration;
776              
777             $cpp_source_subgroup = ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES( $property_key, $modes->{_symbol_table}->{_namespace}, $modes );
778             if ( $cpp_source_subgroup->{H} ne q{} ) {
779             push @{$properties_accessors_mutators}, $cpp_source_subgroup->{H};
780             }
781             if ((exists $cpp_source_subgroup->{PMC}) and (defined $cpp_source_subgroup->{PMC}) and ($cpp_source_subgroup->{PMC} ne q{})) {
782             push @{$properties_accessors_mutators_shims}, $cpp_source_subgroup->{PMC};
783             }
784             }
785             delete $modes->{_inside_class_properties};
786             }
787              
788             # generate accessors & mutators for inherited $properties
789             foreach my $parent_package_name (@{$parent_package_names}) {
790             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $parent_package_name = ' . $parent_package_name . "\n" );
791             # RPerl::diag( 'in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $modes->{_symbol_table}->{ $parent_package_name . q{::} } = ' . Dumper($modes->{_symbol_table}->{ $parent_package_name . q{::} }) . "\n" );
792             foreach my $parent_property_key (keys %{ $modes->{_symbol_table}->{ $parent_package_name . q{::} }->{_properties} }) {
793             if (not exists $modes->{_symbol_table}->{ $package_name_colons . q{::} }->{_properties}->{$parent_property_key}) {
794             $cpp_source_subgroup = ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES( $parent_property_key, $parent_package_name . q{::}, $modes );
795             if ( $cpp_source_subgroup->{H} ne q{} ) {
796             push @{$properties_accessors_mutators}, $cpp_source_subgroup->{H};
797             }
798             if ((exists $cpp_source_subgroup->{PMC}) and (defined $cpp_source_subgroup->{PMC}) and ($cpp_source_subgroup->{PMC} ne q{})) {
799             push @{$properties_accessors_mutators_shims}, $cpp_source_subgroup->{PMC};
800             }
801             }
802             }
803             }
804              
805             if ( exists $properties_declarations->[0] ) {
806             if ( $modes->{label} eq 'ON' ) {
807             $cpp_source_group->{H} .= ' // [[[ OO PROPERTIES ]]]' . "\n";
808             }
809             $cpp_source_group->{H} .= ( join "\n", @{$properties_declarations} ) . "\n\n";
810             }
811              
812             if ( $modes->{label} eq 'ON' ) {
813             $cpp_source_group->{H} .= ' // [[[ OO METHODS ]]]' . "\n\n";
814             }
815              
816             if ( exists $properties_accessors_mutators->[0] ) {
817             if ( $modes->{label} eq 'ON' ) {
818             $cpp_source_group->{H} .= ' // <<< OO PROPERTIES, ACCESSORS & MUTATORS >>>' . "\n";
819             }
820             $cpp_source_group->{H} .= ( join "\n", @{$properties_accessors_mutators} ) . "\n\n";
821             }
822              
823             if ( exists $properties_accessors_mutators_shims->[0] ) {
824             if ( ( not exists $cpp_source_group->{_PMC_accessors_mutators_shims} ) or ( not defined $cpp_source_group->{_PMC_accessors_mutators_shims} ) ) {
825             $cpp_source_group->{_PMC_accessors_mutators_shims} = {};
826             }
827             elsif (( not exists $cpp_source_group->{_PMC_accessors_mutators_shims}->{$package_name_underscores} )
828             or ( not defined $cpp_source_group->{_PMC_accessors_mutators_shims}->{$package_name_underscores} ) )
829             {
830             $cpp_source_group->{_PMC_accessors_mutators_shims}->{$package_name_underscores} = q{};
831             }
832             $cpp_source_group->{_PMC_accessors_mutators_shims}->{$package_name_underscores} .= ( join "\n", @{$properties_accessors_mutators_shims} ) . "\n";
833             }
834              
835             if ( $modes->{label} eq 'ON' ) {
836             $cpp_source_group->{H} .= ' // <<< CONSTRUCTOR & DESTRUCTOR >>>' . "\n";
837             }
838             if ( exists $properties_initializations->[0] ) { # initialize properties in constructor
839             $cpp_source_group->{H} .= q{ } . $package_name_underscores . '() {' . "\n" . ( join "\n", @{$properties_initializations} ) . "\n" . '}' . "\n"; # CONSTRUCTOR
840             }
841             else { # empty constructor
842             $cpp_source_group->{H} .= q{ } . $package_name_underscores . '() {}' . "\n"; # CONSTRUCTOR
843             }
844             $cpp_source_group->{H} .= q{ } . '~' . $package_name_underscores . '() {}' . "\n\n"; # DESTRUCTOR
845              
846             if ( $modes->{label} eq 'ON' ) {
847             $cpp_source_group->{H} .= ' // <<< CLASS NAME REPORTER >>>' . "\n";
848             }
849             my string $package_name_scoped = $package_name_underscores;
850             $package_name_scoped =~ s/__/::/gxms;
851             $cpp_source_group->{H} .= ' virtual string myclassname() { return (const string) "' . $package_name_scoped . '"; }' . "\n"; # CLASS NAME REPORTER
852              
853             # RPerl::diag('in Class::Generator->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $cpp_source_group->{_H_constants_shims}->{$package_name_underscores} = ' . Dumper($cpp_source_group->{_H_constants_shims}->{$package_name_underscores}) . "\n");
854             if ( ( exists $cpp_source_group->{_H_constants_shims} )
855             and ( defined $cpp_source_group->{_H_constants_shims} )
856             and ( exists $cpp_source_group->{_H_constants_shims}->{$package_name_underscores} )
857             and ( defined $cpp_source_group->{_H_constants_shims}->{$package_name_underscores} ) )
858             {
859             $cpp_source_group->{H} .= "\n";
860             if ( $modes->{label} eq 'ON' ) { $cpp_source_group->{H} .= ' // <<< CONSTANTS, SHIMS >>>' . "\n"; }
861             $cpp_source_group->{H} .= $cpp_source_group->{_H_constants_shims}->{$package_name_underscores};
862             }
863              
864             my string_arrayref $method_declarations = [];
865             my string_arrayref $method_definitions = [];
866             my string_arrayref $subroutine_declarations = [];
867             my string_arrayref $subroutine_definitions = [];
868             my string_arrayref $PMC_subroutines_shims = [];
869             my string_arrayref $CPP_subroutines_shims = [];
870              
871             foreach my object $method_or_subroutine ( ## no critic qw(ProhibitPostfixControls) # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
872             @{ $method_or_subroutine_star->{children} }
873             )
874             {
875             if ( ( ref $method_or_subroutine ) eq 'SubroutineOrMethod_77' ) { # METHOD
876             $cpp_source_subgroup = $method_or_subroutine->ast_to_cpp__generate_declaration__CPPOPS_CPPTYPES($modes);
877             push @{$method_declarations}, $cpp_source_subgroup->{H};
878             $cpp_source_subgroup = $method_or_subroutine->ast_to_cpp__generate__CPPOPS_CPPTYPES( $package_name_underscores, $modes );
879             push @{$method_definitions}, $cpp_source_subgroup->{CPP};
880             if ( ( exists $cpp_source_subgroup->{H_INCLUDES} ) and ( defined $cpp_source_subgroup->{H_INCLUDES} ) ) {
881             $cpp_source_group->{H_INCLUDES} .= $cpp_source_subgroup->{H_INCLUDES};
882             }
883             }
884             elsif ( ( ref $method_or_subroutine ) eq 'SubroutineOrMethod_76' ) { # SUBROUTINE
885             $cpp_source_subgroup = $method_or_subroutine->ast_to_cpp__generate_declaration__CPPOPS_CPPTYPES($modes);
886             push @{$subroutine_declarations}, $cpp_source_subgroup->{H};
887             $cpp_source_subgroup = $method_or_subroutine->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
888             push @{$subroutine_definitions}, $cpp_source_subgroup->{CPP};
889             $cpp_source_subgroup = $method_or_subroutine->ast_to_cpp__generate_shims__CPPOPS_CPPTYPES($modes);
890             if ((exists $cpp_source_subgroup->{PMC}) and (defined $cpp_source_subgroup->{PMC})) {
891             push @{$PMC_subroutines_shims}, $cpp_source_subgroup->{PMC};
892             }
893             push @{$CPP_subroutines_shims}, $cpp_source_subgroup->{CPP};
894             if ( ( exists $cpp_source_subgroup->{H_INCLUDES} ) and ( defined $cpp_source_subgroup->{H_INCLUDES} ) ) {
895             $cpp_source_group->{H_INCLUDES} .= $cpp_source_subgroup->{H_INCLUDES};
896             }
897             }
898             else {
899             die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP00, CODE GENERATOR, ABSTRACT SYNTAX TO C++, CPPOPS_CPPTYPES: Grammar rule '
900             . ( ref $method_or_subroutine )
901             . ' found where SubroutineOrMethod_77 or SubroutineOrMethod_76 expected, dying' )
902             . "\n";
903             }
904             }
905              
906             if ( exists $method_declarations->[0] ) {
907             if ( $modes->{label} eq 'ON' ) {
908             $cpp_source_group->{H} .= "\n" . ' // <<< USER-DEFINED METHODS >>>' . "\n";
909             }
910             $cpp_source_group->{H} .= ( join "\n", @{$method_declarations} ) . "\n";
911             }
912              
913             if ( ( exists $method_definitions->[0] ) or ( exists $subroutine_definitions->[0] ) ) {
914             if ( $modes->{label} eq 'ON' ) {
915             $cpp_source_group->{CPP} .= '// [[[ SUBROUTINES & OO METHODS ]]]' . "\n\n";
916             }
917             $cpp_source_group->{CPP} .= ( join "\n\n", @{$method_definitions} );
918             if ( exists $method_definitions->[0] ) { $cpp_source_group->{CPP} .= "\n\n"; }
919             $cpp_source_group->{CPP} .= ( join "\n\n", @{$subroutine_definitions} );
920             if ( exists $subroutine_definitions->[0] ) { $cpp_source_group->{CPP} .= "\n\n"; }
921             if ( exists $PMC_subroutines_shims->[0] ) {
922             if ( ( not exists $cpp_source_group->{_PMC_subroutines_shims} ) or ( not defined $cpp_source_group->{_PMC_subroutines_shims} ) ) {
923             $cpp_source_group->{_PMC_subroutines_shims} = {};
924             }
925             elsif (( not exists $cpp_source_group->{_PMC_subroutines_shims}->{$package_name_underscores} )
926             or ( not defined $cpp_source_group->{_PMC_subroutines_shims}->{$package_name_underscores} ) )
927             {
928             $cpp_source_group->{_PMC_subroutines_shims}->{$package_name_underscores} = q{};
929             }
930             $cpp_source_group->{_PMC_subroutines_shims}->{$package_name_underscores} .= ( join "\n", @{$PMC_subroutines_shims} ) . "\n";
931             }
932             }
933              
934             $cpp_source_group->{H} .= '}; // end of class' . "\n\n";
935              
936             if ( $modes->{label} eq 'ON' ) {
937             $cpp_source_group->{H} .= '// [[[ OO SUBCLASSES ]]]' . "\n";
938             }
939             $cpp_source_group->{H} .= '#define ' . $package_name_underscores . '_rawptr ' . $package_name_underscores . '*' . "\n";
940             $cpp_source_group->{H} .= 'typedef std::unique_ptr<' . $package_name_underscores . '> ' . $package_name_underscores . '_ptr;' . "\n";
941             $cpp_source_group->{H} .= 'typedef std::vector<' . $package_name_underscores . '_ptr> ' . $package_name_underscores . '_arrayref;' . "\n";
942             $cpp_source_group->{H} .= 'typedef std::unordered_map<string, ' . $package_name_underscores . '_ptr> ' . $package_name_underscores . '_hashref;' . "\n";
943             $cpp_source_group->{H}
944             .= 'typedef std::unordered_map<string, ' . $package_name_underscores . '_ptr>::iterator ' . $package_name_underscores . '_hashref_iterator;' . "\n\n";
945              
946             if ( exists $subroutine_declarations->[0] ) {
947             if ( $modes->{label} eq 'ON' ) {
948             $cpp_source_group->{H} .= '// [[[ SUBROUTINES ]]]' . "\n";
949             }
950             $cpp_source_group->{H} .= ( join "\n", @{$subroutine_declarations} ) . "\n\n";
951             if ( $modes->{label} eq 'ON' ) {
952             $cpp_source_group->{H} .= '// <<< SHIM MACROS >>>' . "\n";
953             }
954             $cpp_source_group->{H} .= ( join "\n", @{$CPP_subroutines_shims} ) . "\n\n";
955             }
956              
957             if ( $modes->{label} eq 'ON' ) {
958             $cpp_source_group->{H} .= '// <<< OPERATIONS & DATA TYPES REPORTER >>>' . "\n";
959             }
960             $cpp_source_group->{H} .= 'integer ' . $package_name_underscores . '__MODE_ID() { return 2; } // CPPOPS_CPPTYPES is 2' . "\n\n";
961              
962             if ( $modes->{label} eq 'ON' ) {
963             $cpp_source_tmp = ( ( '// [[[<<< END CPP TYPES >>>]]]' . "\n" ) x 3 ) . "\n";
964             $cpp_source_group->{H} .= $cpp_source_tmp;
965             $cpp_source_group->{CPP} .= $cpp_source_tmp;
966             }
967              
968             $cpp_source_tmp = <<EOL;
969             # else
970              
971             Purposefully_die_from_a_compile-time_error,_due_to_neither___PERL__TYPES_nor___CPP__TYPES_being_defined.__We_need_to_define_only___CPP__TYPES_in_this_file!
972              
973             # endif
974              
975             EOL
976              
977             $cpp_source_group->{H} .= $cpp_source_tmp;
978             $cpp_source_group->{CPP} .= $cpp_source_tmp;
979              
980             # deferred, prepend possibly-updated H_INCLUDES to H, discarding duplicates
981             my string $H_INCLUDES_UNIQUE = '';
982             foreach my string $H_INCLUDE ( split /\n/, $cpp_source_group->{H_INCLUDES} ) {
983             if ( $H_INCLUDES_UNIQUE !~ /$H_INCLUDE/ ) {
984             $H_INCLUDES_UNIQUE .= $H_INCLUDE . "\n";
985             }
986             }
987             $cpp_source_group->{H} = $H_INCLUDES_UNIQUE . $cpp_source_group->{H};
988             delete $cpp_source_group->{H_INCLUDES};
989              
990             return $cpp_source_group;
991             };
992              
993             # generate accessors/mutators
994             our string_hashref $ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES = sub {
995             ( my string $property_key, my string $namespace_from, my string_hashref $modes ) = @ARG;
996             my string_hashref $cpp_source_group = { H => q{} };
997              
998             # RPerl::diag( "\n" . 'in Class::Generator::ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES(), received $modes = ' . "\n" . Dumper($modes) . "\n" );
999              
1000             # grab RPerl-style type out of symtab, instead of accepting-as-arg now-C++-style type from $property_type in caller
1001             # my string $property_type = $modes->{_symbol_table}->{ $modes->{_symbol_table}->{_namespace} }->{_properties}->{$property_key}->{type};
1002             my string $property_type = $modes->{_symbol_table}->{ $namespace_from }->{_properties}->{$property_key}->{type};
1003             my boolean $is_direct = 0;
1004             my $property_element_or_value_type;
1005              
1006             # array element accessors/mutators
1007             if ( $property_type =~ /_arrayref$/ ) {
1008             $property_element_or_value_type = substr $property_type, 0, ( ( length $property_type ) - 9 ); # strip trailing '_arrayref'
1009             if ( exists $rperlnamespaces_generated::RPERL->{ $property_element_or_value_type . '::' } ) {
1010              
1011             # arrayref of RPerl data types
1012             if ( ( $property_element_or_value_type eq 'object' ) or ( $property_element_or_value_type eq 'hashref' ) ) {
1013              
1014             # arrayref of objects or hashrefs (same as Perl object which is a blessed hashref), set address, return void
1015             $is_direct = 0;
1016             }
1017             elsif ( $property_element_or_value_type eq 'arrayref' ) {
1018              
1019             # arrayref of arrayrefs, set address, return void
1020             $is_direct = 0;
1021             }
1022             else {
1023             # arrayref of scalars, return value
1024             $is_direct = 1;
1025             }
1026             }
1027             else {
1028             # arrayref of user-defined data types (objects), set address, return void
1029             $is_direct = 0;
1030             }
1031             }
1032              
1033             # hash value accessors/mutators
1034             elsif ( $property_type =~ /_hashref$/ ) {
1035             $property_element_or_value_type = substr $property_type, 0, ( ( length $property_type ) - 8 ); # strip trailing '_hashref'
1036             if ( exists $rperlnamespaces_generated::RPERL->{ $property_element_or_value_type . '::' } ) {
1037              
1038             # hashref of RPerl data types
1039             if ( ( $property_element_or_value_type eq 'object' ) or ( $property_element_or_value_type eq 'hashref' ) ) {
1040              
1041             # hashref of objects or hashrefs (same as Perl object which is a blessed hashref), set address, return void
1042             $is_direct = 0;
1043             }
1044             elsif ( $property_element_or_value_type eq 'arrayref' ) {
1045              
1046             # hashref of arrayrefs, set address, return void
1047             $is_direct = 0;
1048             }
1049             else {
1050             # hashref of scalars, return value
1051             $is_direct = 1;
1052             }
1053             }
1054             else {
1055             # hashref of user-defined data types (objects), set address, return void
1056             $is_direct = 0;
1057             }
1058             }
1059              
1060             # scalar accessors/mutators, return value
1061             else {
1062             $is_direct = 1;
1063             }
1064              
1065             if ($is_direct) {
1066             $cpp_source_group->{H} = $property_type . ' get_' . $property_key . '() { return this->' . $property_key . '; }' . "\n";
1067             $cpp_source_group->{H}
1068             .= 'void set_' . $property_key . '(' . $property_type . q{ } . $property_key . '_new) { this->' . $property_key . ' = ' . $property_key . '_new; }';
1069             }
1070             else {
1071             # HARD-CODED EXAMPLE:
1072             #integer get_bodies_size() { return this->bodies.size(); } // call from Perl or C++
1073             #string_arrayref get_bodies_keys() { string_arrayref keys; keys.reserve(this->keys.size()); for(auto hash_entry : this->bodies) { keys.push_back(hash_entry.first); } } // call from Perl or C++
1074             #PhysicsPerl__Astro__Body_ptr& get_bodies_element(integer i) { return this->bodies[i]; } // call from C++
1075             #void get_bodies_element_indirect(integer i, PhysicsPerl__Astro__Body_rawptr bodies_element_rawptr) { *bodies_element_rawptr = *(this->bodies[i].get_raw()); } // call from Perl shim
1076             #void set_bodies_element(integer i, PhysicsPerl__Astro__Body_ptr& bodies_element_ptr) { *(this->bodies[i].get_raw()) = *(bodies_element_ptr.get_raw()); } // call from C++
1077             #void set_bodies_element(integer i, PhysicsPerl__Astro__Body_rawptr bodies_element_rawptr) { *(this->bodies[i].get_raw()) = *bodies_element_rawptr; } // call from Perl
1078             #sub get_bodies_element {
1079             # ( my PhysicsPerl::Astro::System $self, my integer $i ) = @ARG;
1080             # my PhysicsPerl::Astro::Body $bodies_element = PhysicsPerl::Astro::Body->new();
1081             # $self->get_bodies_element_indirect($i, $bodies_element);
1082             # return $bodies_element;
1083             #}
1084              
1085             my string $property_element_or_value_type_cpp_nopointerify = RPerl::Generator::type_convert_perl_to_cpp( $property_element_or_value_type, 0 ); # $pointerify_classes = 0
1086              
1087             # C++ code
1088             if ( $property_type =~ /_arrayref$/ ) {
1089             $cpp_source_group->{H} = 'integer get_' . $property_key . '_size() { return this->' . $property_key . '.size(); } // call from Perl or C++' . "\n";
1090             }
1091             elsif ( $property_type =~ /_hashref$/ ) {
1092             $cpp_source_group->{H}
1093             = 'string_arrayref get_'
1094             . $property_key
1095             . '_keys() { string_arrayref keys; keys.reserve(this->'
1096             . $property_key
1097             . '.size()); for(auto hash_entry : this->'
1098             . $property_key
1099             . ') { keys.push_back(hash_entry.first); } } // call from Perl or C++' . "\n";
1100             }
1101             $cpp_source_group->{H}
1102             .= $property_element_or_value_type_cpp_nopointerify
1103             . '_ptr& get_'
1104             . $property_key
1105             . '_element(integer i) { return this->'
1106             . $property_key
1107             . '[i]; } // call from C++' . "\n";
1108             $cpp_source_group->{H}
1109             .= 'void get_'
1110             . $property_key
1111             . '_element_indirect(integer i, '
1112             . $property_element_or_value_type_cpp_nopointerify
1113             . '_rawptr '
1114             . $property_key
1115             . '_element_rawptr) { *'
1116             . $property_key
1117             . '_element_rawptr = *(this->'
1118             . $property_key
1119             . '[i].get_raw()); } // call from Perl shim' . "\n";
1120             $cpp_source_group->{H}
1121             .= 'void set_'
1122             . $property_key
1123             . '_element(integer i, '
1124             . $property_element_or_value_type_cpp_nopointerify
1125             . '_ptr& '
1126             . $property_key
1127             . '_element_ptr) { *(this->'
1128             . $property_key
1129             . '[i].get_raw()) = *('
1130             . $property_key
1131             . '_element_ptr.get_raw()); } // call from C++' . "\n";
1132             $cpp_source_group->{H}
1133             .= 'void set_'
1134             . $property_key
1135             . '_element(integer i, '
1136             . $property_element_or_value_type_cpp_nopointerify
1137             . '_rawptr '
1138             . $property_key
1139             . '_element_rawptr) { *(this->'
1140             . $property_key
1141             . '[i].get_raw()) = *'
1142             . $property_key
1143             . '_element_rawptr; } // call from Perl';
1144              
1145             # RPerl::diag( "\n" . 'in Class::Generator::ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES(), have $modes->{subcompile} = ' . "\n" . $modes->{subcompile} . "\n" );
1146              
1147             # DEV NOTE: only generate PMC output file in dynamic (default) subcompile mode
1148             if ($modes->{subcompile} eq 'DYNAMIC') {
1149             # RPerl::diag( 'in Class::Generator::ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES(), YES PMC SHIMS' . "\n" );
1150             # Perl shim code
1151             # DEV NOTE: must create return variable object in Perl so it will be memory-managed by Perl,
1152             # and not wrongly destructed or double-destructed by Perl garbage collector and/or C++ memory.h,
1153             # even though Perl object contents will be replaced by C++ memory address, TRICKY!
1154             # HARD-CODED EXAMPLE:
1155             # undef &PhysicsPerl::Astro::System::get_bodies_element;
1156             # *PhysicsPerl::Astro::System::get_bodies_element = sub { ... };
1157              
1158             # $cpp_source_group->{PMC} = 'sub get_' . $property_key . '_element {' . "\n"; # DEV NOTE: use alternate syntax to avoid "subroutine redefined" errors
1159             $cpp_source_group->{PMC} = 'undef &' . $modes->{_symbol_table}->{_namespace} . 'get_' . $property_key . '_element;' . "\n";
1160             $cpp_source_group->{PMC} .= '*' . $modes->{_symbol_table}->{_namespace} . 'get_' . $property_key . '_element = sub {' . "\n";
1161             $cpp_source_group->{PMC}
1162             .= '( my '
1163             . ( substr $modes->{_symbol_table}->{_namespace}, 0, ( ( length $modes->{_symbol_table}->{_namespace} ) - 2 ) )
1164             . ' $self, my integer $i ) = @ARG;' . "\n";
1165             $cpp_source_group->{PMC}
1166             .= 'my ' . $property_element_or_value_type . ' $' . $property_key . '_element = ' . $property_element_or_value_type . '->new();' . "\n";
1167             $cpp_source_group->{PMC} .= '$self->get_' . $property_key . '_element_indirect($i, $' . $property_key . '_element);' . "\n";
1168             $cpp_source_group->{PMC} .= 'return $' . $property_key . '_element;' . "\n";
1169             # $cpp_source_group->{PMC} .= '}'; # DEV NOTE: use alternate syntax to avoid "subroutine redefined" errors
1170             $cpp_source_group->{PMC} .= '};';
1171             }
1172             # else { RPerl::diag( 'in Class::Generator::ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES(), NO PMC SHIMS' . "\n" ); }
1173              
1174             # RPerl::diag( 'in Class::Generator::ast_to_cpp__generate_accessors_mutators__CPPOPS_CPPTYPES(), have $cpp_source_group->{H} = ' . "\n" . $cpp_source_group->{H} . "\n" );
1175             }
1176              
1177             return $cpp_source_group;
1178             };
1179              
1180             1; # end of class
1181