#!perl

use strict;
use warnings;

use SPVM::Builder::Util;
use SPVM::Global;

SPVM::Builder::Util::getopt
  # spvmcc and spvm shared
  'h|help'          => \my $help,
  'v|version'       => \my $show_version,
  'I|include-dir=s' => \my @include_dirs,
  'B|build-dir=s'   => \my $build_dir,
  
  # spvm only
  'e=s' => \my $program_source,
  '-M=s' => \my @use_class_names,
;

unshift @INC, map { $_ =~ s/[\\\/]SPVM$//; $_; } @include_dirs;

if ($help) {
  print SPVM::Builder::Util::extract_usage;
  exit 0;
}
elsif ($show_version) {
  my $version_string = "spvm v$SPVM::VERSION";
  print "$version_string\n";
  exit 0;
}

if (defined $build_dir) {
  $ENV{SPVM_BUILD_DIR} = $build_dir;
}

my $class_name = shift;

if (!defined $class_name && !defined $program_source) {
  die SPVM::Builder::Util::extract_usage;
}

my $eval_string;
if (defined $program_source) {
  $eval_string = 1;
}

my $script_name;

if (defined $class_name) {
  
  if ($class_name =~ /^[a-z]/ || $class_name =~ /[\/\\]/) {
    $script_name = $class_name;
    $0 = $script_name;
  }
  else {
    warn "[DEPRECATED]spvm <class_name>. Use spvm <script_name> instead.";
    
    SPVM::Global::build_class($class_name, __FILE__, __LINE__);
  }
}

for my $use_class_name (@use_class_names) {
  SPVM::Global::build_class($use_class_name, __FILE__, __LINE__);
}

SPVM::Global::build_class('Native', __FILE__, __LINE__);
SPVM::Global::build_class('Native::MethodCall', __FILE__, __LINE__);

if ($eval_string) {
  $program_source = "
class {
static method main : void () {
#line 1
$program_source
}
}
";
}
elsif (defined $script_name) {
  
  open my $script_fh, '<', $script_name
    or die "Can't open file \"$script_name\":$!";
    
  $program_source = do { local $/; <$script_fh> };
  
  $program_source = "#file \"$script_name\"\x{A}$program_source";
}

if (defined $program_source) {
  
  $class_name = SPVM::Global::build_anon_class($program_source, __FILE__, __LINE__);
}

SPVM::Native->check_bootstrap_method($class_name);

my $spvm_class_name = "SPVM::$class_name";

$spvm_class_name->main;

=encoding utf8

=head1 Name

spvm - Executing SPVM programs

=head1 Description

The spvm command executes SPVM programs.

=head1 Usage

  usage: spvm [<options>] <script name|class name>
    
    spvm my_app.spvm
    
    [DEPRECATED]
    spvm -I lib/SPVM Myapp 
    
  options:
    -h, --help                     Shows this message
    -v, --version                  Shows the version
    -I, --include-dir <directory>  Adds a include directory
    -B, --build-dir <directory>    Build diretory
    -e <source>                    Executes a program source code

=head1 Details

  spvm [<options>] <class name|script_name>

The C<spvm> command executes a SPVM program.

C<E<lt>optionsE<gt>> are L<options|/"Options">.

C<E<lt>script nameE<gt>> is a script name that contains a L<bootstrap method|SPVM::Document::Language::Class/"Bootstrap Method"> in an anon class.
  
  class {
    static method main : void () {
      
    }
  }
  
C<E<lt>class nameE<gt>> is a class name that contains a L<bootstrap method|SPVM::Document::Language::Class/"Bootstrap Method">. This argument is deprecated. 

See L<Class Search Directories|SPVM::Document::Language::Class/"Class Search Directories"> about default class search directories.

See L<SPVM::Document::EnvironmentVariables> about available environment variables.

=head1 Options

=head2 --help

Outputs how to use the C<spvm> command to standard output.

=head2 -h

  -h

Same as L</"--help">.

=head2 --version

Outputs the version of the C<spvm> command to standard output. This version is the same as the version of L<SPVM>.

=head2 -v

  -v

Same as L</"--version">.

=head2 --include-dir

  --include-dir <directory>

Prepends C<E<lt>directoryE<gt>> to L<class search directories|SPVM::Document::Language::Class/"Class Search Directories">

This option can be specified multiple times.

  --include-dir dir1 --include-dir dir2

In this case, class search directories becomes the following.

  [dir1, dir2, default_dirs]

=head2 -I

  -I <directory>

Same as L</"--include-dir">.

=head2 --build-dir

  --build-dir <directory>

Sets L<SPVM_BUILD_DIR|SPVM::Document::EnvironmentVariables/"SPVM_BUILD_DIR"> environment variable to C<E<lt>directoryE<gt>>.

=head2 -B

  -B <directory>

Same as L</"--build-dir">.

=head2 -e

  -e <source>

Executes a program from the source string E<lt>sourceE<gt>.

C<E<lt>sourceE<gt>> is exceuted by L<Native::Compiler#eval_string|SPVM::Native::Compiler/"eval_string">.

Examples:

  spvm -e 'say "Hello World!";';

=head1 Copyright & License

Copyright 2023 Yuki Kimoto. All Rights Reserved.

MIT License.
