WASMがスタックマシンでありWATがS式であり
WASMのテキスト表現(つまりアセンブリ言語)WATについて、MDNのイントロダクション的なドキュメントを読んでいる。WASMはスタックマシンで、WATはS式だ。だからなのかわからないが、見た目としてスタックマシンらしい後置記法も、Lispぽい前置記法もできる。
(module
(func $add (param $lhs i32) (param $rhs i32) (result i32)
local.get $lhs
local.get $rhs
i32.add)
(export "add" (func $add))
)
上記はMDNにも出ている例で、単純にふたつの数を足す関数を持つモジュールだ。このモジュールは、こうもかける。
(module
(func $add (param $lhs i32) (param $rhs i32) (result i32)
(i32.add (local.get $lhs) (local.get $rhs)))
(export "add" (func $add))
)
前者で関数$addのbodyは、
local.get $lhs
local.get $rhs
i32.add
と書かれている。これは、$lhsとラベルが付けられた引数をスタックにつみ、$rhsを同じくスタックにつみ、i32.addという組み込みの(という表現が適切なのかわかっていないが)関数を呼び出す、という意味だ。スタックに積まれたふたつの引数は消費され、加算された結果が残る。
後者では、関数のbodyはこう書かれている。
(i32.add (local.get $lhs) (local.get $rhs))
ぱっと見で意味は読み取れるが、スタックマシンの痕跡は消えている。そして、これは前者と完全に等価のようだ(wasmに変換した結果の差もないし、wasm2watの結果も差がない)。つまり、「引数をスタックに積んでから関数を呼ぶ」という処理を、見た目はLispぽい後置記法で書ける、ということだ。
これはWATの仕様なんだろうけど、手で書くことはおそらくほぼ想定していないであろうWATでこの「便利」さ必要だったのかなあ、と疑問に思う。まだWASMのことをほとんど何も知らないので、見当違いな疑問なのかもしれない。
7/6 追記
この件はWASMの仕様書に記載があった。S式表現の方を「Folded Instruction」という。
Instructions can be written as S-expressions by grouping them into folded form.
そして、これは純粋に構文糖衣とのこと。「手で書くことはおそらくほぼ想定していない」という私の推測が間違っていたようだ。
Folded instructions are solely syntactic sugar, no additional syntactic or type-based checking is implied.
WASMのSpecのIssueにはこんな例もあった。
All of these:
(i32.add (i32.const 1) (i32.const 2) (i32.const 3)) (i32.const 1) (i32.add (i32.const 2) (i32.const 3)) (i32.const 1) (i32.const 2) (i32.add (i32.const 3)) (i32.const 1) (i32.const 2) (i32.const 3) (i32.add)Are sugar for:
i32.const 1 i32.const 2 i32.const 3 i32.addEven though i32.add only has only two operands, all of these cases are valid in the s-expression format.