#!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;
}

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

if (defined $class_name) {
  SPVM::Global::build_class($class_name, __FILE__, __LINE__);
}

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

if (defined $program_source) {
  my $current_compiler = SPVM::Native->get_current_compiler;
  
  $current_compiler->set_start_file(__FILE__);
  $current_compiler->set_start_line(__LINE__ + 1);
  $current_compiler->eval_string($program_source);
}
else {
  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>] <class name>
    
    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>

The C<spvm> command executes a SPVM program.

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

C<E<lt>class nameE<gt>> is a class name that contains a L<bootstrap method|SPVM::Document::Language::Class/"Bootstrap Method">.

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.
