んだ日記

ndaDayoの技術日記です

Writing A Compiler In Go を読んでいく Chapter 6 Array編

こんにちは、んだです。

nda-desu.hatenablog.com

今回は、『Writing A Compiler In Go 』のChapter 6、String, Array and Hashについて書いていきます。

Array

Stringについては、IntergerLiteralとやっていることが同じなので、Arrayから見ていきます。

またArrayのcompilerについては、Arrayのオブジェクトを走査しておるだけなのでCompileの説明は省きまして、VMから眺めていきましょう。

Array VM

// 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.OpArray:
            numElements := int(code.ReadUnit16(vm.instructions[ip+1:]))
            ip += 2

            array := vm.buildArray(vm.sp-numElements, vm.sp)
            vm.sp = vm.sp - numElements

            err := vm.push(array)

            if err != nil {
                return err
            }

やっていることは他のOpcodeと同じです。異なるのは、buildArrayです。

buildArray

では、buildArrayの中身を見てみましょう

// vm/vm.go
func (vm *VM) buildArray(startIndex, endIndex int) object.Object {
    elements := make([]object.Object, endIndex-startIndex)

    for i := startIndex; i < endIndex; i++ {
        elements[i-startIndex] = vm.stack[i]
    }

    return &object.Array{Elements: elements}
}

startIndex, endIndex

まずは、startIndex, endIndexにはどんな値が入るのか?から確認しましょう。

// vm/vm.go
numElements := int(code.ReadUnit16(vm.instructions[ip+1:]))
array := vm.buildArray(vm.sp-numElements, vm.sp)

まずは、numElementsに配列の要素数を入れます。 仮に[1, 2, 3, 4] という配列だったとすると、要素数は5ですね。

で、配列の要素はすべてOpConstantなので、OpConstant命令を処理するタイミングでスタックには5個積まれるので、vm.spの値は5です。

startIndexは、vm.sp-numElementsで0が入り、endIndexは、vm.spの現在の値なので5が入るという感じですね。

stackから値を取り出そう

buildArrayの本体に戻りましょう。 startIndex, endIndexですが、以下のようにstackからの値を取り出す際に利用されます。

stackから値を取り出して、Elementsに詰めて返しています。

// vm/vm.go
for i := startIndex; i < endIndex; i++ {
    elements[i-startIndex] = vm.stack[i]
}

return &object.Array{Elements: elements}
}

spを要素分減らして、Push

最後にspを要素分減らして、Pushして完了です。

// vm/vm.go

case code.OpArray:
    numElements := int(code.ReadUnit16(vm.instructions[ip+1:]))
    ip += 2

    array := vm.buildArray(vm.sp-numElements, vm.sp)
    vm.sp = vm.sp - numElements

    err := vm.push(array)

まとめ

今回はArrayのみをまとめてみました。

ArrayはVMでどのように処理するのか?と、はじめは想像できませんでしたが、コードを追ってみると、比較的に単純な処理で出来ていますね。

再帰はすばらしいですな。

では、次回はHashについてまとめていきます。

僕から以上。あったかくして寝ろよ