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;
}
}
}
Perlゼミ

