1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2013-06-17

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

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

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

実装

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

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

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

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

      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のコードは一度消しましょう。

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

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

        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の前に構造体の初期化が必要なようです。

作り直すことにする

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

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

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

まとめ

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

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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?