パターンマッチ実装奮闘記(7)

前回は、型と変数領域の確保について考えて実装することが出来ました。

1. 型と変数領域の確保について考える
2. ヴァリアント値の初期化について考える
3. パターンマッチ構文について考える

３つに分けて考える事でうまく考えが進みました。今回は、2番目の値の初期化について考えます。


## コード例

まずは、ヴァリアント値の初期化のコードの例を書いてみます。

```
val vt = TVariant(List(
  "A"->TStr(List("a"->Ti(32))),
  "B"->TStr(List("a"->Ti(32), "b"->Ti(32)))
))
EVal(t,"data", null)

EAssign(vt, EId(vt, "data"), ETag(vt, "A",List(ELdc(Ti(32), 2))) )

```
と書く事にしましょう。ETag式で初期化出来る事にするのです。この式が以下のLLVMのコードに変換出来ればよい訳です。

```
%.struct1 = type {i32, i32}	
%.struct2 = type {i32}	
%.struct3 = type {i32, %.struct2}	

  ; データの領域を確保
  %data = alloca %.struct3	
  ; data.tagのアドレスを取り出し
  %data.tag = getelementptr inbounds %struct.Data* %data, i32 0, i32 0 
  ; 値0を設定
  store i32 0, i32* %data.tag, align 4
  ; dataのaに1を設定
  %data.b = getelementptr inbounds %struct3* %data, i32 0, i32 1
  ; bからaにキャスト
  %data.a = bitcast %struct1* %data.b to %struct2*
  ; 値を設定
  %data.a.a = getelementptr inbounds %struct2* %data.a, i32 0, i32 0
  store i32 1, i32* %data.a.a, align 4
```

## 実装

コード例が出来たので実装してみます。式は以下のよう定義します。

```scala
case class ETag(t:T, id:String, ls:List[E]) extends E
```

先ほどの例をテストコードに加えて実行してみましょう。エラーが起きる箇所が修正箇所です。

まずは、alphaでエラーが起きました。alphaのEBlockの処理をコピペしてすませます。はい、妖怪コピペおじさんです。ということで、後でリファクタリングすることになりますよ。

```scala
      case e @ ETag(t: T, id:String, ls: List[E]) =>
        val (ls1, env1) = ls.foldLeft(List[E](), env) {
          case ((ls, env), a) =>
            val (a1, env1) = f(a, env)
            ((a1 :: ls), env1)
        }
        (e.copy(t, id, ls1.reverse), env1)
```

## 実装中止と方針変更

駄目だ、進めない！この先は、構造体の初期化の構文が使えるようになってから、タグの初期化に進んだ方が良いと気がつきました。焦る気持は置いておいて、構造体の初期化が出来るようになりましょう。今回の目標は変更して、構造体の初期化にします。

テストコードから、ETagのコードは一度消しましょう。

## 構造体の値設定構文を考える

構造体の値を纏めてする処理は、前に、作った事があります。前作ったコードを見て、何をしていたかを調べてみましょう。

```scala
        def o2(e: E):String = e match {
          case ELd(_,v) => ""+v
          case ELdd(_,v) => ""+v
          case ETuple(_,ls) => 
              "{"+ls.foldLeft("") {
                case ("", l) => llt(l.t) + " " + o2(l)
                case (v, l) => v + ", " + llt(l.t) + " " + o2(l)
              }+"}"
        }
        def out(t: T, e2: E) {
          (t, e2) match {
            case (t, ELd(_, v)) => asm("@"+id+" = global "+llt(t)+" " + v)
            case (t, ELdd(_, v)) => asm("@"+id+" = global "+llt(t)+" " + v)
            case (t: TStruct, v@ETuple(_, _)) => asm("@"+id+" = global "+llt(t)+" " + o2(v) )
            case (t, null) =>  asm("@"+id+" = common global "+llt(t)+" zeroinitializer")
            //case (_, EId(_, v)) => asm("@"+id+" = @"+v)
          }
        }
        out(t, e2)
```

というのがグローバル変数にはありました。グローバル変数のみの初期化だったので、ローカル変数用の処理はありませんでした。

ローカル変数の初期化はやった事がないようなので、何処でやったら良いのかを考えます。グローバル変数の初期化処理は、emit内にありました。そして、タプルの式で値を設定していました。

ローカルの構造体の初期化も、同様にタプルの式で初期化する事にしましょう。Mincamlはどうだったかと思ってみましたが、LetTupleとTupleがあってVariantはありませんでした。

やはり、Variantの前に構造体の初期化が必要なようです。

## 作り直すことにする

実は作っている自分ですらソースの内容が良くわかりません。この拡張に次ぐ拡張で分からなくなっているのと、１回目の実装なので、経験不足なので不安なのです。このまま作り続けるのは嫌になってきました。

どちらにせよ、ちゃんとパターンマッチの作り方を書くためには、最初から作る必要があります。

急がば回れです。１から作り直してみたほうがよいでしょう。作り直します。気持は焦るのですが、技術がなければ出来ないのです。

## まとめ

今回は、ヴァリアント型のデータの初期化について考えました。考えた結果、構造体の初期化の技術がないと出来ないと気がつきました。

そして、リファクタリングの必要性に迫られたので、作り直す事にしました。