class TestCase::Module::Native::Compiler {
  use Native::Compiler;
  use Native;
  use Native::MethodCall;
  use Stringable;
  use Fn;
  
  static method compile : int () {
    
    # Extra
    {
      my $current_env = Native->get_current_env;
      
      my $current_stack = Native->get_current_stack;
      
      my $current_runtime = $current_env->runtime;
    }
    
    my $current_compiler = Native->get_current_compiler;
    
    my $include_dir = "t/test_add_class/SPVM";
    
    $current_compiler->prepend_include_dir($include_dir);
    
    $current_compiler->set_start_file(__FILE__);
    
    {
      my $basic_type_name = "MyPoint";
      $current_compiler->set_start_line(__LINE__ + 1);
      $current_compiler->compile($basic_type_name);
    }
    
    {
      my $class_method_call = Native::MethodCall->new_class_method("MyPoint", "new");
      
      {
        my $stringable = (Stringable)$class_method_call->call([(object)1, 2]);
        
        unless ($stringable->to_string eq "(1,2)") {
          return 0;
        }
      }
    }
    
    {
      eval { Native::MethodCall->new_class_method("MyPoint", "not_exists"); }
      
      Fn->contains($@, "he \"not_exists\" method in the \"MyPoint\" class cannot be found.");
      
      $@ = undef;
    }
    
    {
      my $basic_type_name = "NotExist::XXXXXXXXXXXXXXXXXXXXXXXXX";
      $current_compiler->set_start_line(__LINE__ + 1);
      eval { $current_compiler->compile($basic_type_name); }
      
      unless (Fn->contains($@, "[Compile Error]")) {
        return 0;
      }
      
      unless (Fn->contains($@, "NotExist::XXXXXXXXXXXXXXXXXXXXXXXXX")) {
        return 0;
      }
    }
    
    $@ = undef;
    
    return 1;
  }
  
  static method compile_anon_class : int () {
    
    {
      my $compiler = Native->get_current_compiler;
      
      my $source = <<'EOS';
class {
  static method sum : int ($num1 : int, $num2 : int) {
    return $num1 + $num2;
  }
}
EOS
      $compiler->set_start_file(__FILE__);
      $compiler->set_start_line(__LINE__ + 1);
      my $anon_class_name = (string)undef;
      
      $anon_class_name = $compiler->compile_anon_class($source);
      
      my $ret = Native::MethodCall->call_class_method($anon_class_name, "sum", [(object)1, 2]);
      
      unless ($ret->(Int)->value == 3) {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method eval_string : int () {
    
    {
      my $compiler = Native->get_current_compiler;
      
      my $main_source = <<'EOS';
my $total = 1 + 2;
warn "[Test Output]$total";
EOS
      $compiler->set_start_file(__FILE__);
      $compiler->set_start_line(__LINE__ + 1);
      my $anon_class_name = (string)undef;
      
      $compiler->eval_string($main_source);
      
    }
    
    {
      my $compiler = Native->get_current_compiler;
      
      my $main_source = <<'EOS';
my $total = 1 + 2 foo
warn "[Test Output]$total";
EOS
      $compiler->set_start_file(__FILE__);
      $compiler->set_start_line(__LINE__ + 1);
      my $anon_class_name = (string)undef;
      
      eval { $compiler->eval_string($main_source); }
      
      unless (Fn->contains($@, "[Compile Error]")) {
        return 0;
      }
      
      unless (Fn->contains($@, "1:")) {
        return 0;
      }
    }
    
    $@ = undef;
    
    return 1;
  }
}