# SPVMドキュメント 1.0 ベータ

SPVMドキュメント > SPVMエクスチェンジAPI仕様

## SPVMエクスチェンジAPI仕様

最終更新日 2019年5月27日

現在この日本語の翻訳ドキュメントは、SPVMの最新のドキュメントに追随していません。
最新のドキュメントはSPVM Documentを参照してください。
SPVMは1.0のリリースに向けて、活発に試験と開発が行われています。

SPVMエクスチェンジAPI仕様がこのドキュメントには記述されています。SPVMは、1.0のリリースに向けて、ベータテスト中です。SPVMエクスチェンジAPI仕様は、警告なく変更されることがあります。

## 目次

## SPVMエクスチェンジAPIとは

SPVMエクスチェンジAPIとは、PerlとSPVMのデータ構造を変換、PerlからSPVMのサブルーチンを呼び出すためのAPIのことです。

- Perlの数値や文字列や配列などのデータ構造をSPVMのデータ構造に変換
- SPVMのデータ構造をPerlの数値や文字列や配列などのデータ構造に変換
- SPVMのサブルーチンを呼び出す

SPVMで作成されたモジュールは、コンパイル終了後に、Perlのモジュールとして、そのまま実行できるようになります。

## Perlのデータ構造をSPVMのデータ構造に変換する

### Perlのスカラ値をSPVMのSPVM::Byte型に変換 - SPVM::Byte->new

Perlのスカラ値をSPVMのSPVM::Byte型に変換するには、SPVM::Byte->newメソッドを使います。

    my $spvm_byte = SPVM::Byte->new(98);

Perlのスカラ値は、Perlのスカラ値をSPVMの数値型に変換する規則よって、SPVMのbyte型に変換され、その値が、SPVM::Byteのnewメソッドに渡され、SPVM::Byte型のオブジェクトが返されます。

### Perlのスカラ値をSPVMのSPVM::Short型に変換 - SPVM::Short->new

Perlのスカラ値をSPVMのSPVM::Short型に変換するには、SPVM::Short->newメソッドを使います。

    my $spvm_short = SPVM::Short->new(9800);

Perlのスカラ値は、Perlのスカラ値をSPVMの数値型に変換する規則よって、SPVMのshort型に変換され、その値が、SPVM::Shortのnewメソッドに渡され、SPVM::Short型のオブジェクトが返されます。

### Perlのスカラ値をSPVMのSPVM::Int型に変換 - SPVM::Int->new

Perlのスカラ値をSPVMのSPVM::Int型に変換するには、SPVM::Int->newメソッドを使います。

    my $spvm_int = SPVM::Int->new(100000);

Perlのスカラ値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのint型に変換され、その値が、SPVM::Intのnewメソッドに渡され、SPVM::Int型のオブジェクトが返されます。

### Perlのスカラ値をSPVMのSPVM::Long型に変換 - SPVM::Long->new

Perlのスカラ値をSPVMのSPVM::Long型に変換すると、SPVM::Long->newメソッドを使います。

    my $spvm_long = SPVM::Long->new(98);

Perlのスカラ値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのlong型に変換され、その値が、SPVM::Longのnewメソッドに渡され、SPVM::Long型のオブジェクトが返されます。

### Perlのスカラ値をSPVMのSPVM::Float型に変換 - SPVM::Float->new

Perlのスカラ値をSPVMのSPVM::Float型に変換するには、SPVM::Float->newメソッドを使います。

    my $spvm_float = SPVM::Float->new(2.5);

Perlのスカラ値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのfloat型に変換され、その値が、SPVM::Floatのnewメソッドに渡され、SPVM::Float型のオブジェクトが返されます。

### Perlのスカラ値をSPVMのSPVM::Double型に変換 - SPVM::Double->new

Perlのスカラ値をSPVMのSPVM::Double型に変換するには、SPVM::Double->newメソッドを使います。

    my $spvm_double = SPVM::Double->new(2.5);

Perlのスカラ値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのdouble型に変換され、その値が、SPVM::Doubleのnewメソッドに渡され、SPVM::Double型のオブジェクトが返されます。

### Perlの配列リファレンスをSPVMのbyte[]型に変換 - SPVM::new_byte_array

Perlの配列リファレンスをSPVMのbyte[]型に変換するには、SPVM::new_byte_array関数を使います。

    my $spvm_nums = SPVM::new_byte_array([1, 2, 3]);

第一引数に配列リファレンスを受け取ります。

配列リファレンスのそれぞれの要素の値は、Perlのスカラ値から、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのbyte型に変換されます。

戻り値は、SPVMの「byte[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの配列リファレンスをSPVMのshort[]型に変換

Perlの配列リファレンスをSPVMのshort[]型に変換するには、SPVM::new_short_array関数を使います。

    my $spvm_nums = SPVM::new_short_array([1, 2, 3]);

第一引数に配列リファレンスを受け取ります。

配列リファレンスのそれぞれの要素の値は、Perlのスカラ値から、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのshort型に変換されます。

戻り値は、SPVMの「short[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの配列リファレンスをSPVMのint[]型に変換

Perlの配列リファレンスをSPVMのint[]型に変換するには、SPVM::new_int_array関数を使います。

    my $spvm_nums = SPVM::new_int_array([1, 2, 3]);

第一引数に配列リファレンスを受け取ります。

配列リファレンスのそれぞれの要素の値は、Perlのスカラ値から、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMのint型に変換されます。

戻り値は、SPVMの「int[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの配列リファレンスをSPVMのlong[]型に変換

Perlの配列リファレンスをSPVMのlong[]型に変換するには、SPVM::new_long_array関数を使います。

    my $spvm_nums = SPVM::new_long_array([1, 2, 3]);

第一引数に配列リファレンスを受け取ります。

配列リファレンスのそれぞれの要素の値は、Perlのスカラ値から、perlapiとC99の型変換による以下の変換によって、SPVMのlong型に変換されます。

    (int64_t)SvIV(perl_value)

戻り値は、SPVMの「long[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの配列リファレンスをSPVMのfloat[]型に変換

Perlの配列リファレンスをSPVMのfloat[]型に変換するには、SPVM::new_float_array関数を使います。

    my $spvm_nums = SPVM::new_float_array([1, 2, 3]);

第一引数に配列リファレンスを受け取ります。

配列リファレンスのそれぞれの要素の値は、Perlのスカラ値から、perlapiとC99の型変換による以下の変換によって、SPVMのfloat型に変換されます。

    (float)SvNV(perl_value)

戻り値は、SPVMの「float[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの配列リファレンスをSPVMのdouble[]型に変換

Perlの配列リファレンスをSPVMのdouble[]型に変換するには、SPVM::new_double_array関数を使います。

    my $spvm_nums = SPVM::new_double_array([1, 2, 3]);

第一引数に配列リファレンスを受け取ります。

配列リファレンスのそれぞれの要素の値は、Perlのスカラ値から、perlapiとC99の型変換による以下の変換によって、SPVMのdouble型に変換されます。

    (double)SvNV(perl_value)

戻り値は、SPVMの「double[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの配列リファレンスをSPVMのオブジェクトの配列型に変換 - SPVM::new_object_array

Perlの配列リファレンスをSPVMのオブジェクトの配列型に変換するには、SPVM::new_object_array関数を使います。

    my $byte_array = SPVM::new_object_array("SPVM::Byte[]", [SPVM::Byte->new(1), SPVM::Byte->new(2), SPVM::Byte->new(3)]);

第一引数は、型名を指定します。これは、存在する基本型を要素とする配列型でなければなりません。そうでない場合は、例外が発生します。

第二引数は、Perlの配列リファレンスです。要素は、SPVMのオブジェクト型を表現した「SPVM::Data」を継承しているオブジェクトか、未定義値でなければなりません。そうでない場合は、例外が発生します。

戻り値は、SPVMの配列型を表現した「SPVM::Data::Array」オブジェクトです。

多次元配列を生成することもできます。

    my $object1 = SPVM::new_int_array([1, 2, 3]);
    my $object2 = SPVM::new_int_array([4, 5, 6]);
    my $oarray = SPVM::new_object_array("int[][]", [$object1, $object2]);

### Perlの配列リファレンスをSPVMの値の配列型に変換 - SPVM::new_mulnum_array

Perlの配列リファレンスをSPVMの値の配列型に変換するには、SPVM::new_mulnum_array関数を使用します。

        my $perl_values = [
          {x => 0, y => 1, z => 2},
          {x => 3, y => 4, z => 5},
          {x => 6, y => 7, z => 8},
        ];
        my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3i[]", $values);

第一引数は、SPVMの値の配列型を指定します。

第二引数は、ハッシュリファレンスを要素に持つ、配列リファレンスです。ハッシュのリファレンスのキーには、複数数値型のすべてのフィールドの値が含まれていなければなりません。そうでない場合は、例外が発生します。

戻り値は、SPVMの値の配列型を表現した「SPVM::Data::Array」オブジェクトです。

ハッシュリファレンスに含まれる値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、変換されます。

いくつかのサンプルです。

    # new_mulnum_array - byte
    {
      my $values = [
        {x => 0, y => 1, z => 2},
        {x => 3, y => 4, z => 5},
        {x => 6, y => 7, z => 8},
      ];
      my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3b[]", $values);
    }

    # new_mulnum_array - short
    {
      my $values = [
        {x => 0, y => 1, z => 2},
        {x => 3, y => 4, z => 5},
        {x => 6, y => 7, z => 8},
      ];
      my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3s[]", $values);
    }

    # new_mulnum_array - int
    {
      my $values = [
        {x => 0, y => 1, z => 2},
        {x => 3, y => 4, z => 5},
        {x => 6, y => 7, z => 8},
      ];
      my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3i[]", $values);
    }

    # new_mulnum_array - long
    {
      my $values = [
        {x => 0, y => 1, z => 2},
        {x => 3, y => 4, z => 5},
        {x => 6, y => 7, z => 8},
      ];
      my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3l[]", $values);
    }

    # new_mulnum_array - float
    {
      my $values = [
        {x => 0, y => 1, z => 2},
        {x => 3, y => 4, z => 5},
        {x => 6, y => 7, z => 8},
      ];
      my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3f[]", $values);
    }

    # new_mulnum_array - double
    {
      my $values = [
        {x => 0, y => 1, z => 2},
        {x => 3, y => 4, z => 5},
        {x => 6, y => 7, z => 8},
      ];
      my $spvm_value_array = SPVM::new_mulnum_array("TestCase::Point_3d[]", $values);
      ok(TestCase::ExchangeAPI->spvm_new_mulnum_array_double($spvm_value_array));
      my $out_values = $spvm_value_array->to_elems;
      is_deeply($out_values, $values);
    }

### Perlのバイナリ列をSPVMのbyte[]型に変換 - SPVM::new_byte_array_from_bin

Perlのバイナリ列をSPVMのbyte[]型に変換するには、SPVM::new_byte_array_from_bin関数を使います。

    my $perl_binary = pack('c3', 97, 98, 99);
    my $spvm_byte_array = SPVM::new_byte_array_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ8bit符号付整数の並びと解釈されます。長さは、8bit符号付整数として解釈された場合の長さになります。

戻り値は、SPVMの「byte[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

上記のサンプルは、次と同じ意味でもあります。バイナリ列は、8bit符号付整数の並びである場合は、packを使っても、Perlのdecodeされていない文字列でもかまいません。

    my $binary = "abc";
    my $spvm_byte_array = SPVM::new_byte_array_from_bin($perl_binary);

### Perlのバイナリ列をSPVMのstring型に変換 - SPVM::new_string_from_bin

Perlのバイナリ列をSPVMのstring型に変換するには、SPVM::new_string_from_bin関数を使います。

    my $perl_binary = pack('c3', 97, 98, 99);
    my $spvm_byte_array = SPVM::new_string_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ8bit符号付整数の並びと解釈されます。長さは、8bit符号付整数として解釈された場合の長さになります。

戻り値は、SPVMの「byte[]」型を表現した「SPVM::Data::Array」オブジェクトです。SPVMのstring型は実行時にはbyte[]型として扱われます。

第一引数が未定義値だった場合は、未定義値が返ります。

上記のサンプルは、次と同じ意味でもあります。バイナリ列は、8bit符号付整数の並びである場合は、packを使っても、Perlのdecodeされていない文字列でもかまいません。

    my $binary = "abc";
    my $spvm_byte_array = SPVM::new_byte_array_from_bin($perl_binary);

この関数は実際には、SPVM::new_byte_array_from_binのエイリアスです。

### Perlのバイナリ列をSPVMのshort[]型に変換 - SPVM::new_short_array_from_bin

Perlのバイナリ列をSPVMのshort[]型に変換するには、SPVM::new_short_array_from_bin関数を使います。

    my $perl_binary = pack('s3', 97, 98, 99);
    my $spvm_short_array = SPVM::new_short_array_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ16bit符号付整数の並びと解釈されます。長さは、16bit符号付整数として解釈された場合の長さになります。

戻り値は、SPVMの「short[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlのバイナリ列をSPVMのint[]型に変換 - SPVM::new_int_array_from_bin

Perlのバイナリ列をSPVMのint[]型に変換するには、SPVM::new_int_array_from_bin関数を使います。

    my $perl_binary = pack('l3', 97, 98, 99);
    my $spvm_int_array = SPVM::new_int_array_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ32bit符号付整数の並びと解釈されます。長さは、32bit符号付整数として解釈された場合の長さになります。

戻り値は、SPVMの「int[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlのバイナリ列をSPVMのlong[]型に変換 - SPVM::new_long_array_from_bin

Perlのバイナリ列をSPVMのlong[]型に変換するには、SPVM::new_long_array_from_bin関数を使います。

    my $perl_binary = pack('q3', 97, 98, 99);
    my $spvm_long_array = SPVM::new_long_array_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ64bit符号付整数の並びと解釈されます。長さは、64bit符号付整数として解釈された場合の長さになります。

戻り値は、SPVMの「long[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlのバイナリ列をSPVMのfloat[]型に変換 - SPVM::new_float_array_from_bin

Perlのバイナリ列をSPVMのfloat[]型に変換するには、SPVM::new_float_array_from_bin関数を使います。

    my $perl_binary = pack('f3', 0.5, 1.5, 2.5);
    my $spvm_float_array = SPVM::new_float_array_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ32bit浮動小数点の並びと解釈されます。長さは、32bit浮動小数点として解釈された場合の長さになります。

戻り値は、SPVMの「float[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlのバイナリ列をSPVMのdouble[]型に変換 - SPVM::new_double_array_from_bin

Perlのバイナリ列をSPVMのdouble[]型に変換するには、SPVM::new_double_array_from_bin関数を使います。

    my $perl_binary = pack('f3', 0.5, 1.5, 2.5);
    my $spvm_double_array = SPVM::new_double_array_from_bin($perl_binary);

第一引数にPerlのバイナリ列を受け取ります。

バイナリ列は、実行環境のバイトオーダーで並んだ32bit浮動小数点の並びと解釈されます。長さは、32bit浮動小数点として解釈された場合の長さになります。

戻り値は、SPVMの「double[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlのバイナリ列をSPVMの値の配列型に変換 - SPVM::new_mulnum_array_from_bin

Perlのパックされたバイナリを、SPVMの値の配列型に変換するには、SPVM::new_mulnum_array_from_bin関数を使用します。

        my $binary = pack('l9', ($INT_MIN, 1, 2), (3, 4, 5), (6, 7, 8));
        my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3i[]", $binary);

第一引数は、Perlのパックされたバイナリを指定します。バイナリの長さは、複数数値型のフィールドの個数とフィールド幅をかけたもので、割り切れる必要があります。そうでない場合は、例外が発生します。

第二引数は、SPVMの値の配列型を指定します。

戻り値は、SPVMの値の配列型を表現した「SPVM::Data::Array」オブジェクトです。返される配列の長さは、バイナリの長さを、複数数値型のフィールドの個数とフィールド幅をかけたもので、割った長さになります。

いくつかのサンプルです。

    # new_mulnum_array_from_bin - byte
    {
      my $binary = pack('c9', (0, 1, 2), (3, 4, 5), (6, 7, 8));
      my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3b[]", $binary);
    }

    # new_mulnum_array_from_bin - short
    {
      my $binary = pack('s9', (0, 1, 2), (3, 4, 5), (6, 7, 8));
      my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3s[]", $binary);
    }

    # new_mulnum_array_from_bin - int
    {
      my $binary = pack('l9', (0, 1, 2), (3, 4, 5), (6, 7, 8));
      my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3i[]", $binary);
    }

    # new_mulnum_array_from_bin - long
    {
      my $binary = pack('q9', (0, 1, 2), (3, 4, 5), (6, 7, 8));
      my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3l[]", $binary);
    }

    # new_mulnum_array_from_bin - float
    {
      my $binary = pack('f9', (0, 1, 2), (3, 4, 5), (6, 7, 8));
      my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3f[]", $binary);
    }

    # new_mulnum_array_from_bin - double
    {
      my $binary = pack('d9', (0, 1, 2), (3, 4, 5), (6, 7, 8));
      my $spvm_value_array = SPVM::new_mulnum_array_from_bin("TestCase::Point_3d[]", $binary);
    }

第一引数は、SPVMの値の配列型を指定します。

第二引数は、ハッシュリファレンスを要素に持つ、配列リファレンスです。ハッシュのリファレンスのキーには、複数数値型のすべてのフィールドの値が含まれていなければなりません。そうでない場合は、例外が発生します。

## SPVMのデータ構造をPerlのデータ構造に変換する

### SPVMの配列をPerlの配列リファレンスに変換 - to_elems

SPVMの配列をPerlの配列リファレンスに変換するにはSPVM::Data::Arrayのto_elemsメソッドを使用します。

    my $perl_array_ref = $spvm_array->to_elems;

SPVMの配列の要素が、数値型である場合は、SPVMの数値型をPerlのスカラ値に変換する規則によって変換されます。

SPVMの配列の要素が、オブジェクト型である場合は、対応するSPVM::Dataあるいは、そのサブクラスが作成されます。

SPVMの配列の要素が、複数数値型である場合は、フィールドのキーと値を持つ、ハッシュリファレンスが作成されます。値は、SPVMの数値型をPerlのスカラ値に変換する規則によって変換されます。

SPVMの配列の要素が、未定義値である場合は、Perlの未定義値に変換されます。

### SPVMの配列をPerlのバイナリ列に変換 - to_bin

SPVMの配列をPerlのバイナリ列に変換るにはSPVM::Data::Arrayのto_binメソッドを使用します。

    my $perl_binary = $spvm_array->to_bin;

SPVMの配列が、数値の配列型、あるいは、値の配列型である場合は、SPVMにおけるバイナリ表現が、そのままスカラ変数にコピーされます。

SPVMの配列がそれ以外の型である場合は、例外が発生します。

### SPVMの文字列をPerlの文字列に変換 - to_string

SPVMの文字列をPerlの文字列に変換するにはSPVM::Data::Arrayのto_stringメソッドを使用します。

    my $perl_array_ref = $spvm_array->to_string;

SPVMの型がbyte[]型あるいはstring型である場合は、PerlのUTF-8でデコードされた文字列に変換されます。

SPVMのデータが未定義値である場合は、Perlの未定義値に変換されます。

SPVMのデータが、上記以外の型である場合は、例外が発生します。

### SPVMの文字列の配列をPerlの文字列の配列リファレンスに変換 - to_strings

SPVMの文字列の配列をPerlの文字列の配列リファレンスに変換するにはSPVM::Data::Arrayのto_stringsメソッドを使用します。

    my $perl_array_ref = $spvm_array->to_strings;

SPVMの型がbyte[][]型あるいはstring[]型である場合は、PerlのUTF-8でデコードされた文字列の配列のリファレンスに変換されます。

SPVMの配列型の要素が未定義値であった場合は、Perlの未定義値に変換されます。

SPVMのデータが、上記以外の型である場合は、例外が発生します。

## SPVMのサブルーチンの呼び出し

### SPVMモジュールの読み込み

SPVMモジュールは、次のようにしてPerlから読み込むことができます。モジュール名と検索のルールは、拡張子が「spvm」であることを除いて、Perlと同じです。

    # script.pl

    use SPVM 'Foo';

モジュールの検索パス上に以下のFoo.spvmが配置されているとします。

    # Foo.spvm
    package Foo {
      sub sum : int ($x1 : int, $x2 : int) {

        return $x1 + $x2;
      }
    }

### サブルーチン呼び出し

サブルーチンを呼び出すためには、SPVMモジュールの読み込みによって、SPVMモジュールが読み込まれている必要があります。

    # script.pl

    use SPVM 'Foo';

モジュールの検索パス上に以下のFoo.spvmが配置されているとします。

    # Foo.spvm
    package Foo {
      sub sum : int ($x1 : int, $x2 : int) {

        return $x1 + $x2;
      }
    }

SPVMのサブルーチンは、Perlのサブルーチンでラッピングされ、Perlのクラスメソッド呼び出しを使って呼び出すことができます。

    # script.pl

    use SPVM 'Foo';

    my $total = Foo->sum(1, 2);

引数の個数がSPVMのサブルーチンの引数の個数と一致しない場合は、例外が発生します。

引数に渡されるPerlの値は、引数における変換によって、SPVMの値に変換されます。

変換後の型が、SPVMのサブルーチンの引数の型に適合しない場合は、例外が発生します。

戻り値は、戻り値における変換によって、変換されます。

SPVMの例外は、Perlの例外に変換されます。

### メソッド呼び出し

メソッドを呼び出すためには、SPVMモジュールの読み込みによって、SPVMモジュールが読み込まれている必要があります。

    # script.pl

    use SPVM 'Foo';

モジュールの検索パス上に以下のFoo.spvmが配置されているとします。

    # Foo.spvm
    package Foo {
      sub new : Foo {
        return new Foo;
      }

      sub sum : int ($self : self, $x1 : int, $x2 : int) {
        return $x1 + $x2;
      }
    }

SPVMのメソッドは、Perlのサブルーチンでラッピングされ、Perlのメソッド呼び出しを使って呼び出すことができます。

    # script.pl

    use SPVM 'Foo';

    my $foo = Foo->new;

    my $total = $foo->sum(1, 2);

引数の個数がSPVMのサブルーチンの引数の個数と一致しない場合は、例外が発生します。

引数に渡されるPerlの値は、引数における変換によって、SPVMの値に変換されます。

変換後の型が、SPVMのサブルーチンの引数の型に適合しない場合は、例外が発生します。

戻り値は、戻り値における変換によって、変換されます。

SPVMの例外は、Perlの例外に変換されます。

### 引数における変換

#### 数値型

SPVMのサブルーチンの定義の引数の型が数値型であった場合は、引数の値はPerlのスカラ値をSPVMの数値型に変換する規則によって、SPVMの数値に変換されます。

    # SPVMのサブルーチン定義
    package Foo {
      sub call_byte : void ($num : byte);
      sub call_short : void ($num : short);
      sub call_int : void ($num : int);
      sub call_long : void ($num : long);
      sub call_float : void ($num : float);
      sub call_double : void ($num : double);
    }

    # Perlから呼び出し
    Foo->call_byte(23);
    Foo->call_short(23);
    Foo->call_int(23);
    Foo->call_long(23);
    Foo->call_float(2.3);
    Foo->call_double(2.3);

#### 複数数値型

SPVMのサブルーチンの定義の引数の型が複数数値型であった場合は、引数の値は、ハッシュのリファレンスで、キーには、複数数値型のすべてのフィールド名が含まれている必要があります。そうでない場合は、例外が発生します。ハッシュリファレンスの値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMの値に変換されます。

    # SPVMのサブルーチン定義
    package Foo {
      sub call_complex_float : void ($z : SPVM::Complex_2f);
      sub call_complex_double : void ($z : SPVM::Complex_2d);
    }

    # Perlから呼び出し
    Foo->call_complex_float({re => 2.3, im => 5.6});
    Foo->call_complex_double({re => 2.3, im => 5.6});

#### 数値のリファレンス型

SPVMのサブルーチンの定義の引数の型が数値のリファレンス型であった場合は、引数の値は、スカラのリファレンスでなければなりません。そうでない場合は、例外が発生します。

    # SPVMのサブルーチン定義
    package Foo {
      sub call_byte_ref : void ($num : byte&);
      sub call_short_ref : void ($num : short&);
      sub call_int_ref : void ($num : int&);
      sub call_long_ref : void ($num : long&);
      sub call_float_ref : void ($num : float&);
      sub call_double_ref : void ($num : double&);
    }

    # Perlから呼び出し
    my $num_byte = 23;
    Foo->call_byte_ref(\$num_byte);

    my $num_short = 23;
    Foo->call_short_ref(\$num_short);

    my $num_int = 23;
    Foo->call_int_ref(\$num_int);

    my $num_long = 23;
    Foo->call_long_ref(\$num_long);

    my $num_float = 23;
    Foo->call_float_ref(\$num_float);

    my $num_double = 23;
    Foo->call_double_ref(\$num_double);

SPVMのサブルーチンの定義の引数の型が複数数値のリファレンス型であった場合は、引数の値は、ハッシュのリファレンスのリファレンスで、キーには、複数数値型のすべてのフィールド名が含まれている必要があります。そうでない場合は、例外が発生します。

SPVMのサブルーチンの定義の引数の型が、数値の配列型であった場合は、Perlの配列のリファレンスは、対応するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値は、Perlのスカラ値をSPVMの数値型に変換する規則によって、SPVMの数値に変換されます。引数が文字列で、

SPVMのサブルーチンの定義の引数の型が、byte[]型であった場合は、Perlのデコードされた文字列は、UTF-8にエンコードされ、byte[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。

SPVMのサブルーチンの定義の引数の型が、オブジェクト型で、引数に渡される値が未定義値であった場合は、SPVMの未定義値に変換されます。

SPVMのサブルーチンの定義の引数の型が、文字列互換型で、引数に渡される値が、リファレンスではないスカラ値であった場合は、UTF-8にエンコードされ、SPVMのbyte[]型を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。

SPVMのサブルーチンの定義の引数の型が、文字列互換型の配列型で、引数に渡される値が、配列リファレンスかつ最初の要素がリファレンスではないスカラ値であった場合は、SPVMのbyte[][]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素は未定義値であった場合は、SPVMの未定義値に変換され、そうでない場合は、UTF-8にエンコードされ、SPVMのbyte[]型に変換されます。

SPVMのサブルーチンの定義の引数の型が、byte[]型で、引数に渡される値が、配列リファレンスであった場合は、byte[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値はPerlのスカラ値をSPVMの数値型に変換する規則によって変換されます。

SPVMのサブルーチンの定義の引数の型が、short[]型で、引数に渡される値が、配列リファレンスであった場合は、short[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値はPerlのスカラ値をSPVMの数値型に変換する規則によって変換されます。

SPVMのサブルーチンの定義の引数の型が、int[]型で、引数に渡される値が、配列リファレンスであった場合は、int[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値はPerlのスカラ値をSPVMの数値型に変換する規則によって変換されます。

SPVMのサブルーチンの定義の引数の型が、long[]型で、引数に渡される値が、配列リファレンスであった場合は、long[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値はPerlのスカラ値をSPVMの数値型に変換する規則によって変換されます。

SPVMのサブルーチンの定義の引数の型が、float[]型で、引数に渡される値が、配列リファレンスであった場合は、float[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値はPerlのスカラ値をSPVMの数値型に変換する規則によって変換されます。

SPVMのサブルーチンの定義の引数の型が、double[]型で、引数に渡される値が、配列リファレンスであった場合は、double[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値はPerlのスカラ値をSPVMの数値型に変換する規則によって変換されます。

SPVMのサブルーチンの定義の引数の型が、object[]型で、引数に渡される値が、配列リファレンスであった場合は、object[]を表現するPerlのSPVM::Data::Arrayオブジェクトに変換されます。要素の値が未定義値であった場合は、SPVMの未定義に変換され、リファレンスでないスカラ値であった場合は、UTF-8にエンコードされ、SPVMのbyte[]型に変換され、PerlのSPVM::Dataオブジェクトであれば、変換はされません。それ以外の場合は、例外が発生します。

### 戻り値における変換

戻り値が、SPVMの数値型であった場合は、SPVMの数値型をPerlのスカラ値に変換する規則によって、Perlのスカラ値に変換されます。

戻り値が、SPVMの複数数値型であった場合は、ハッシュのリファレンスに変換されます。キーは、SPVMの複数数値型のフィールド名で、値はSPVMの数値型をPerlのスカラ値に変換する規則によってPerlのスカラ値に変換された値になります。

戻り値が、SPVMのオブジェクト型で未定義値であった場合は、Perlの未定義値に変換されます。

戻り値がSPVMの配列型(汎用オブジェクト配列型を含む)であった場合は、対応するPerlのSPVM::Data::Arrayオブジェクトに変換されます。

戻り値がSPVMの配列型以外のオブジェクト型であった場合は、対応するPerlのSPVM::Dataオブジェクトに変換されます。

## ユーティリティ

その他のユーティリティです。

### SPVMの例外の取得 - exception

SPVMの例外を取得します。取得される文字列は、undefでなかった場合は、UTF-8とみなしてデコードされた文字列です。

    my $exception = SPVM::exception();

### Perlの文字列をSPVMのbyte[]型に変換 - SPVM::new_byte_array_from_string

Perlの文字列をSPVMのbyte[]型に変換するには、SPVM::new_byte_array_from_string関数を使います。Perlの文字列は、ここではデコードされた文字列を指します。

    use utf8;
    my $spvm_byte_array = SPVM::new_byte_array_from_string("あいうえお");

第一引数にPerlの文字列を受け取ります。Perlの文字列は、ここではデコードされた文字列を指します。

長さは、UTF-8として、バイト列を数えた場合の長さになります。

戻り値は、SPVMの「byte[]」型を表現した「SPVM::Data::Array」オブジェクトです。

第一引数が未定義値だった場合は、未定義値が返ります。

### Perlの文字列をSPVMのstring型に変換 - SPVM::new_string

Perlの文字列をSPVMのstring型に変換するには、SPVM::new_string関数を使います。Perlの文字列は、ここではデコードされた文字列を指します。

    use utf8;
    my $spvm_string = SPVM::new_string("あいうえお");

第一引数にPerlの文字列を受け取ります。

長さは、UTF-8として、バイト列を数えた場合の長さになります。

戻り値は、SPVMの「byte[]」型を表現した「SPVM::Data::Array」オブジェクトです。SPVMのstring型は実行時にはbyte[]型として扱われます。

第一引数が未定義値だった場合は、未定義値が返ります。

この関数は実際には、SPVM::new_byte_array_from_stringのエイリアスです。

### SPVMの例外の設定 - set_exception

SPVMの例外を設定します。引数は、デコードされた文字列かundefを指定します。

    SPVM::set_exception("あいう");
    SPVM::set_exception(undef);

### 確保されたメモリブロックの数を取得 - memory_blocks_count

memory_blocks_count関数を使うと、確保されたメモリブロックの数を取得できます。

    my $count = SPVM::get_memory_blocks_count();

SPVMランタイムは、オブジェクトを生成するとき、ウィークリファレンスを新しく作成するときに、ヒープからメモリを確保します。一回のメモリ取得の操作によって確保されたメモリをメモリブロックと呼びます。

SPVMは、リファレンスカウント式のGCを持っており、通常は、メモリの確保と解放については、意識する必要がありませんが、ネイティブでサブルーチンを記述するときは、メモリリークが起こっていないことを試験で確認したいという場合があるでしょう。

    # 最初のメモリブロックカウント
    my $start_memory_blocks_count = SPVM::get_memory_blocks_count();

    # 処理
    # ...

    # 最後のメモリブロックカウント
    my $end_memory_blocks_count = SPVM::get_memory_blocks_count();

    unless ($end_memory_blocks_count == $start_memory_blocks_count) {
      die "Memroy leak";
    }

## Perlのスカラ値をSPVMの数値型に変換する規則

Perlのスカラ値をSPVMの数値型に変換する規則は以下で定義されます。

変換規則は、C言語で記述されます。SvIVとSvNVは、perlapiで定義された関数です。int8_t, int16_t, int32_t, int64_t, float, doubleは、C99で定義されている型です。

Perlのスカラ値をSPVMのbyte型に変換

    (int8_t)SvIV(perl_value)

Perlのスカラ値をSPVMのshort型に変換

    (int16_t)SvIV(perl_value)

Perlのスカラ値をSPVMのint型に変換

    (int32_t)SvIV(perl_value)

Perlのスカラ値をSPVMのlong型に変換

    (int64_t)SvIV(perl_value)

Perlのスカラ値をSPVMのfloat型に変換

    (float)SvNV(perl_value)

Perlのスカラ値をSPVMのdouble型に変換

    (double)SvNV(perl_value)

## SPVMの数値型をPerlのスカラ値に変換する規則

Perlのスカラ値をSPVMの数値型に変換する規則は以下で定義されます。

変換規則は、C言語で記述されます。newSVivとnewSVnvは、perlapiで定義された関数です。int8_t, int16_t, int32_t, int64_t, float, doubleは、C99で定義されている型です。

SPVMの値は、コードのサンプルでは、不定になっていますが、値が入っているものと考えて下さい。

Perlのスカラ値をSPVMのbyte型に変換

    int8_t spvm_value;
    newSViv(spvm_value)

Perlのスカラ値をSPVMのshort型に変換

    int16_t spvm_value;
    newSViv(spvm_value)

Perlのスカラ値をSPVMのint型に変換

    int32_t spvm_value;
    newSViv(spvm_value)

Perlのスカラ値をSPVMのlong型に変換

    int64_t spvm_value;
    newSViv(spvm_value)

Perlのスカラ値をSPVMのfloat型に変換

    float spvm_value;
    newSVnv(spvm_value)

Perlのスカラ値をSPVMのdouble型に変換

    double spvm_value;
    newSVnv(spvm_value)