From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

# [[[ HEADER ]]]
use strict;
our $VERSION = 0.005_000;
# [[[ OO INHERITANCE ]]]
# [[[ CRITICS ]]]
## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
# [[[ OO PROPERTIES ]]]
our hashref $properties = {};
# [[[ SUBROUTINES & OO METHODS ]]]
sub ast_to_rperl__generate {
{ my string_hashref::method $RETURN_TYPE };
( my object $self, my string_hashref $modes) = @ARG;
my string_hashref $rperl_source_group = { PMC => q{} };
my string_hashref $rperl_source_subgroup;
# RPerl::diag( 'in ConstructorCall->ast_to_rperl__generate(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
if ( ( ref $self ) ne 'Expression_154' ) {
die RPerl::Parser::rperl_rule__replace(
'ERROR ECOGEASRP000, CODE GENERATOR, ABSTRACT SYNTAX TO RPERL: Grammar rule '
. ( ref $self )
. ' found where Expression_154 expected, dying' )
. "\n";
}
# Expression -> WordScoped OP02_METHOD_THINARROW_NEW OPTIONAL-36 ')'
my string $type = $self->{children}->[0]->{children}->[0];
my string $thin_arrow_new_left_paren = $self->{children}->[1];
my object $properties_init_optional = $self->{children}->[2];
my string $right_paren = $self->{children}->[3];
$rperl_source_group->{PMC} .= $type . $thin_arrow_new_left_paren;
if ( defined $properties_init_optional->{children}->[0] ) {
$rperl_source_subgroup = $properties_init_optional->{children}->[0]->ast_to_rperl__generate($modes);
RPerl::Generator::source_group_append( $rperl_source_group, $rperl_source_subgroup );
}
$rperl_source_group->{PMC} .= $right_paren;
return $rperl_source_group;
}
sub ast_to_cpp__generate__CPPOPS_PERLTYPES {
{ my string_hashref::method $RETURN_TYPE };
( my object $self, my string_hashref $modes) = @ARG;
my string_hashref $cpp_source_group
= { CPP =>
q{// <<< RP::O::E::SC::MC::CC __DUMMY_SOURCE_CODE CPPOPS_PERLTYPES >>>}
. "\n" };
#...
return $cpp_source_group;
}
sub ast_to_cpp__generate__CPPOPS_CPPTYPES {
{ my string_hashref::method $RETURN_TYPE };
( my object $self, my string_hashref $modes) = @ARG;
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
my string_hashref $cpp_source_group = { CPP => q{} };
my string_hashref $cpp_source_subgroup;
if ( ( ref $self ) ne 'Expression_154' ) {
die RPerl::Parser::rperl_rule__replace(
'ERROR ECOGEASCP000, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule ' . ( ref $self ) . ' found where Expression_154 expected, dying' ) . "\n";
}
# Expression -> WordScoped OP02_METHOD_THINARROW_NEW OPTIONAL-36 ')'
my string $type = $self->{children}->[0]->{children}->[0];
my string $type_cpp = RPerl::Generator::type_convert_perl_to_cpp($type, 0); # $pointerify_classes = 0
my object $properties_init_optional = $self->{children}->[2];
# FROM: MongoDB::MongoClient->new(); # YES SUPPORT, default value
# FROM: MongoDB::MongoClient->new({host => 'mongodb://localhost:27017'}); # YES SUPPORT, host parameter
# FROM: MongoDB::MongoClient->new({host => q{mongodb://localhost:27017}}); # YES SUPPORT, host parameter
# FROM: MongoDB::MongoClient->new({host => 'localhost', port => 27_017}); # NO SUPPORT, parsing of non-host parameters not yet implemented below
# TO: {mongodb_host {"mongodb://localhost:27017"}};
# DEV NOTE, CORRELATION #rp131: constructor call for MongoDB
if ( (substr $type, 0, 7) eq 'MongoDB' ) {
if ((not exists $modes->{_enable_mongodb}) or (not defined $modes->{_enable_mongodb}) or (not $modes->{_enable_mongodb})) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP091b, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Found constructor call for package '
. q{'} . $type . q{'}
. ' but MongoDB support is not enabled, perhaps you forgot to load MongoDB support via `use RPerl::Support::MongoDB;`, dying' )
. "\n";
}
# only MongoClient objects may be directly constructed, see MongoDB::Database & MongoDB::Collection documentation
if ($type ne 'MongoDB::MongoClient') {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP092b, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Found constructor call for package '
. q{'} . $type . q{'}
. ' but only ' . q{'} . 'MongoDB::MongoClient' . q{'} . ' may be directly constructed, please see the MongoDB documentation on CPAN for more information, dying' )
. "\n";
}
my string $mongodb_host;
if ( defined $properties_init_optional->{children}->[0] ) {
# NEED UPGRADE: parse MongoDB parameters other than only 'host' below
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), MongoDB constructor, have $properties_init_optional->{children}->[0] = ' . "\n" . RPerl::Parser::rperl_ast__dump($properties_init_optional->{children}->[0]) . "\n" );
my $properties_init = $properties_init_optional->{children}->[0];
if ((ref $properties_init) ne 'HashReference_232') {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097a, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}) or
(not defined $properties_init->{children}) or
(scalar @{$properties_init->{children}}) != 4) { # the empty _STAR_LIST plus curly braces makes 4 elements instead of 1
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098a, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[2]) or
((ref $properties_init->{children}->[2]) ne '_STAR_LIST')) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097b, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}->[2]->{children}) or
(not defined $properties_init->{children}->[2]->{children}) or
((scalar @{$properties_init->{children}->[2]->{children}}) != 0)) { # the empty _STAR_LST has 0 children elements
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098b, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]) or
((ref $properties_init->{children}->[1]) ne 'HashEntry_225')) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097c, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}->[1]->{children}) or
(not defined $properties_init->{children}->[1]->{children}) or
((scalar @{$properties_init->{children}->[1]->{children}}) != 4)) { # the key name, fat comma/arrow =>, optional inner type, and value make 4
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), MongoDB constructor, have $properties_init->{children}->[1]->{children} = ' . "\n" . RPerl::Parser::rperl_ast__dump($properties_init->{children}->[1]->{children}) . "\n" );
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098c, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]->{children}->[0]) or
((ref $properties_init->{children}->[1]->{children}->[0]) ne 'VarOrLitOrOpStrOrWord_252')) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097d, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}->[1]->{children}->[0]->{children}) or
(not defined $properties_init->{children}->[1]->{children}->[0]->{children}) or
((scalar @{$properties_init->{children}->[1]->{children}->[0]->{children}}) != 1)) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098d, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]->{children}->[0]->{children}->[0]) or
((ref $properties_init->{children}->[1]->{children}->[0]->{children}->[0]) ne 'OpStringOrWord_279')) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097e, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}->[1]->{children}->[0]->{children}->[0]->{children}) or
(not defined $properties_init->{children}->[1]->{children}->[0]->{children}->[0]->{children}) or
((scalar @{$properties_init->{children}->[1]->{children}->[0]->{children}->[0]->{children}}) != 1)) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098e, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]->{children}->[0]->{children}->[0]->{children}->[0]) or
($properties_init->{children}->[1]->{children}->[0]->{children}->[0]->{children}->[0] ne 'host')) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097f, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]->{children}->[3]) or
((ref $properties_init->{children}->[1]->{children}->[3]) ne 'SubExpression_157')) {
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), MongoDB constructor, have $properties_init->{children}->[1]->{children}->[3] = ' . "\n" . RPerl::Parser::rperl_ast__dump($properties_init->{children}->[1]->{children}->[3]) . "\n" );
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097g, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}->[1]->{children}->[3]->{children}) or
(not defined $properties_init->{children}->[1]->{children}->[3]->{children}) or
((scalar @{$properties_init->{children}->[1]->{children}->[3]->{children}}) != 1)) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098g, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]->{children}->[3]->{children}->[0]) or
((ref $properties_init->{children}->[1]->{children}->[3]->{children}->[0]) ne 'Literal_256')) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097h, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not exists $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}) or
(not defined $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}) or
((scalar @{$properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}}) != 1)) {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP098h, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', wrong number of arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
elsif ((not defined $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}->[0]) or
(
((substr $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}->[0], 1, 10) ne q{mongodb://}) and
((substr $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}->[0], 2, 10) ne q{mongodb://})
) ) {
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), MongoDB constructor, have $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}->[0] = ' . "\n" . RPerl::Parser::rperl_ast__dump($properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}->[0]) . "\n" );
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097i, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
$mongodb_host = $properties_init->{children}->[1]->{children}->[3]->{children}->[0]->{children}->[0];
# trim leading & trailing quotation marks
if ((substr $mongodb_host, 0, 1) eq q{'} ) {
substr $mongodb_host, 0, 1, q{};
substr $mongodb_host, -1, 1, q{};
}
elsif ((substr $mongodb_host, 0, 1) eq 'q' ) {
substr $mongodb_host, 0, 2, q{};
substr $mongodb_host, -1, 1, q{};
}
else {
die RPerl::Parser::rperl_rule__replace( 'ERROR ECOGEASCP097j, CODE GENERATOR, ABSTRACT SYNTAX TO C++: In constructor call for package '
. q{'} . $type . q{()'} . ', invalid or no arguments found, must be exactly 1 non-empty hashref, only ' . q{'host'} . ' key with ' . q{'mongodb://HOST:PORT'} . ' value currently supported, dying' ) . "\n";
}
}
# default host & port
else {
$mongodb_host = 'mongodb://localhost:27017';
}
$cpp_source_group->{CPP} .= '{mongodb_host{"' . $mongodb_host . '"}}';
}
# constructor call with properties to initialize
elsif ( defined $properties_init_optional->{children}->[0] ) {
$properties_init_optional = $properties_init_optional->{children}->[0]; # unwrap hashref object
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have unwrapped $properties_init_optional = ' . "\n" . RPerl::Parser::rperl_ast__dump($properties_init_optional) . "\n" );
my object $property_0 = $properties_init_optional->{children}->[1];
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $property_0 = ' . "\n" . RPerl::Parser::rperl_ast__dump($property_0) . "\n" );
if ( ( ref $property_0 ) ne 'HashEntry_225' ) {
die RPerl::Parser::rperl_rule__replace(
'ERROR ECOGEASCP036, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule ' . ( ref $property_0 ) . ' found where HashEntry_225 expected, object property value initialization hashref must contain normal key/value pairs only, dying' ) . "\n";
}
$cpp_source_subgroup = $self->ast_to_cpp__generate__CPPOPS_CPPTYPES__property_init($modes, $property_0);
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $cpp_source_subgroup from $property_0 = ' . "\n" . RPerl::Parser::rperl_ast__dump($cpp_source_subgroup) . "\n" );
# $cpp_source_group->{CPP} .= 'NEW_' . $type_cpp . '{}.' . $cpp_source_subgroup->{CPP_name} . '(' . $cpp_source_subgroup->{CPP_value} . ')'; # this should work except for AStyle bug
$cpp_source_group->{CPP} .= '(NEW_' . $type_cpp . '{}).' . $cpp_source_subgroup->{CPP_name} . '(' . $cpp_source_subgroup->{CPP_value} . ')'; # NEED FIX: extraneous parentheses required due to AStyle bug https://sourceforge.net/p/astyle/bugs/468/
my object $properties = $properties_init_optional->{children}->[2];
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $properties = ' . "\n" . RPerl::Parser::rperl_ast__dump($properties) . "\n" );
if (defined $properties->{children}->[0]) {
foreach my object $property (@{$properties->{children}}) {
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $property = ' . "\n" . RPerl::Parser::rperl_ast__dump($property) . "\n" );
if ((exists $property->{attr}) and (defined $property->{attr}) and ($property->{attr} eq ',')) {
next; # skip commas, they are not properties!
}
$cpp_source_subgroup = $self->ast_to_cpp__generate__CPPOPS_CPPTYPES__property_init($modes, $property);
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES(), have $cpp_source_subgroup from $property = ' . "\n" . RPerl::Parser::rperl_ast__dump($cpp_source_subgroup) . "\n" );
$cpp_source_group->{CPP} .= '.' . $cpp_source_subgroup->{CPP_name} . '(' . $cpp_source_subgroup->{CPP_value} . ')';
}
}
$cpp_source_group->{CPP} .= '.NEW()';
}
# constructor call without properties to initialize
else {
$cpp_source_group->{CPP} .= 'new ' . $type_cpp;
}
return $cpp_source_group;
}
sub ast_to_cpp__generate__CPPOPS_CPPTYPES__property_init {
{ my string_hashref::method $RETURN_TYPE };
( my object $self, my string_hashref $modes, my object $property ) = @ARG;
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES__property_init(), received $self = ' . "\n" . RPerl::Parser::rperl_ast__dump($self) . "\n" );
# RPerl::diag( 'in ConstructorCall->ast_to_cpp__generate__CPPOPS_CPPTYPES__property_init(), received $property = ' . "\n" . RPerl::Parser::rperl_ast__dump($property) . "\n" );
my string_hashref $cpp_source_group = { CPP_name => q{}, CPP_value => q{} };
my string_hashref $cpp_source_subgroup;
my object $property_name = $property->{children}->[0];
my object $property_type_inner_optional = $property->{children}->[2];
my object $property_value = $property->{children}->[3];
if ( ( ref $property_name ) ne 'VarOrLitOrOpStrOrWord_252' ) {
die RPerl::Parser::rperl_rule__replace(
'ERROR ECOGEASCP036, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule ' . ( ref $property_name ) . ' found where VarOrLitOrOpStrOrWord_252 expected, object property value initialization hashref must contain normal key/value pairs only, dying' ) . "\n";
}
$property_name = $property_name->{children}->[0]; # unwrap OpStringOrWord_279 from VarOrLitOrOpStrOrWord_252
if ( ( ref $property_name ) ne 'OpStringOrWord_279' ) {
die RPerl::Parser::rperl_rule__replace(
'ERROR ECOGEASCP037, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Grammar rule ' . ( ref $property_name ) . ' found where OpStringOrWord_279 expected, object property value initialization hashref must contain bareword keys only, dying' ) . "\n";
}
$property_name = $property_name->{children}->[0]; # unwrap bareword from OpStringOrWord_279
if ( exists $property_type_inner_optional->{children}->[0] ) {
die RPerl::Parser::rperl_rule__replace(
'ERROR ECOGEASCP038, CODE GENERATOR, ABSTRACT SYNTAX TO C++: Object property initialization, hashref entry for property name ' . q{'} . $property_name . q{'} . ' has inner type when it should have no inner type, dying' ) . "\n";
}
$cpp_source_group->{CPP_name} = $property_name;
$cpp_source_subgroup = $property_value->ast_to_cpp__generate__CPPOPS_CPPTYPES($modes);
$cpp_source_group->{CPP_value} = $cpp_source_subgroup->{CPP};
return $cpp_source_group;
}
1; # end of class