#!/usr/bin/perl
# [[[ HEADER ]]]
use strict;
use warnings;
use RPerl::AfterSubclass;

# DEV NOTE, CORRELATION #rp16: RPerl's underscore-is-comma (not CPAN's underscore-is-beta) numbering scheme utilized here
our $VERSION = 1.100_000;    # CODENAME JUPITER

#our $VERSION = 20150905;    # NON-RELEASE VERSION NUMBER, OFFICIAL LONGDATE
#our $VERSION = 2015.248;    # NON-RELEASE VERSION NUMBER, OFFICIAL STARDATE

# [[[ CRITICS ]]]
## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
## no critic qw(ProhibitExplicitStdin)  # USER DEFAULT 4: allow <STDIN>
## no critic qw(RequireInterpolationOfMetachars)  # USER DEFAULT 2: allow single-quoted control characters & sigils
## no critic qw(ProhibitBooleanGrep)  # SYSTEM SPECIAL 1: allow grep
## no critic qw(RequireCarping)  # SYSTEM SPECIAL 13: allow die instead of croak

# [[[ INCLUDES ]]]
use RPerl::Parser;    # includes Perl::Critic
use RPerl::Generator;
use RPerl::Compiler;    # includes Inline
use Getopt::Long qw(:config no_ignore_case);
use Pod::Usage;

# [[[ SUBROUTINES ]]]

# NEED UPGRADE: this array must be instantiated here, because GetOptions'
# diamond '<>' operator does not allow passing arguments or receiving return values
my string_arrayref $input_file_names_unlabeled = [];

# [[[ ACCEPT, CHECK, REPORT OPTIONS (COMMAND-LINE ARGUMENTS) ]]]
# [[[ ACCEPT, CHECK, REPORT OPTIONS (COMMAND-LINE ARGUMENTS) ]]]
# [[[ ACCEPT, CHECK, REPORT OPTIONS (COMMAND-LINE ARGUMENTS) ]]]

sub accept_and_verify_input_files {
    ( my string_arrayref $input_file_names, my string_arrayref $input_file_names_unlabeled ) = @_;

    #    RPerl::diag( 'in rperl::accept_and_verify_input_files(), received $input_file_names = ' . Dumper($input_file_names) . "\n" );
    #    RPerl::diag( 'in rperl::accept_and_verify_input_files(), received $input_file_names_unlabeled = ' . Dumper($input_file_names_unlabeled) . "\n" );

    RPerl::diag("\n\n");    # move output away from initial Inline compiler output
    RPerl::diag( 'in rperl, have $RPerl::DEBUG = ' . $RPerl::DEBUG . "\n" );
    RPerl::diag( 'in rperl, have $RPerl::VERBOSE = ' . $RPerl::VERBOSE . "\n" );

    # accept unlabeled input file name(s) if no labeled values specified
    if ( ( scalar @{$input_file_names_unlabeled} ) > 0 ) {
        if ( ( scalar @{$input_file_names} ) == 0 ) {
            $input_file_names = $input_file_names_unlabeled;
        }
        else {
            die "ERROR EARG08: Both labeled & unlabeled RPerl source code input file option(s) specified, dying\n";
        }
    }

    if ( ( scalar @{$input_file_names} ) == 0 ) {
        die "ERROR EARG01: No RPerl source code input file(s) specified, dying\n";
    }

    # verify input file(s)
    my $input_files_count = scalar @{$input_file_names};

    # DEV NOTE: Perl::Critic BUG!  'integer' triggers false positive RequireFinalReturn
    #    for my integer $i ( 0 .. ( $input_files_count - 1 ) ) {
    for my $i ( 0 .. ( $input_files_count - 1 ) ) {
        my string $input_file_name = $input_file_names->[$i];

#    RPerl::diag('in rperl, top of file verifying loop ' . $i . ' of ' . $input_files_count . ", have \$input_file_names->[$i] = '" . $input_file_name . "'\n");

        if ( not( -e $input_file_name ) ) {    ## no critic qw(ProhibitCascadingIfElse)  # SYSTEM DEFAULT 2: allow argument-handling logic
            die "ERROR EARG02: Specified RPerl source code input file '$input_file_name' does not exist, dying\n";
        }
        elsif ( not( -r $input_file_name ) ) {
            die "ERROR EARG03: Specified RPerl source code input file '$input_file_name' is not readable, dying\n";
        }
        elsif ( not( -f $input_file_name ) ) {
            die "ERROR EARG04: Specified RPerl source code input file '$input_file_name' is not a plain file, dying\n";
        }
        elsif ( ( $input_file_name !~ /[.]pm$/xms )
            and ( $input_file_name !~ /[.]pl$/xms ) )
        {
            die
                "ERROR EARG05: Specified RPerl source code input file '$input_file_name' is not a Perl program ending in '.pl' or module ending in '.pm', dying\n";
        }

    }
    return $input_file_names;
}

sub verify_and_default_modes {
    (   my string_hashref $modes,
        my string_hashref $modes_default,
        my arrayref_hashref $modes_supported,
        my integer $dependencies_flag,
        my integer $compile_flag,
        my integer $execute_flag,
        my integer $test_flag
    ) = @_;

    if ( defined $dependencies_flag ) {
        if ($dependencies_flag) {
            $modes->{dependencies} = 'ON';
        }
        else {
            $modes->{dependencies} = 'OFF';
        }
    }

    if ( defined $compile_flag ) {
        if ($compile_flag) {
            $modes->{compile} = 'SUBCOMPILE';
        }
        else {    # --nocompile command-line argument (option) disables SAVE & SUBCOMPILE steps, PARSE & GENERATE remain enabled
            $modes->{compile} = 'GENERATE';
        }
    }

    if ( defined $execute_flag ) {
        if ($execute_flag) {
            $modes->{execute} = 'ON';
        }
        else {
            $modes->{execute} = 'OFF';
        }
    }

    # test mode is PERLOPS_PERLTYPES_GENERATE, do not save files to disk; test mode flag ignored if false
    if ( defined $test_flag ) {
        if ($test_flag) {
            $modes->{ops}     = 'PERL';
            $modes->{types}   = 'PERL';
            $modes->{compile} = 'GENERATE';
        }
    }

    # must put Perl variables into environmental variables for the values to be properly utilized,
    # do not simply overwrite values, check for applicability first

    # DEV NOTE, CORRELATION #rp17: default to off; if either variable is set to true, then do emit messages
    if ($RPerl::DEBUG) {
        $ENV{RPERL_DEBUG} = $RPerl::DEBUG;
    }
    if ($RPerl::VERBOSE) {
        $ENV{RPERL_VERBOSE} = $RPerl::VERBOSE;
    }

    # verify modes
    foreach my string $mode_key ( keys %{$modes} ) {
        if ( not( exists $modes_supported->{$mode_key} ) ) {
            die "ERROR EARG06: Unsupported or invalid mode category '$mode_key' specified, supported categories are ("
                . join( ', ', keys %{$modes_supported} )
                . '), dying' . "\n";
        }
        elsif ( not( grep { $_ eq $modes->{$mode_key} } @{ $modes_supported->{$mode_key} } ) ) {
            die 'ERROR EARG07: Unsupported or invalid mode ' . q{'}
                . $modes->{$mode_key}
                . ' in mode category ' . q{'}
                . $mode_key . q{'}
                . 'specified, supported modes are ('
                . join( ', ', @{ $modes_supported->{$mode_key} } )
                . '), dying' . "\n";
        }
    }

    # initialize empty symbol table, to be populated during GENERATE phase
    $modes->{_symbol_table} = { _namespace => 'main::', _subroutine => q{} };

    # defaults when mode(s) not provided
    foreach my string $mode_default_key ( keys %{$modes_default} ) { ## no critic qw(ProhibitPostfixControls)  # SYSTEM SPECIAL 6: PERL CRITIC FILED ISSUE #639, not postfix foreach or if
        if ( not( exists $modes->{$mode_default_key} ) ) {
            $modes->{$mode_default_key} = $modes_default->{$mode_default_key};
        }
    }

    1;    # DEV NOTE: Perl::Critic BUG!  must have this '1;' to avoid false positive ProhibitPostfixControls & RequireFinalReturn

    return $modes;
}

sub verbose_multi_file_settings {
    ( my string_arrayref $input_file_names, my hashref_arrayref $output_file_name_groups, my integer $input_files_count, my string_hashref $modes ) = @_;
    if ( $input_files_count > 1 ) {
        RPerl::verbose( multi_file_settings( $input_file_names, $output_file_name_groups, $input_files_count, $modes ) );
        RPerl::verbose_pause( "\n" . 'PRESS <ENTER> TO CONTINUE' . "\n" );
    }
    return;
}

sub diag_multi_file_settings {
    ( my string_arrayref $input_file_names, my hashref_arrayref $output_file_name_groups, my integer $input_files_count, my string_hashref $modes ) = @_;
    if ( $input_files_count > 1 ) {
        RPerl::diag( multi_file_settings( $input_file_names, $output_file_name_groups, $input_files_count, $modes ) );
        RPerl::diag_pause( "\n" . 'PRESS <ENTER> TO CONTINUE' . "\n" );
    }
    return;
}

sub multi_file_settings {
    ( my string_arrayref $input_file_names, my hashref_arrayref $output_file_name_groups, my integer $input_files_count, my string_hashref $modes ) = @_;
    my string $retval = q{};

    $retval .= 'Input File(s):' . "\n";
    foreach my string $input_file_name ( @{$input_file_names} ) {
        $retval .= q{    } . $input_file_name . "\n";
    }
    $retval .= 'Output File(s):' . "\n";
    foreach my string_hashref $output_file_name_group ( @{$output_file_name_groups} ) {
        $retval .= q{    } . stringify_output_file_name_group($output_file_name_group) . "\n";
    }
    $retval .= 'Modes:' . "\n";
    foreach my string $mode_key ( keys %{$modes} ) {
        $retval .= q{    } . $mode_key . ' => ' . $modes->{$mode_key} . "\n";
    }
    return $retval;
}

# allow omission of "-infile" on command line
#our void $store_unlabeled_options = sub {  # NEED FIX: can't define RPerl-style subroutines here?
sub store_unlabeled_options {
    ( my unknown $option ) = @_;
    push @{$input_file_names_unlabeled}, $option;
    return;
}

# print value of option flags
sub verbose_flags {
    ( my integer $dependencies_flag, my integer $compile_flag, my integer $execute_flag, my integer $test_flag ) = @_;
    RPerl::verbose( 'Verbose Flag:       ' . $RPerl::VERBOSE . "\n" );
    RPerl::verbose( 'Debug Flag:         ' . $RPerl::DEBUG . "\n" );
    if ( defined $dependencies_flag ) {
        RPerl::verbose( 'Dependencies Flag:  ' . $dependencies_flag . "\n" );
    }
    if ( defined $compile_flag ) {
        RPerl::verbose( 'Compile Flag:       ' . $compile_flag . "\n" );
    }
    if ( defined $execute_flag ) {
        RPerl::verbose( 'Execute Flag:       ' . $execute_flag . "\n" );
    }
    if ( defined $test_flag ) {
        RPerl::verbose( 'Test Flag:          ' . $test_flag . "\n" );
    }
}

sub stringify_output_file_name_group {
    ( my string_hashref $output_file_name_group) = @_;
    my string $output_file_names = q{};
    foreach my string $suffix_key (qw(EXE PMC CPP H)) {
        if ( exists $output_file_name_group->{$suffix_key} ) {
            $output_file_names .= $output_file_name_group->{$suffix_key} . q{  };
        }
    }
    return $output_file_names;
}

# [[[ CALL COMPILER ]]]
# [[[ CALL COMPILER ]]]
# [[[ CALL COMPILER ]]]

sub depends_parse_generate_save_subcompile_execute {
    (   my string_arrayref $input_file_names,
        my hashref_arrayref $output_file_name_groups,
        my string_arrayref $output_file_name_prefixes,
        my integer $input_files_count,
        my string_hashref $modes
    ) = @_;

    if ( $modes->{ops} eq 'PERL' ) {

        # PERL ops does not actually SUBCOMPILE, set compile mode to SAVE instead
        if ( $modes->{compile} eq 'SUBCOMPILE' ) {
            $modes->{compile} = 'SAVE';
        }

        # PERL ops does not have CPP types, set types mode to PERL instead
        if ( $modes->{types} eq 'CPP' ) { $modes->{types} = 'PERL'; }
    }

    # only execute single *.pl program files, executing multiple files may cause unexpected behavior
    if ( $input_files_count > 1 ) {
        $modes->{execute} = 'OFF';
    }

    # [[[ OUTER COMPILE LOOP, USER-SPECIFIED INPUT FILES ]]]
    # NEED FIX: Perl::Critic BUG!  'integer' triggers false positive RequireFinalReturn
    #    for my integer $i ( 0 .. ( $input_files_count - 1 ) ) {
    for my $i ( 0 .. ( $input_files_count - 1 ) ) {
        my string $input_file_name                = $input_file_names->[$i];
        my string_hashref $output_file_name_group = $output_file_name_groups->[$i];

        # clear symtab before each input file, use automatic dependencies mode (enabled by default) to compile multiple files within a single symtab
        $modes->{_symbol_table} = {};

        # only execute *.pl program files, executing *.pm module files causes useless additional subcompile to occur
        if ( ( $modes->{execute} eq 'ON' ) and ( $input_file_name !~ /[.]pl$/xms ) ) {
            $modes->{execute} = 'OFF';
        }

        if ( $input_files_count > 1 ) {
            RPerl::verbose_clear_screen();
            RPerl::verbose( 'Input File Number:  ' . ( $i + 1 ) . ' of ' . $input_files_count . "\n" );
        }

        RPerl::verbose( 'Input File:         ' . $input_file_name . "\n" );
        RPerl::verbose( 'Output File(s):     ' . stringify_output_file_name_group($output_file_name_group) . "\n" );
        RPerl::verbose( 'Modes:              ops => '
                . $modes->{ops}
                . ', types => '
                . $modes->{types}
                . ', check => '
                . $modes->{check}
                . ', compile => '
                . $modes->{compile}
                . ', execute => '
                . $modes->{execute}
                . ', label => '
                . $modes->{label}
                . "\n\n" );

        my string_arrayref $input_file_name_deps = [$input_file_name];
        my integer $input_file_and_deps_count;
        my integer $input_file_deps_count                = 0;
        my hashref_arrayref $output_file_name_dep_groups = [$output_file_name_group];
        my hashref_arrayref $source_dep_groups           = [];

        if ( $modes->{dependencies} eq 'ON' ) {
            $input_file_name_deps = find_dependencies($input_file_name);
            RPerl::verbose('DEPENDENCIES:       Follow & find all deps... ');
            if ( exists $input_file_name_deps->[0] ) {
                $input_file_name_deps = accept_and_verify_input_files( $input_file_name_deps, [] );    # verify deps input files
            }
            $input_file_name_deps      = [ @{$input_file_name_deps}, $input_file_name ];               # append input file to deps list
            $input_file_and_deps_count = scalar @{$input_file_name_deps};
            $input_file_deps_count     = $input_file_and_deps_count - 1;
            $output_file_name_dep_groups
                = generate_output_file_names( $input_file_name_deps, $output_file_name_prefixes, $input_file_and_deps_count, $modes ); # generate deps output file names
            RPerl::verbose( sprintf( "%4d", $input_file_deps_count ) . ' found.' . "\n" );
            diag_multi_file_settings( $input_file_name_deps, $output_file_name_dep_groups, $input_file_and_deps_count, $modes );
        }

        if (( $input_file_deps_count > 0 ) and ($modes->{compile} ne 'PARSE')){
            $modes->{_compile_saved} = $modes->{compile};
            $modes->{compile}        = 'GENERATE';
        }

        # [[[ FIRST INNER COMPILE LOOP, 1 INPUT FILE & ITS DEPENDENCIES, DEFER SAVE & SUBCOMPILE IF DEPENDENCIES EXIST ]]]
        for my $j ( 0 .. $input_file_deps_count ) {
            my string $input_file_name_dep                = $input_file_name_deps->[$j];
            my string_hashref $output_file_name_dep_group = $output_file_name_dep_groups->[$j];

            if ( $input_file_deps_count > 0 ) {
                if ( $j < $input_file_deps_count ) {
                    RPerl::verbose( "\n" . 'Dep Input File:     ' . $input_file_name_dep . "\n" );
                }
                else {
                    RPerl::verbose( "\n" . 'Input File:         ' . $input_file_name_dep . "\n" );
                }
            }

            if ( $modes->{ops} eq 'PERL' ) {
                $source_dep_groups->[$j] = RPerl::Compiler::rperl_to_rperl__parse_generate( $input_file_name_dep, $output_file_name_dep_group, {}, $modes );
            }
            elsif ( $modes->{ops} eq 'CPP' ) {

                # use eval to trap C++ compiler errors
                my integer $eval_retval = eval {
                    $source_dep_groups->[$j]
                        = RPerl::Compiler::rperl_to_xsbinary__parse_generate_compile( $input_file_name_dep, $output_file_name_dep_group, {}, $modes ); # returns void
                    1;    # return true
                };
                if ( not defined $eval_retval ) {
                    print $EVAL_ERROR;

                    # force-disable execution if an error is trapped in eval() above
                    $modes->{execute} = 'OFF';
                }
            }
        }

        if (    ( $input_file_deps_count > 0 ) and ($modes->{compile} ne 'PARSE')
            and ( ( $modes->{_compile_saved} eq 'SAVE' ) or ( $modes->{_compile_saved} = 'SUBCOMPILE' ) ) )
        {
            RPerl::verbose( "\n" . 'DEPENDENCIES:       Complete deferred actions...' . "\n" );
            $modes->{compile} = $modes->{_compile_saved} . '_DEFERRED';

            # [[[ SECOND INNER COMPILE LOOP, 1 INPUT FILE & ITS DEPENDENCIES, DEFERRED SAVE & SUBCOMPILE ]]]
            for my $j ( 0 .. $input_file_deps_count ) {
                my string $input_file_name_dep                = $input_file_name_deps->[$j];
                my string_hashref $output_file_name_dep_group = $output_file_name_dep_groups->[$j];
                my string_hashref $source_dep_group           = $source_dep_groups->[$j];

                if ( $j < $input_file_deps_count ) {
                    RPerl::verbose( "\n" . 'Dep Output File(s): ' . stringify_output_file_name_group($output_file_name_dep_group) . "\n" );
                }
                else {
                    RPerl::verbose( "\n" . 'Output File(s):     ' . stringify_output_file_name_group($output_file_name_dep_group) . "\n" );
                }

                if ( $modes->{ops} eq 'PERL' ) {
                    RPerl::Compiler::rperl_to_rperl__parse_generate( $input_file_name_dep, $output_file_name_dep_group, $source_dep_group, $modes );
                }
                elsif ( $modes->{ops} eq 'CPP' ) {

#                RPerl::diag( 'in depends_parse_generate_save_subcompile_execute(), have $modes->{_symbol_table} = ' . "\n" . Dumper($modes->{_symbol_table}) . "\n" );

                    # use eval to trap C++ compiler errors
                    my integer $eval_retval = eval {
                        RPerl::Compiler::rperl_to_xsbinary__parse_generate_compile( $input_file_name_dep, $output_file_name_dep_group, $source_dep_group,
                            $modes );    # returns void
                        1;               # return true
                    };
                    if ( not defined $eval_retval ) {
                        print $EVAL_ERROR;

                        # force-disable execution if an error is trapped in eval() above
                        $modes->{execute} = 'OFF';
                    }
                }
            }
        }
 
        if ( $modes->{execute} eq 'ON' ) {
            RPerl::verbose( 'EXECUTE:       Run code...' . "\n" );
            RPerl::verbose("\n");
            my integer $execute_retval = system( $EXECUTABLE_NAME, $input_file_name );
        }

#        RPerl::diag( 'in depends_parse_generate_save_subcompile_execute(), have $modes->{_symbol_table} = ' . "\n" . Dumper($modes->{_symbol_table}) . "\n" );

        if (    ( $input_files_count > 1 )
            and ( $i < ( $input_files_count - 1 ) ) )
        {
            RPerl::verbose_pause("\nPRESS <ENTER> TO CONTINUE\n");
        }
    }
    return;
}

# [[[ OPERATIONS ]]]

# [[[ ACTUALLY RUN CODE ]]]
# [[[ ACTUALLY RUN CODE ]]]
# [[[ ACTUALLY RUN CODE ]]]

my integer $help                              = 0;
my integer $version                           = 0;
my integer $dependencies_flag                 = undef;
my integer $compile_flag                      = undef;
my integer $execute_flag                      = undef;
my integer $test_flag                         = undef;
my string_arrayref $input_file_names          = [];
my string_arrayref $output_file_name_prefixes = [];
my hashref_arrayref $output_file_name_groups  = [];
my string_hashref $modes                      = {};      # can't store defaults here, erased by GetOptions()
my string_hashref $modes_default              = {        # default to CPPOPS_CPPTYPES_CHECKTRACE_SUBCOMPILE_EXECUTE_LABEL in C++ output code
    dependencies => 'ON',
    ops          => 'CPP',
    types        => 'CPP',
    check        => 'TRACE',
    compile      => 'SUBCOMPILE',
    execute      => 'ON',
    label        => 'ON'
};
my arrayref_hashref $modes_supported = {
    dependencies => [ 'OFF',   'ON' ],
    ops          => [ 'PERL',  'CPP' ],
    types        => [ 'PERL',  'CPP', 'DUAL' ],
    check        => [ 'OFF',   'ON', 'TRACE' ],
    compile      => [ 'PARSE', 'GENERATE', 'SAVE', 'SUBCOMPILE' ],
    execute      => [ 'OFF',   'ON' ],
    label        => [ 'OFF',   'ON' ]
};
my integer $input_files_count = 0;

GetOptions(
    'help|?'        => \$help,
    'version'       => \$version,
    'dependencies!' => \$dependencies_flag,
    'Verbose!'      => \$RPerl::VERBOSE,
    'Debug!'        => \$RPerl::DEBUG,
    'compile!'      => \$compile_flag,
    'execute!'      => \$execute_flag,
    'test'          => \$test_flag,
    'infile=s{1,}'  => \@{$input_file_names},
    'outfile=s{1,}' => \@{$output_file_name_prefixes},
    'mode=s%'       => \$modes,
    '<>'            => \&store_unlabeled_options
) or die "ERROR EARG00: Failure processing command line arguments, dying\n";

if ($help) { pod2usage( -verbose => 1 ); exit; }
if ($version) {

    # NEED UPDATE: automatically generate version info

    # DEV NOTE, CORRELATION #rp16: numbering schemes mentioned below
    my $version_message = <<EOL;

This is RPerl version 1.100_000, Long Date 20150905, Star Date 2015.248
v1.100_000 using RPerl's underscore-is-comma numbering scheme
v1.100000  using  CPAN's underscore-is-beta  numbering scheme

Copyright © 2013, 2014, 2015, William N. Braswell, Jr..  All Rights Reserved.
This work is Free & Open Source; you can redistribute it and/or modify it 
under the same terms as Perl 5.22.0.

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
For licensing details, please see http://dev.perl.org/licenses/

Complete documentation for RPerl, including FAQ lists, should be found on 
the Internet, point your browser at http://www.rperl.org/, the RPerl Home Page.

EOL
    print $version_message;
    exit;
}
verbose_flags( $dependencies_flag, $compile_flag, $execute_flag, $test_flag );
$input_file_names        = accept_and_verify_input_files( $input_file_names, $input_file_names_unlabeled );
$input_files_count       = scalar @{$input_file_names};
$modes                   = verify_and_default_modes( $modes, $modes_default, $modes_supported, $dependencies_flag, $compile_flag, $execute_flag, $test_flag );
$output_file_name_groups = generate_output_file_names( $input_file_names, $output_file_name_prefixes, $input_files_count, $modes );
verbose_multi_file_settings( $input_file_names, $output_file_name_groups, $input_files_count, $modes );
depends_parse_generate_save_subcompile_execute( $input_file_names, $output_file_name_groups, $output_file_name_prefixes, $input_files_count, $modes );

__END__
=head1 NAME

rperl Front-End Program

Restricted Perl, The Optimizing Perl 5 Compiler

=head1 SYNOPSIS

        rperl [OPTIONS] input_file_0.(pm|pl) [input_file_1.(pm|pl) ...]

=head1 OPTIONS

=over 8

=item B<--help _OR_ -h _OR_ -?>

 Print a brief help message.

=item B<--version _OR_ -v>

 Print version number and copyright information.
 Lowercase 'v' not to be confused with uppercase 'V' in 'Verbose' option below.
 
=item B<--dependencies _OR_ -d>

=item B<--nodependencies _OR_ -nod>

 Follow and compile dependencies, or not.
 Enabled by default, equivalent to '--mode dependencies=ON' option.
 Lowercase 'd' not to be confused with uppercase 'D' in 'Debug' option below.
 WARNING: Disabling dependencies will likely cause errors or undefined behavior.

=item B<--infile=MyFile.pm _OR_ -i=MyFile.pm>

 Specify input file, may be repeated for multiple input files.
 Option prefix '--infile' may be entirely omitted.
 Option prefix MUST be omitted to specify wildcard for multiple input files.

=item B<--outfile=MyFile _OR_ -o=MyFile>

 Specify output file prefix, may be repeated for multiple output files.
 RPerl *.pm input file with PERL ops will create MyFile.pmc output file.
 RPerl *.pl input file with PERL ops will create my_file (or my_file.exe) & my_file.pmc output files.
 RPerl *.pm input file with CPP ops will create MyFile.pmc, MyFile.cpp, & MyFile.h output files.
 RPerl *.pl input file with CPP ops will create myfile (or myfile.exe on Windows), MyFile.pmc, MyFile.cpp, & MyFile.h output files.
 Option may be entirely omitted, 'MyFile.*' input file will default to 'MyFile.*' out.

=item B<--mode ops=PERL _OR_ -m ops=PERL>

=item B<--mode ops=CPP _OR_ -m ops=CPP>

 Specify operations mode, CPP by default.
 If set to PERL, forces types mode to PERL & compile mode to PARSE or GENERATE; test mode, does not actually compile.

=item B<--mode types=PERL _OR_ -m types=PERL>

=item B<--mode types=CPP _OR_ -m types=CPP>

=item B<--mode types=DUAL _OR_ -m types=DUAL>

 Specify data types mode, CPP by default.
 DUAL mode allows generate-once-compile-many types, selected by '#define __FOO__TYPES' in lib/rperltypes_mode.h file.

=item B<--mode check=OFF _OR_ -m check=OFF>

=item B<--mode check=ON _OR_ -m check=ON>

=item B<--mode check=TRACE _OR_ -m check=TRACE>

 Specify data type checking mode, TRACE by default.

=item B<--mode dependencies=OFF _OR_ -m dependencies=OFF>

=item B<--mode dependencies=ON _OR_ -m dependencies=ON>

 Specify dependencies mode, ON by default.

=item B<--mode compile=PARSE _OR_ -m compile=PARSE>

=item B<--mode compile=GENERATE _OR_ -m compile=GENERATE>

=item B<--mode compile=SUBCOMPILE _OR_ -m compile=SUBCOMPILE>

 Specify compile mode, SUBCOMPILE by default.

=item B<--mode execute=OFF _OR_ -m execute=OFF>

=item B<--mode execute=ON _OR_ -m execute=ON>

 Specify execute mode, ON by default.

=item B<--mode label=OFF _OR_ -m label=OFF>

=item B<--mode label=ON _OR_ -m label=ON>

 Specify source section label mode, ON by default.

=item B<--compile _OR_ -c>

=item B<--nocompile _OR_ -noc>

 Generate & subcompile C++ source code, or not.
 Enabled by default, equivalent to '--mode compile=SUBCOMPILE' option.

=item B<--execute _OR_ -e>

=item B<--noexecute _OR_ -noe>

 Run input code after optional compile, or not.
 Enabled by default for *.pl program input files, always disabled for *.pm module input files or multiple input files.
 Equivalent to '--mode execute=ON' option.

=item B<--Verbose _OR_ -V>

=item B<--noVerbose _OR_ -noV>

 Include additional user information in output, or not.
 Disabled by default, equivalent to `export RPERL_VERBOSE=1` shell command.
 Uppercase 'V' not to be confused with lowercase 'v' in 'version' option above.

=item B<--Debug _OR_ -D>

=item B<--noDebug _OR_ -noD>

 Include system diagnostic information in output, or not.
 Disabled by default, equivalent to `export RPERL_DEBUG=1` shell command.
 Uppercase 'D' not to be confused with lowercase 'd' in 'dependencies' option above.

=item B<--test _OR_ -t>

 Test mode: Perl ops, Perl types, Parse & Generate (no Save or Compile)
 Disabled by default, equivalent to '--mode ops=PERL --mode types=PERL --mode compile=GENERATE' options.
 
=back

=head1 DESCRIPTION

B<RPerl> is a compiler.  For more info:

L<https://github.com/wbraswell/rperl/blob/master/README.md>

=head1 SEE ALSO

L<RPerl>

=head1 AUTHOR

B<William N. Braswell, Jr.>

L<mailto:wbraswell@NOSPAM.cpan.org>

=cut