package TestCase::Assign {
  use TestCase::Minimal;
  use TestCase::Simple;
  use SPVM::Complex_2f;
  use SPVM::Complex_2d;
  use SPVM::Util (INT8_MIN, INT8_MAX, INT16_MIN, INT16_MAX, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX, FLT_MIN, FLT_MAX, DBL_MIN, DBL_MAX);
  
  sub assign_ref : int () {
    my $num = 1;
    my $ref_num1 = \$num;
    my $ref_num2 = $ref_num1;
    
    if ($$ref_num2 == 1) {
      return 1;
    }
    
    return 0;
  }
  
  sub assign_return_value_multi_numeric_type : int () {
    my $z1 : SPVM::Complex_2d;
    $z1->{re} = 1;
    $z1->{im} = 2;
    
    my $z2 : SPVM::Complex_2d;
    my $z3 : SPVM::Complex_2d;
    
    $z3 = $z2 = $z1;
    
    if ($z3->{re} == 1 && $z3->{im} == 2 && $z2->{re} == 1 && $z2->{im} == 2) {
      return 1;
    }
    
    return 0;
  }
  
  sub assign_return_value_value_field : int () {
    my $z : SPVM::Complex_2d;
    $z->{im} = 1;
    my $im1 : double;
    my $im2 : double;
    
    $im1 = $im2 = $z->{im};
    
    if ($im1 == 1 && $im2 == 1) {
      return 1;
    }
    
    return 0;
  }

  sub assign_return_value_ref : int () {
    my $num = 1;
    my $num_ref1 : int&;
    my $num_ref2 : int&;
    
    $num_ref1 = $num_ref2 = \$num;
    
    if ($$num_ref1 == 1 && $$num_ref2 == 1) {
      return 1;
    }
    
    return 0;
  }

  sub assign_return_value_my_var : int () {
    
    if (my $var = 1) {
      return 1;
    }
    
    return 0;
  }

  sub assign_return_value_byte : int () {
    my $v1 : byte;
    my $v2 : byte;
    
    $v2 = $v1 = (byte)INT8_MIN();
    
    if ($v2 == INT8_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_short : int () {
    my $v1 : short;
    my $v2 : short;
    
    $v2 = $v1 = (short)INT16_MIN();
    
    if ($v2 == INT16_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_int : int () {
    my $v1 : int;
    my $v2 : int;
    
    $v2 = $v1 = (int)INT32_MIN();
    
    if ($v2 == INT32_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_long : int () {
    my $v1 : long;
    my $v2 : long;
    
    $v2 = $v1 = (long)INT64_MIN();
    
    if ($v2 == INT64_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_float : int () {
    my $v1 : float;
    my $v2 : float;
    
    $v2 = $v1 = (float)FLT_MIN();
    
    if ($v2 == FLT_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_double : int () {
    my $v1 : double;
    my $v2 : double;
    
    $v2 = $v1 = (double)DBL_MIN();
    
    if ($v2 == DBL_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_var : int () {
      my $v1 : int;
      my $v2 : int;
      my $v3 : int;
      
      $v1 = 1;
      $v3 = $v2 = $v1;
      
      if ($v3 == 1 && $v2 == 1) {
        return 1;
      }
      return 0;
  }
  
  sub assign_return_value_constant : int () {
      my $v1 : int;
      my $v2 : int;
      my $v3 : int;
      
      $v3 = $v2 = 1;
      
      if ($v3 == 1) {
        return 1;
      }
      return 0;
  }

  sub assign_return_value_object : int () {
    my $v1 : TestCase::Minimal;
    my $v2 : TestCase::Minimal;
    
    $v2 = $v1 = TestCase::Minimal->new;;
    
    if ($v2 isa TestCase::Minimal) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_array_access_right_var : int () {
    my $nums = new int[1];
    
    my $var1 = 1;
    my $var2 = $nums->[0] = $var1;
    
    if ($var2 == 1) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_array_access_right_not_var : int () {
    my $nums = new int[1];
    
    my $var2 = $nums->[0] = 1;
    
    if ($var2 == 1) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_array_access_left_var : int () {
    my $nums = new int[1];
    
    my $var1 : int;
    $nums->[0] = 1;
    my $var2 = $var1 = $nums->[0];
    
    if ($var2 == 1 && $var1 == 1) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_array_access_chain : int () {
    my $nums = new int[2];
    
    my $var2 = $nums->[0] = $nums->[1] = 1;
    
    if ($var2 == 1 && $nums->[0] == 1 && $nums->[1] == 1) {
      return 1;
    }
    return 0;
  }

  sub assign_return_value_field_access : int () {
    my $v2 : int;
    
    my $minimal = TestCase::Minimal->new;
    $v2 = $minimal->{x} = 1;
    
    if ($v2 == 1) {
      return 1;
    }
    return 0;
  }

  sub assign : int () {
    # Constant assignment
    my $success_constant_narrow = 0;
    {
      # narrowing constant byte
      my $value1 : byte = 127;
      my $value2 : byte = -128;
      my $value3 = $value1 + $value2;
      
      # narrowing constant short
      my $value4 : short = 32767;
      my $value5 : short = -32768;
      my $value6 = $value4 + $value5;

      # narrowing constant int
      my $value7 : int = 2147483647L;
      my $value8 : int = -2147483648L;
      my $value9 = $value7 + $value8;
      
      if ($value3 == -1) {
        if ($value6 == -1) {
          if ($value9 == -1) {
            $success_constant_narrow = 1;
          }
        }
      }
    }
    
    # Widning
    my $success_constant_wide = 0;
    {
      my $value1 : short = (byte)127;
      my $value2 : int = (byte)127;
      my $value3 : long = (byte)127;
      my $value4 : float = (byte)127;
      my $value5 : double = (byte)127;
      
      if ($value1 == 127) {
        if ($value2 == 127) {
          if ($value3 == 127) {
            if ($value4 == 127.0f) {
              if ($value5 = 127.0) {
                $success_constant_wide = 1;
              }
            }
          }
        }
      }
    }
    
    # Assign same name variable
    my $success_assign_same_name_variable = 0;
    {
      my $obj = TestCase::Minimal->new;
      $obj = $obj;
      $success_assign_same_name_variable = 1;
    }
    
    if ($success_constant_narrow && $success_constant_wide && $success_assign_same_name_variable) {
      return 1;
    }
    
    return 0;
  }
  
  sub assign_numeric_to_string : int () {
    my $inum : string = 25;
    my $dnum : string = 0.25;
    
    my $inum_str : string = $inum;
    my $dnum_str : string = $dnum;
    
    if ($inum_str eq "25" && $dnum_str eq "0.25") {
      return 1;
    }
    
    return 0;
  }

  sub assign_byte_to_byte_object : int () {
    my $byte : byte = INT8_MIN();
    my $byte_obj : SPVM::Byte = $byte;
    
    if ($byte_obj isa SPVM::Byte) {
      if ($byte_obj->val == INT8_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_short_to_short_object : int () {
    my $short : short = INT16_MIN();
    my $short_obj : SPVM::Short = $short;
    
    if ($short_obj isa SPVM::Short) {
      if ($short_obj->val == INT16_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_int_to_int_object : int () {
    my $int : int = INT32_MIN();
    my $int_obj : SPVM::Int = $int;
    
    if ($int_obj isa SPVM::Int) {
      if ($int_obj->val == INT32_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_long_to_long_object : int () {
    my $long : long = INT64_MIN();
    my $long_obj : SPVM::Long = $long;
    
    if ($long_obj isa SPVM::Long) {
      if ($long_obj->val == INT64_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_float_to_float_object : int () {
    my $float : float = FLT_MIN();
    my $float_obj : SPVM::Float = $float;
    
    if ($float_obj isa SPVM::Float) {
      if ($float_obj->val == FLT_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_double_to_double_object : int () {
    my $double : double = DBL_MIN();
    my $double_obj : SPVM::Double = $double;
    
    if ($double_obj isa SPVM::Double) {
      if ($double_obj->val == DBL_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_byte_to_any_object : int () {
    my $byte : byte = INT8_MIN();
    my $byte_obj : object = $byte;
    
    if ($byte_obj isa SPVM::Byte) {
      my $byte_obj2 = (SPVM::Byte)$byte_obj;
      if ($byte_obj2->val == INT8_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_short_to_any_object : int () {
    my $short : short = INT16_MIN();
    my $short_obj : object = $short;
    
    if ($short_obj isa SPVM::Short) {
      my $short_obj2 = (SPVM::Short)$short_obj;
      if ($short_obj2->val == INT16_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_int_to_any_object : int () {
    my $int : int = INT32_MIN();
    my $int_obj : object = $int;
    
    if ($int_obj isa SPVM::Int) {
      my $int_obj2 = (SPVM::Int)$int_obj;
      if ($int_obj2->val == INT32_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_long_to_any_object : int () {
    my $long : long = INT64_MIN();
    my $long_obj : object = $long;
    
    if ($long_obj isa SPVM::Long) {
      my $long_obj2 = (SPVM::Long)$long_obj;
      if ($long_obj2->val == INT64_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_float_to_any_object : int () {
    my $float : float = FLT_MIN();
    my $float_obj : object = $float;
    
    if ($float_obj isa SPVM::Float) {
      my $float_obj2 = (SPVM::Float)$float_obj;
      if ($float_obj2->val == FLT_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_double_to_any_object : int () {
    my $double : double = DBL_MIN();
    my $double_obj : object = $double;
    
    if ($double_obj isa SPVM::Double) {
      my $double_obj2 = (SPVM::Double)$double_obj;
      if ($double_obj2->val == DBL_MIN()) {
        return 1;
      }
    }
    return 0;
  }

  sub assign_byte_object_to_byte : int () {
    my $byte_obj = SPVM::Byte->new(INT8_MIN());
    my $byte : byte = $byte_obj;
    
    if ($byte == INT8_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_short_object_to_short : int () {
    my $short_obj = SPVM::Short->new(INT16_MIN());
    my $short : short = $short_obj;
    
    if ($short == INT16_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_int_object_to_int : int () {
    my $int_obj = SPVM::Int->new(INT32_MIN());
    my $int : int = $int_obj;
    
    if ($int == INT32_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_long_object_to_long : int () {
    my $long_obj = SPVM::Long->new(INT64_MIN());
    my $long : long = $long_obj;
    
    if ($long == INT64_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_float_object_to_float : int () {
    my $float_obj = SPVM::Float->new(FLT_MIN());
    my $float : float = $float_obj;
    
    if ($float == FLT_MIN()) {
      return 1;
    }
    return 0;
  }
  sub assign_double_object_to_double : int () {
    my $double_obj = SPVM::Double->new(DBL_MIN());
    my $double : double = $double_obj;
    
    if ($double == DBL_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_any_object_to_byte : int () {
    my $byte_obj = (object)SPVM::Byte->new(INT8_MIN());
    my $byte : byte = $byte_obj;
    
    if ($byte == INT8_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_any_object_to_short : int () {
    my $short_obj = (object)SPVM::Short->new(INT16_MIN());
    my $short : short = $short_obj;
    
    if ($short == INT16_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_any_object_to_int : int () {
    my $int_obj = (object)SPVM::Int->new(INT32_MIN());
    my $int : int = $int_obj;
    
    if ($int == INT32_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_any_object_to_long : int () {
    my $long_obj = (object)SPVM::Long->new(INT64_MIN());
    my $long : long = $long_obj;
    
    if ($long == INT64_MIN()) {
      return 1;
    }
    return 0;
  }

  sub assign_any_object_to_float : int () {
    my $float_obj = (object)SPVM::Float->new(FLT_MIN());
    my $float : float = $float_obj;
    
    if ($float == FLT_MIN()) {
      return 1;
    }
    return 0;
  }
  sub assign_any_object_to_double : int () {
    my $double_obj = (object)SPVM::Double->new(DBL_MIN());
    my $double : double = $double_obj;
    
    if ($double == DBL_MIN()) {
      return 1;
    }
    return 0;
  }
  sub assign_undef_to_numeric_object : int () {
    my $int_obj = SPVM::Int->new(1);
    $int_obj = undef;
    if ($int_obj == undef) {
      return 1;
    }
    return 0;
  }
}