こんにちは!んだです。
今日も今日とて『Writing A Compiler In Go』の読書録を書いていきます。 ほんなごて、コンパイラは楽しいですね。
前回は、Conditionalのcompilerについて眺めていきましたので、今回はVMについてみていきます。Executing Jumps!!です。
TestCase
まずは、いつものようにTestCaseを眺めてまいりましょう。
func TestConditionals(t *testing.T) { tests := []vmTestCase{ {"if (true) { 10 }", 10}, {"if (true) { 10 } else { 20 }", 10}, {"if (false) { 10 } else { 20 } ", 20}, {"if (1) { 10 }", 10}, {"if (1 < 2) { 10 }", 10}, {"if (1 < 2) { 10 } else { 20 }", 10}, {"if (1 > 2) { 10 } else { 20 }", 20}, } runVmTests(t, tests) }
if文が並んでおりますね。 では、どうやってVM上で処理していくかをみていきましょう。
OpJump
まずは、OpJumpから
// vm/vm.go func (vm *VM) Run() error { for ip := 0; ip < len(vm.instructions); ip++ { op := code.Opcode(vm.instructions[ip]) switch op { // [....] case code.OpJump: pos := int(code.ReadUnit16(vm.instructions[ip+1:])) ip = pos - 1
ip = pos - 1
は、何をしているのでしょうか?
OpJumpでは、Jump先まで命令を進めたいわけですが、ip = pos - 1
と一つポジションをずらしておかないと、次のループに入った時にインクリメントされていまい、Jump先の一個に進んでしまいます。
そのため、ip = pos - 1
で一つずらしておくわけですね。
OpJumpNotTruthy
続いては、OpJumpNotTruthyです。
// vm/vm.go func (vm *VM) Run() error { for ip := 0; ip < len(vm.instructions); ip++ { op := code.Opcode(vm.instructions[ip]) switch op { // [....] case code.OpJumpNotTruthy: pos := int(code.ReadUnit16(vm.instructions[ip+1:])) ip += 2 condition := vm.pop() if !isTruthy(condition) { ip = pos - 1 }
テストケースを眺めながら追ってみましょう。
inputとして
if (true) { 10 } else { 20 };
があったときに、Bytecodeは以下のように生成されます。
0000:code.Make(code.OpTrue), 0001:code.Make(code.OpJumpNotTruthy, 10), 0004:code.Make(code.OpConstant, 0), 0007:code.Make(code.OpJump, 13), 0010:code.Make(code.OpConstant, 1), 0013:code.Make(code.OpPop),
まずは、以下でジャンプ先を取得して、posに入れておきます。続いて、オペランド分ipを移動します。
pos := int(code.ReadUnit16(vm.instructions[ip+1:])) ip += 2
次は、条件式をPopしてきて真偽値を判定します。
falseの場合には、ip = pos - 1
としてあげることで、0009からスタートすることにます。
ループ時に1つipがインクリメントされるので、ジャンプ先である0010に移動できるというわけです。
condition := vm.pop() if !isTruthy(condition) { ip = pos - 1 }
ということでテストも通りまして、条件分岐も突破です。
まとめ
以上で条件分岐も完了です。
前回までの中置式や前置式と違って、JUMP命令がある分やや複雑ではあるのですが、一つ一つみていくとやっていることはシンプルです。
次回は5章となり後半です。
どんな実装が出てくるか、興奮してきますね。
僕から以上。あったかくして寝ろよ。