SPVMでは以下のようにサブルーチンを呼び出すことができません。
Foo::bar();
常に、アロー演算子を使う必要があります。
Foo->bar();
SPVMの世界に閉じるのであれば、この二つを同じものとして扱うことができるのですが、Perlの世界においては、二つの表現は意味が異なります。
SPVMのひとつの目標は、SPVMにおける呼び出しとPerlにおける呼び出しを完全に一致させることです。
SPVMの世界でアロー演算子で呼び出せるものが、Perlの世界でもアロー演算子で呼び出せるという単純な規則を設けることで、呼び出しを完全に一致させています。
C99は、加算演算子・減算演算子・乗算演算子における整数演算のオーバーフロー時の動作について定義していないので、処理系依存になります。
ほぼすべての環境においては、2の補数表現を使って、整数を表現し、加算と減算を行いますので、2の補数表現で演算を行った場合の結果になることが期待されます。
はい。ライブラリがC89、C11、C++の各仕様で書かれていても利用できます。C99準拠というのは、SPVM自体のソースコード自体において適用されるだけです。
通常は、定数畳み込みの最適化は、行われませんが、プリコンパイルされたサブルーチンでは、定数畳み込みがCコンパイラによって試みらるでしょう。
演算子の優先順位はPerlをベースにして作成されており、ほぼPerlの優先順位だと考えて大丈夫です。
ひとつの違いは、SPVMには型キャストがあることです。型キャストは「単項演算子」の優先順位よりもひとつ低く、「乗算演算子」の優先順位よりも一つ高くなっています。
以下の例ではキャストが先に行われます。
(long)3 + 1;
これを、戻り値にすることは可能なはずですが、現在は実装されていません。
実装されていない理由は、一時変数の増加とオペレーションコードの増加が見込まれ、最適な形で実装することが、現在の作者の実力では困難であることです。
現在の内部実装では、条件判定した結果は、内部的な条件フラグに保存されます。
戻り値が欲しい場合は、次のように記述してください。
my $flag : int; if ($num > 3) { $flag = 1; } else { $flag = 0; }
SPVMは柔軟で、十分な後方互換性を保つことを目標に現在、設計しています。
いくつかの分野で、プログラムが正しく記述できること、パフォーマンスの要件を満たすことが必要です。1.0のリリースは、この要件が満たされた後になります。
デバイスドライバや、Open CV、Open GL、SIMD、 Open MP、GPUなどのC/C++ライブラリとの連携の確認。
HTTPSのリクエストを処理できるHTTPクライアント/サーバーライブラリ。
Windows APIを利用したネイティブWindowsアプリケーションの作成。
少なくともデバイスドライバやC/C++ライブラリと連携でき、WebにHTTPSで接続できる、ネイティブアプリケーションが作成できることの確認が必要です。
言語仕様と文法についてはPerlを主に参考にしています。
Perl 6の文法・キーワードを部分的に採用しています。「has」「native」「ro」「rw」「wo」など。
SPVMのバーチャルマシンの初期実装は、JavaVMを参考にして、可変長バイト命令を解釈するスタック型VMとして作成されました。現在のSPVMは、64bitの固定長命令を解釈するレジスター型VMとなっています。
数値型と数値計算においては、Javaの計算規則を参考にしました。
ボクシング、アンボクシング、可変長引数については、Javaを参考にしました。
コールバックについては、C言語の関数ポインタを参考にしました。
レジスタ型VMを採用している最も大きな理由は、SPVMのオペレーションコードを、C言語のソースコードに変換するときに、1対1で対応させることができるためです。gccの最適化が適用できます。
残念なことですが、列挙に利用できるるのはint型だけです。
他の型の定数を利用したい場合は、定数を返すサブルーチンを定義してください。
sub FOO : double () { return 3.14; }
一つの定数を返すサブルーチンは、定数としてインライン展開されることが仕様上で保証されているので、パフォーマンスを気にせず利用できます。
SPVMにおいては、メソッドの呼び出し、クラスメソッドの呼び出しについては、かっこの省略が可能です。サブルーチン名だけを指定した場合においては、かっこの省略ができません。
これは、サブルーチン名だけでは、識別子名がサブルーチンであることを、ソースコードの中で、決定できないためです。パッケージ名やフィールド名との区別ができません。
他のソースファイルを解析することによって、かっこを省略する構文は、理論的には可能ですが、SPVMでは、単一ファイルの中で、静的な構文解析を完了できるということを重要視しました。
gcc 4.3で確認しており、保証される最低のバージョンはgcc 4.3です。C99がサポートされている必要があります。
残念ながら、SPVMには、符号なし整数型はありません。
Unix、Linux、macOS、Windowsに対応しています。
コンテキストは存在しません。関数の呼び出しには括弧が必要です。三項演算子はありません。シングルクォートは、文字定数です。
標準関数や標準モジュールは、Perlとは完全に異なっています。
サブルーチンは、必ずメソッドか、クラスメソッドになります。サブルーチンの絶対名での呼び出しはできません。
モジュールの拡張子は「spvm」です。
型はすべて静的型です。サブルーチン呼び出しは、コンパイル時に解決されます。配列は静的です。動的配列とハッシュは、モジュールとして提供されます。
スレッドは、コアではサポートされていませんが、エクステンションを使ったユーザーモジュールを作成することで、間接的に利用できます。
SPVMはシングルスレッドで動くように設計されています。シングルスレッドは、利用者にとって簡単で安全な設計です。
スレッドの機能はSPVMのコアにはありませんが、CやC++のスレッドライブラリを利用して、エクステンションから利用することはできます。
エクステンションでは、スレッド用のSPVMの実行環境を生成して、スレッド上で、利用できます。
SPVMのモジュールとして作成すれば、SPVMからサブルーチンを通して、間接的にスレッドを利用できます。
エクステンションとは、SPVMからC/C++の関数を呼び出すための仕組みのことです。
プリコンパイルとは、SPVMのサブルーチンを、コンパイル時に機械語に変換する仕組みのことです。機械語に変換されたサブルーチンは、高速に実行できます。
precompileが指定されたサブルーチンを含むモジュールファイルは、コンパイル時に、Cのソースコードに変換されます。
precompile sub sum : int ($num1 : int, $num2 : int) { return $num1 + $num2; }
Cのソースコードは、ビルドディレクトリの中に作成されます。
生成されたCのソースコードは、Perlをコンパイルしたコンパイラ(通常はgccかclang)によって、機械語(.oの拡張子を持つオブジェクトファイル)にコンパイルされます。
機械語に変換された後、各OSで呼び出すことのできる共有ライブラリ(.soや.dll)にリンクされます。
プリコンパイルする場合に、必要となるディレクトリのことです。
ビルドディレクトリを利用することをSPVMに教えるにはSPVM::BuildDirモジュールを使用する必要があります。
use SPVM::BuildDir;
スクリプトがあるディレクトリの「spvm_build」というディレクトリがデフォルトのビルドディレクトリ名になります。
ビルドディレクトリ名を自分で指定したい場合は、次のようにします。
use FindBin; use SPVM::BuildDir "$FindBin::Bin/mydir;
SPVMでは、コールバック型とは、実装を持たないメソッドが一つだけ定義されているパッケージのことをいいます。
コールバック型のひとつの例は、標準モジュールである「SPVM::Comparable」です。
package SPVM::Comparable : callback_t { sub compare : int ($self : self, $object1 : object, $object2 : object); }
機能としては、C言語の関数ポインタに似ています。
残念なことですが、SPVMにはジェネリクスはありません。SPVMは、コンパイル時の型決定性よりも、型の簡単さを選択しました。
コンテナの要素は、汎用オブジェクト型で定義してください。汎用オブジェクトから実際のオブジェクトを取得するためには、型キャストが必要です。
sub add : void ($self : self, $object : ojbect) { ... } sub get : object ($self : self, $index : int) { ... }
my $list = SPVM::ObjectList->new; $list->add("hello!"); my $str = (string)$list->get(0);
残念ですが、継承はありません。SPVMでは「汎用オブジェクト型」「汎用オブジェクト配列型」「コールバック型」を使って、ポリモーフィズムを実現します。
サブルーチンのオーバーロードはありません。サブルーチンは、サブルーチン名で一意的に識別されます。
採用されていない最も大きな理由は、Perl自体が型を持たないために、PerlからSPVMのサブルーチンへ渡す値の型が決定できないためです。
このためSPVMでは、サブルーチン名によって、戻り値と引数の型がわかるように設計されています。
はい、浮動小数点の表現方法、および演算は、処理系に依存します。
二つの連続したアンダーラインは、エクステンションにおいて、パッケージ名とサブルーチン名の区切りとして利用されるためです。
エクステンションはC言語で書かれます。
# SPVMのサブルーチン package Foo::Bar { sub baz : void () { } }
// エクステンションにおける関数名 SPNATIVE__Foo__Bar__baz(SPVM_ENV* env, SPVM_VALUE* stack) { }
SPVMの「Foo::Barパッケージのbazサブルーチン」はエクステンションの「SPNATIVE__Foo__Bar__baz」に対応します。これは1対1に対応し、相互に名前の変換が可能です。
残念ながら、SPVMからPerlのサブルーチンを呼び出すことはできません。
一度代入した値を変更できなくする機能はありませんが、他の機能の組み合わせで実現することができます。
コンパイル時定数で数値型の場合
定数サブルーチンを使用します。
package Foo { sub VAL : double () { return 5.1234; } }
コンパイル時定数でオブジェクト型の場合
パッケージ変数を定義します。パッケージ変数に読み込み用のアクセッサを定義します。BEGINブロックを使って、パッケージ変数を初期化します。
package Foo { our $POINT : ro int; BEGIN { $POINT = Point->new; } }
はいできます。
パッケージ変数を定義します。BEGINブロックを使って、パッケージ変数を初期化します。singletonメソッドで、オブジェクトを返します。
package Foo { our $SINGLETON : Foo; BEGIN { $SINGLETON = new Foo; } sub singleton : Foo () { return $SINGLETON; } }
コア機能、標準関数、標準モジュールについては、作者が決定を行っています。その範囲の中であれば、開発への参加が可能です。
バグ報告、ベンチマーク、言語評価、ブログなどでの紹介は歓迎です。
「README」の中に開発手順が記載されています。
木本裕紀(kimoto.yuki@gmail.com)
moti(motohiko.ave@gmail.com)
バグ報告はGitHubのIssueで行うことができます。