研究目的

研究目的

現在開発の進んでいる言語にスクリプト言語のRakuがある. Rakuは起動時間がPerl5やPython, Rubyなどの主要なスクリプト言語に比べて非常に低速である. RakuはコンパイラがRakuそのもので書かれているため, 毎回コンパイラのロードとコンパイル, JITコンパイルを繰り返すことになる. 最近のスクリプト言語では, コンパイラが自身で書かれているケースが多い. 例えば, PyPy, Go言語, Haskellなどである. そこで, この問題を解決するために, 既にコンパイラをロードしてあるサーバーを用意し, サーバー上でスクリプト言語を実行する手法を提案している. Rakuに対しては, 当研究室にてAbyssサーバーを開発している.

# やったこと

  • 今までhomebrewでinstallしたrakudo-starを使っていたが, githubからroastをcloneしてbuildした.
    • brew unlink rakudo-starでrakudo-starを無効化したり, githubからzefをclone&buildしたり.
  • use v6;がどのように実装されているのかを調べた. (後述)
  • EVALFILEを参考にEvalAsMod.pm6を作成した.
1
2
3
4
5
6
7
8
9
unit module EvalAsMod;
use MONKEY-SEE-NO-EVAL;

sub EVALASMOD($filename, :$lang = 'Raku', :$check) is export {
    my $code = 'my module Mod {'~"\n"~slurp($filename)~'}';
    $code = $code.lines.map({$_ unless $_ ~~ /^use\sv6.*$/});
    $code = $code.join("\n");
    EVAL $code, :$lang, :$check, :context(CALLER::), :$filename;
}
  • EvalAsMod.pmを使用して名前空間が切られているか実験した. (後述)
  • 複数のスクリプトをServerに送れるようclient.p6に手を加えた.

# use v6;がどのように実装されているのかを調べた.

  • このページで下記の記述を発見. use v6;のコードはコメント行を除いた中で最初の行でなければならないっぽい.

we’ll require that a “use v6.X” is the first non-comment, non-whitespace declaration in a file. Anything later will trigger a “too late to switch Raku language version”.

  • use v6;を複数回宣言して出てくるerror文Too late to switch language version.がどこで定義されているのか調べた.

  • rakudo/src/core.c/Exception.pm6にてX::Language::TooLateとして定義されている.

  • X::Language::TooLateは以下で呼び出されている.

    1. rakudo/src/perl6/Grammar.nqp
    2. rakudo/src/perl6/World.nqp
      • World.nqpではX::Language::TooLateの部分がコメントアウトされている.
  • Grammar.nqpのコードを読んでみた.

    • X::Language::TooLatetoken statement_controlの中で使われている.
      • statement_controlはmoduleのimportなどを解釈する役割?
    • typed_panicという関数の引数にされている.
      • 同じくGrammar.nqp内に定義されていた関数.
    • 読んでもよくわからなかった…

# EvalAsMod.pmを使用して名前空間が切られているか実験した.

  • 実験用の2つのスクリプトを用意.
1
2
3
4
5
6
7
use v6;

our sub add ($a, $b) {
    say $a + $b;
}

add 7, 11;
1
2
3
4
5
6
7
use v6;

our sub add ($a, $b) {
    say $a ~ $b;
}

add 'hello', 'world';
  • EVALFILEでスクリプトを評価するverのAbyss::Server.pm6で上の2つのスクリプトを実行する.
    • Redeclaration of routine 'add' (already defined in packageAbyss::Server). Did you mean to declare a multi-sub?というerrorがでた.
  • EVALASMODでスクリプトを評価するverのAbyss::Server.pm6で上の2つのスクリプトを実行する.
    • errorが出ずに無事結果を出力. 同じスクリプトを複数回実行させても大丈夫.
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy
min.js"integrity="sha256-UKkzOn/w1mBxRmLLGrSeyB4e1xbrp4xylgAWb3M42pU="crossorigin="anonymous" defer > an class="line">typedef struct node { int key; /* キー */ int color; /* 色 */ struct node *parent; /* 親ノード */ struct node *left; /* 左の子ノード */ struct node *right; /* 右の子ノード */ } Node; /* NILノード */ Node *NIL; /* プロトタイプ宣言 */ void leftRotate(Node **root, Node *x); void rightRotate(Node **root, Node *x); void insertFixup(Node **root, Node *z); void insertNode(Node **root, Node *z); void transplant(Node **root, Node *u, Node *v); Node *minimum(Node *x); void deleteFixup(Node **root, Node *x); void deleteNode(Node **root, Node *z); /* 初期化 */ void init() { NIL = (Node *)malloc(sizeof(Node)); NIL->color = BLACK; } /* 左回転 */ void leftRotate(Node **root, Node *x) { Node *y = x->right; x->right = y->left; if (y->left != NIL) { y->left->parent = x; } y->parent = x->parent; if (x->parent == NIL) { *root = y; } else if (x == x->parent->left) { x->parent->left = y; } else { x->parent->right = y; } y->left = x; x->parent = y; } /* 右回転 */ void rightRotate(Node **root, Node *x) { Node *y = x->left; x->left = y->right; if (y->right != NIL) { y->right->parent = x; } y->parent = x->parent; if (x->parent == NIL) { *root = y; } else if (x == x->parent->right) { x->parent->right = y; } else { x->parent->left = y; } y->right = x; x->parent = y; } /* 親子関係の修正と色の変更 */ void insertFixup(Node **root, Node *z) { Node *y; while (z->parent->color == RED) { if (z->parent == z->parent->parent->left) { y = z->parent->parent->right; if (y->color == RED) { z->parent->color = BLACK; y->color = BLACK; z->parent->parent->color = RED; z = z->parent->parent; } else { if (z == z->parent->right) { z = z->parent; leftRotate(root, z); } z->parent->color = BLACK; z->parent->parent->color = RED; rightRotate(root, z->parent->parent); } } else { y = z->parent->parent->left; if (y->color == RED) { z->parent->color = BLACK; y->color = BLACK; z->parent->parent->color = RED; z = z->parent->parent; } else { if (z == z->parent->left) { z = z->parent; rightRotate(root, z); } z->parent->color = BLACK; z->parent->parent->color = RED; leftRotate(root, z->parent->parent); } } } (*root)->color = BLACK; } /* ノードの挿入 */ void insertNode(Node **root, Node *z) { Node *y = NIL; Node *x = *root; while (x != NIL) { y = x; if (z->key < x->key) { x = x->left; } else { x = x->right; } } z->parent = y; if (y == NIL) { *root = z; } else if (z->key < y->key) { y->left = z; } else { y->right = z; } z->left = NIL; z->right = NIL; z->color = RED; insertFixup(root, z); } /* ノードの置換 */ void transplant(Node **root, Node *u, Node *v) { if (u->parent == NIL) { *root = v; } else if (u == u->parent->left) { u->parent->left = v; } else { u->parent->right = v; } v->parent = u->parent; } /* 最小値を持つノードを探索 */ Node * minimum(Node *x) { while (x->left != NIL) { x = x->left; } return x; } /*削除のための修正 */ void deleteFixup(Node **root, Node *x) { Node *w; while (x != *root && x->color == BLACK) { if (x == x->parent->left) { w = x->parent->right; if (w->color == RED) { w->color = BLACK; x->parent->color = RED; leftRotate(root, x->parent); w = x->parent->right; } if (w->left->color == BLACK && w->right->color == BLACK) { w->color = RED; x = x->parent; } else { if (w->right->color == BLACK) { w->left->color = BLACK; w->color = RED; rightRotate(root, w); w = x->parent->right; } w->color = x->parent->color; x->parent->color = BLACK; w->right->color = BLACK; leftRotate(root, x->parent); x = *root; } } else { w = x->parent->left; if (w->color == RED) { w->color = BLACK; x->parent->color = RED; rightRotate(root, x->parent); w = x->parent->left; } if (w->right->color == BLACK && w->left->color == BLACK) { w->color = RED; x = x->parent; } else { if (w->left->color == BLACK) { w->right->color = BLACK; w->color = RED; leftRotate(root, w); w = x->parent->left; } w->color = x->parent->color; x->parent->color = BLACK; w->left->color = BLACK; rightRotate(root, x->parent); x = *root; } } } x->color = BLACK; } /* ノードの削除 */ void deleteNode(Node **root, Node *z) { Node *y = z; Node *x; int y_original_color = y->color; if (z->left == NIL) { x = z->right; transplant(root, z, z->right); } else if (z->right == NIL) { x = z->left; transplant(root, z, z->left); } else { y = minimum(z->right); y_original_color = y->color; x = y->right; if (y->parent == z) { x->parent = y; } else { transplant(root, y, y->right); y->right = z->right; y->right->parent = y; } transplant(root, z, y); y->left = z->left; y->left->parent = y; y->color = z->color; } if (y_original_color == BLACK) { deleteFixup(root, x); } /* ノードを削除する前に、メモリを解放 */ free(z); z = NIL; // z を NIL に設定 } /* ノードの検索 */ Node * search(Node *x, int key) { while (x != NIL && key != x->key) { if (key < x->key) { x = x->left; } else { x = x->right; } } return x; } /* ノードの挿入と削除のテスト */ int main() { /* 初期化 */ init(); /* 空のRed-Black Treeの作成 */ Node *root = NIL; /* ノードの挿入 */ insertNode(&root, (Node[]){{11, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{2, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{14, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{1, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{7, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{15, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{5, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{8, RED, NIL, NIL, NIL}}); insertNode(&root, (Node[]){{4, RED, NIL, NIL, NIL}}); /* 挿入後のTreeの出力 */ printf("insert: 11, 2, 14, 1, 7, 15, 5, 8, 4\n"); printf("output: "); printf("%d(%c) ", root->key, (root->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->key, (root->left->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->right->key, (root->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->left->key, (root->left->left->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->key, (root->left->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->right->right->key, (root->right->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->left->key, (root->left->right->left->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->right->key, (root->left->right->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->left->right->key, (root->left->right->left->right->color == RED) ? 'R' : 'B'); printf("\n"); /* ノードの削除 */ Node *z = search(root, 2); if (z != NIL) { deleteNode(&root, z); } /* 削除後のTreeの出力 */ printf("delete: 2\n"); printf("output: "); printf("%d(%c) ", root->key, (root->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->key, (root->left->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->right->key, (root->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->left->key, (root->left->left->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->key, (root->left->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->right->right->key, (root->right->right->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->left->key, (root->left->right->left->color == RED) ? 'R' : 'B'); printf("%d(%c) ", root->left->right->left->right->key, (root->left->right->left->right->color == RED) ? 'R' : 'B'); printf("\n"); return 0; }

# 実行結果

途中までは動いてそう

1
2
3
4
5
6
$ ./a.out
insert: 11, 2, 14, 1, 7, 15, 5, 8, 4
output: 7(B) 2(R) 11(R) 1(B) 5(B) 14(B) 4(R) 0(B) 0(B)
a.out(17079,0x1de8d7a80) malloc: *** error for object 0x16f207008: pointer being freed was not allocated
a.out(17079,0x1de8d7a80) malloc: *** set a breakpoint in malloc_error_break to debug
zsh: abort      ./a.out
comments powered by Disqus