Parrot についてのメモ
とりあえずメモ。
PIR
PIR(Parrot Intermediate Representation)は Parrot の中間レベルのアセンブリ言語。
使える機能としては
- ガーベッジ・コレクション
- コンティニュエーション
- レキシカルバインディング
- オブジェクト指向
- 多値
- 例外
- テイルコール
- コルーチン
- UTF-8 UTF-16 のサポート
などがある。
.sub hello
.local pmc en, jp
$P0 = newclass "EnHello"
$P1 = newclass "JpHello"
en = new "EnHello"
jp = new "JpHello"
en.'hello'("Parrot")
jp.'hello'(utf8:unicode:"おーむちゃん")
.end
.namespace [ "EnHello" ]
.sub 'hello' :method
.param string name
$S0 = "Hello, "
$S0 .= name
$S0 .= "!"
say $S0
.end
.namespace [ "JpHello" ]
.sub 'hello' :method
.param string name
$S0 = utf8:unicode:"こんにちは、"
$S0 .= name
$S0 .= utf8:unicode:"♪"
say $S0
.end
変数
レジスタ
$[INSP]\d+
変数(名前付き変数)
named variables: int, num, string, pmc
pmc = "PolyMorphic Container".
= "Parrot Magic Cookies"?
named variables のスコープはサブルーチン。
symbol variables のスコープもサブルーチン。
グローバルにしたい場合は set_global と get_global を使う。
= でキャストが可能
$P0 = new 'Integer'
$P0 = 5
$S0 = $P0
PIR のコードは全て .sub と .end の中(サブルーチン)に書く。
メイン関数は :main で指定。指定がなければファイルの先頭の .sub がメイン関数となる。
say できるためには .sub get_string :vtable :method
$S0 = self.'symbol-name'() .return($S0) .end を実装する。
ネームスペースとスコープ
- .HLL 小文字で指定する
- set_hll_global
- get_hll_global
- get_hll_namespace
- get_root_namespace
- 'export_to'
異なる namespace の sub は直接呼べない。ただし root namespace(.namespace [])の sub は直に呼べる。
.sub main
## 呼べない fb()
## 呼べない $P0 = get_global "fb"
$P0 = get_global ["a";"b"], "fb"
$P0()
froot()
.end
.namespace []
.sub froot
say "in root"
.end
.namespace ["a"]
.sub fa
say "in a"
froot()
.end
.namespace ["a";"b"]
.sub fb
say "in b"
## 呼べない fa()
## 呼べない $P0 = get_global "fa"
## 呼べない $P0 = get_global ["a"], "fa"
## 呼べない $P0 = get_root_global "fa"
## 呼べない $P0 = get_root_global ["a"], "fa"
## 呼べない $P0 = get_hll_global "fa"
$P0 = get_hll_global ["a"], "fa"
$P0()
froot() # root ネームスペースは直に呼べる
.end
サブルーチン
初期化サブルーチンの雛形。
.namespace []
.sub '' :anon :init :load
# ...
.end
:anon はネームスペースに登録されない。gensym に似てる。
クロージャ
:outer で環境を指定した sub を .const 'Sub' でつかまえて newclosure する。
.lex するレジスタは pmc でないといけない。
他のネームスペースの sub をつかまえるときは find_name を使う。
.sub main
$P0 = make_closure(10)
$P1 = make_closure(100)
$P0() # 11
$P1() # 101
$P0() # 12
$P1() # 102
.end
.sub make_closure
.param pmc n
.lex 'n', n
.const 'Sub' foo_sub = "foo"
$P1 = newclosure foo_sub
.return($P1)
.end
.sub foo :outer(make_closure)
$P0 = find_lex 'n'
$P0 += 1
say $P0
.end
ダイナミックスコープ
outer の指定は不要で find_dynamic_lex と store_dynamic_lex でアクセスする。
.sub foo
.local pmc var
var = box "foo value"
.lex 'var', var
say var
bar()
say var
.end
.sub bar
.local pmc var
var = find_dynamic_lex 'var'
say var
$P1 = box "new value"
store_dynamic_lex 'var', $P1
.end
多値
.return に複数の値を指定し、複数の変数を括弧で左辺とする。
.sub main
($P0, $P1, $P2) = foo()
say $P0
say $P1
say $P2
.end
.sub foo
.return(1, "a", utf8:unicode:"あ")
.end
文字列
ユニコードが使える。
utf8:unicode:"UTF-8 の文字列"utf8:unicode 意外にも utf16:unicode, ascii, binary も使える。
マクロ
.macro から .endm で定義する。引数は . を付けると展開される。呼び出し時は .macro_name(arg1,...) と、やはり . を付ける。
.macro macro_name(arg1, arg2, ... argn)
中身
.endm
インクルードとロード
- .include
- load_bytecode
Evaluating a Code String
.sub main
.local pmc compiler, generated1, generated2
.local string source1, source2
compiler = compreg "PIR"
source1 = ".sub foo\n$S1 = 'in eval 1'\nsay $S1\n.end"
source2 = ".sub foo\n$S1 = 'in eval 2'\nsay $S1\n.end"
generated1 = compiler(source1)
generated2 = compiler(source2)
generated1() # in eval 1
generated2() # in eval 2
foo() # in eval 2
$P1 = generated1
$P1() # in eval 1
.end
トレース
PASM を出力する
-o オプションで PASM を出力できる。-o - で標準出力に PASM をはく。
parrot -o - a.pir
0 件のコメント:
コメントを投稿