2009/09/26

Parrot についてのメモ

とりあえずメモ。

http://www.parrot.org/

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 件のコメント: