SPVMが少しづつ動くようになってきた
Perlで数値演算と配列演算を速くするために開発しているSPVMが言語として少しづつ動くようになってきた。これが、Perlにうまく組み込めるかどうかは、研究段階なんだけど、ちょっとできたところまでを少し紹介。
SPVMはStatic Perl Virtual Matchineの略です。静的型を持ったPerl風の言語をPerlから呼び出せるようにすることを目的とした研究です。
今日は試験用のスクリプトを紹介。変数はすべて静的型を持っていて、自動的な型変換は行われません。型推論の機能を備えているので、変数宣言は省略できます。できるだけPerlに近い表現で書けるようになっています。
package Main { sub main () : int { my $num1 = 2; my $num2 = 5; my $num3 = sum($num1, $num2); std::println_int($num3); return 0; } sub sum ($num1 : int, $num2 : int) : int { my $num3 = $num1 + $num2; return $num3; } }
これが実行できます。出力結果は以下のようになります。
7
Test.spvmのファイルの中を見れば、今実装されている機能が見れます。一部抜粋。できる限りPerlの表現に近づけた静的言語になっています。
use Test::EnumA; use Test::EnumB; use Test::EnumC; use Test::EnumD; use Test::Simple; use Test::Minimal; package Test { sub main($mvar : int) : int { std::println_int(Test::EnumD->THREE); std::println_int(Test::EnumD->FORE); std::println_int(std::test_call1(4)); # Core functions { std::print_byte((byte)1); std::print_short((short)1); std::print_int(1); std::print_long(1L); std::print_float(1f); std::print_double(1.0); std::println("end"); } { my $nums = malloc int[258]; my $len = len $nums; for (my $i = 0; $i < $len; $i++) { $nums[$i] = $i; } for (my $i = 0; $i < $len; $i++) { $nums[$i] = $i; } } { my $nums = malloc int[2000000]; my $len = len $nums; my $i = 0; for ($i = 0; $i < $len; $i = $i + 1) { $nums[$i] = $i; } std::println_int($i); std::println_int($nums[$i - 1]); } # Object to get long field is undef #{ # my $obj : Test::Minimal; # $obj{x} = 1L; #} # Object to get long field is undef #{ # my $obj : Test::Minimal; # $obj{x}; #} # Index is out of range #{ # my $nums = malloc int[3]; # $nums[3] = 1; #} # Index is out of range #{ # my $nums = malloc int[3]; # $nums[-1] = 3; #} # Array is undef #{ # my $nums : int[]; # $nums[0] = 1; #} # Index is out of range #{ # my $nums = malloc int[3]; # $nums[3]; #} # Index is out of range #{ # my $nums = malloc int[3]; # $nums[-1]; #} # Array is undef #{ # my $nums : int[]; # $nums[0]; #} { my $string : string = "abc"; } { my $strings : string[] = malloc string[5]; $strings[0] = "abc"; $strings[1] = "ppp"; std::println($strings[1]); } { malloc Test::Minimal; } { my $obj1 = malloc Test::Minimal; my $obj2 : Test::Minimal; my $obj3 : Test::Minimal = undef; } # Increment byte { my $num = (byte)1; $num++; std::println_byte($num); } # Increment short { my $num = (short)1; $num++; std::println_short($num); } # increment int { my $var = 4; $var++; $var--; --$var; ++$var; } # Increment long { my $var = (long)4; $var++; $var--; --$var; ++$var; } try { sum0(1, 2); 3; sum0(3, 4); 1; } catch ($error : byte[]) { sum0(5, 6); 2; } { my $nums = malloc int[3]; $nums[0] = 1; $nums[1] = 2; $nums[2] = 3; my $total = std::sum_int($nums); std::println_int($total); } { my $string = "ace"; std::println($string); } { my $num = (byte)3; std::println_byte($num); my $num2 = (long)1 + (long)$num; std::println_long($num2); } # get and set field { my $m = malloc Test::Minimal; $m{x} = 2L; $m{y} = 3L; std::println_long($m{x}); std::println_long($m{y}); } # Free when assignment { my $m = malloc Test::Minimal; $m = malloc Test::Minimal; } # left is object, right is undef { my $obj : Test::Minimal = undef; } if (1) { 2; if (3) { 4; } elsif (8) { 9; } else { 5; } } else { 6; } 7; std::println_int(sum0(1, 1)); std::println_int(sum2(1, 2)); # Constant float std::println_float(0.3f); std::println_float(1f); std::println_float(2f); std::println_float(1.2f); # Constant double std::println_double(0d); std::println_double(1d); std::println_double(1.2); # Constant int std::println_int(-2147483648); std::println_int(-32769); std::println_int(-32768); std::println_int(-129); std::println_int(-128); std::println_int(-2); std::println_int(-1); std::println_int(0); std::println_int(1); std::println_int(2); std::println_int(3); std::println_int(4); std::println_int(5); std::println_int(6); std::println_int(127); std::println_int(128); std::println_int(255); std::println_int(256); std::println_int(32767); std::println_int(32768); std::println_int(65535); std::println_int(65536); std::println_int(2147483647); # Constant long std::println_long(-1L); std::println_long(0L); std::println_long(1L); std::println_long(2L); std::println_long(9223372036854775807L); std::println_long(-9223372036854775807L); std::println_long(-2147483648L); std::println_long(-32769L); std::println_long(-32768L); std::println_long(-129L); std::println_long(-128L); std::println_long(-2L); std::println_long(-1L); std::println_long(0L); std::println_long(1L); std::println_long(2L); std::println_long(3L); std::println_long(4L); std::println_long(5L); std::println_long(6L); std::println_long(127L); std::println_long(128L); std::println_long(255L); std::println_long(256L); std::println_long(32767L); std::println_long(32768L); std::println_long(65535L); std::println_long(65536L); std::println_long(2147483647L); std::println_long(0xFFL); "abc"; # Table switch int { my $num = 3; switch($num) { case Test::EnumD->THREE: std::println_int(1); case Test::EnumD->FORE: std::println_int(2); case 5: std::println_int(3); default: std::println_int(5); } } # Lookup switch int { my $num = 3; switch ($num) { case 1: std::println_int(1); case 3: std::println_int(2); case 10000: std::println_int(2); default: std::println_int(5); } } # { # my $num = 5; # switch($num) { # default: # std::println_int(5); # } # } # my $num; # my $num1 = undef; if (1) { 3; if (2) { 4; } 5; } 6; my $simple3 : Test::Simple = malloc Test::Simple; std::println_int($simple3->get_x()); $simple3->get_x; $simple3{y} = 2; $simple3{x}; $simple3{y}; my $simple2 : Test::Simple = malloc Test::Simple; if (1) { } if (1 == 1) { } if (1 != 1) { } if (1 <= 1) { } if (1 < 1) { } if (1 >= 1) { } if (1 > 1) { } if (!1) { } if (1L) { } if (1.5) { } if ($simple2) { } if (undef) { } if ($simple2 == undef) { } if (undef == $simple2) { } if (undef == undef) { } if (undef != undef) { } if (5L || 6L) { } if (5L && 6L) { } if (!1L) { } if (1L > 2L) { 3L; 4L; }; 5L; if (1.2 > 2.0) {}; if (1.2 >= 2.0) {}; if (1.2 < 2.0) {}; if (1.2 <= 2.0) {}; if (1.2 == 1.0) { } if (1.2 != 2.0) { }; if (1 > 2) {}; if (1 >= 2) {}; if (1 < 2) {}; if (1 <= 2) {}; if (1 == 1) { } if (1 != 2) { }; { my $nums = malloc int[3]; $nums[0] = 13; $nums[1] = 14; std::println_int($nums[0]); std::println_int($nums[1]); } { my $nums : long[] = malloc long[3]; $nums[0] = 11L; $nums[1] = 12L; std::println_long($nums[0]); std::println_long($nums[1]); std::println_int(len $nums); my $nums_length : int = len $nums; } my $simple : Test::Simple = malloc Test::Simple; my $v1 : int; my $v2 : int; my $v3 : int; $v3 = $v2 = $v1 = 5; 100; 1000; 1 << 2; 1 >> 2; 1 >>> 2; Test::EnumA::ONE(); Test::EnumA::TWO(); Test::EnumA->ONE(); Test::EnumA->ONE; # Basic operation byte { } # Basic operation short { } # Basic operation int { 1 ^ 4; 1 & 2; 1 | 2; -3 + +2; 3 - (1 + 2); 5 + 19; 1 + 2; 1 - 2; 1 * 2; 1 / 3; 4 % 6; } # Basic operation long { 1L ^ 4L; 1L & 2L; 1L | 2L; -3L + +2L; 3L - (1L + 2L); 5L + 19L; 1L + 2L; 1L - 2L; 1L * 2L; 1L / 3L; 4L % 6L; } 1.2 / 3.0; 1.2f / 3.0f; 1.2 * 4.0; 1.2f * 4.0f; 1.2 + 3.0; 1.2f + 3.0f; 1.2 - 3.0; 1.2f - 3.0f; # Compare long { if (1L > 2L) {}; if (1L >= 2L) {}; if (1L < 2L) {}; if (1L <= 2L) {}; if (1L == 1L) { } if (1L != 2L) { }; } my $bar : double = (double)1; undef; Test::sum0(1, 2); sum0(1, 2); test1(); while (1) { 1; last; } # for (my $i : int = 0; $i < 5; $i = $i + 1) { # 1; # last; # next; # } { my $num0 = (byte)0; my $num1 = (byte)1; my $num2 = (byte)2; my $num3 = $num0 + $num1 + $num2; std::println_byte($num3); } { my $num0 = (short)0; my $num1 = (short)1; my $num2 = (short)2; my $num3 = $num0 + $num1 + $num2; std::println_short($num3); } # die "ERROR"; return $mvar + 3; } sub test1 () : int { my $num0 = 1; my $num1 = 2; my $num2 = 3; my $num3 = 4; my $num4 = 5; return 0; } sub sum4($num1 : long, $num2 : long) : long { return $num1 + $num2; } sub sum3 ($simple : Test::Simple, $foo : long, $bar : float) : int { if (3) { } if (3) { 1; } elsif (4) { 4; } else { } if (3) { 1; } elsif (4) { 4; } elsif (5) { } else { } if (1) { } else { } return 2; } sub sum1 ($num1 : long, $num2 : long) : long { return $num1 + $num2; } sub sum0($num1 : int, $num2 : int) : int { return $num1 + $num2; } sub sum2 ($num1 : int, $num2 : int) : int { # die "Error"; my $num3 = sum0($num1, $num2); return $num3 + 3; } sub increfcount($test : Test::Minimal, $num : int) : int { my $aaa = malloc Test::Minimal; } sub decinctest ($num1 : Test::Minimal, $num2 : int, $num3 : Test::Minimal) : int { { my $num4 = malloc Test::Minimal; my $num5 = malloc Test::Minimal; } return 2; } sub return_object() : Test::Minimal { my $obj0 = malloc Test::Minimal; { my $obj1 = malloc Test::Minimal; my $obj2 : Test::Minimal; my $obj3 : Test::Minimal = undef; return $obj2; } } }