トランスパイルするDSLを作りたいが何を読んだらいいのかまだよくわかっていないので、誰か教えてほしい、という記事です。
あらすじ
最近色々な技術を勉強している。具体的にはロガーの実装を読んだりRefinement Typesの勉強をしたりしている。仕事で必要というのが半分、興味半分といった具合で、素振りも兼ねてやっているので結果的に仕事で役立ったりしている。
個人的には、こういう暮らしの勉強みたいなところだと、本業で勉強しなければならないものに加えて、シナジーが生じるような勉強をしたり購買をすると良いのだろうなと思っている。 たとえばラズパイとかN100のマシンを買ってちょっとしたk3sクラスタを作ってみたりするとクラスタ技術の良い勉強になる。さらに電子工作の勉強をしておくとラズパイと組み合わせてIoT的なこともできるようになる。
そんな中、ずっと自分が勉強したいな〜と思いつつ放置している分野がコンパイラだ。オタクは絵を描けないといけないみたいな風潮が昔あったが、それのパソカタ版として、漢たるもの(?)言語の自作くらいできてほしいみたいなのがある。あと単純に、「コンパイラ作れる」といったらすごくカッコ良い気がする。 とはいえそんなに作りたい言語というのはなく、手間暇かかること請け合いの分野なので手が出せずにいる。
しかしこのごろ、ちょうど都合良く、コンパイラからはちょっと格下げになるが、DSLを作りたいと思っている。ざっくり言うと、DSLはコンパイラのうち構文解析とか型チェックをホスト言語に相乗りしてしまおうというやつだ。
なんでDSLを作りたいのかというと、最近Stormworksというゲームで遊んでおり、そのゲーム内の拡張概念としてLuaを使うようになったためだ。もう少し詳しく説明する。
Stormworksとは、巨大な箱庭の中で車・船・航空機などの乗り物を自作し、人の救助を行ったりドンパチやりあったりするシミュレーション型のゲームである。その車両の制御はちょうど既製品のICチップを使って電子工作する感覚で、既製の部品を使って行うことになるのだが、複雑な制御のためにLuaを実行できる部品もあり、マイコンと呼ばれている。
Steam:Stormworks: Build and Rescue
しかしLuaは動的な言語なので実際に機体をスポーンさせて動作させなければLuaがきちんと動くかわからないという弱点も同時に秘めている。Stormworksはやや重いゲームなので、毎回車両をスポーンさせて確認するのは手間であり、試行錯誤しにくい。頑張ってスポーンさせたらLuaの変数や関数が未定義で動作せずにやり直し、といったことを何度もやるのがストレスになってきた。動くかどうかくらい最低限最初から分かっていてほしい。いちおうゲーム内エディタには構文チェッカーがあるが、構文しか見てくれないので動く保証が全くない。未定義変数を使ったりしても普通に通ってしまう。
そこで、Luaにコンパイル(トランスパイル)する静的で強い型付け言語を作ったらどうか、と思い至った。Luaの仕様自体は簡単なので、技術的には不可能ではないだろう。しかしながら自分の実力では1からトランスパイラを書くのは難しいと考え、パーサや型システムをScalaに丸投げして、自分はFreeモナドかなんかでDSLを実装する、という方針を取ることで、比較的楽に目的を達成できるのではないかと目論んだ。
DSL作りたい
というわけでLuaにトランスパイルされるようなDSLをScala上に組みたい。ScalaでDSLを書くと「動くことが保証された」Luaに変換されて出てくる、というのがゴールとなる。
StormworksのLuaは特に何の変哲もないLuaだが、組込みでいくつかの変数(screen
とかinput
とか)があるのでこれをシステムコール的な感じで最初から呼べるようにしておくと便利なはずだ。
- 組込み変数をいくつか提供したい
- 未定義変数を呼ぼうとしたりしたらちゃんとコケてほしい
- 関数定義できたい
マクロの利用をしなければならない局面がわずかにあるかもしれないが、なるだけ使わずに済ませたいところ。
だがDSLでトランスパイラを実現した人が巷にはあまりいないため、いくつか疑問がある:
- DSLを作るとき、そもそもどういう感じで考えていけばいいのか
- だいたい普通の(?)言語製作と同じように、環境を用意して変数を割り付けて・・・みたいなことをやればいいのか?
- テストとかどういう感じでやればいいのか?
- Scalaはこの目的に適切なのか?
- Freeモナド使ったらなんとかなる?
DSLを作ったことがある読者諸賢におかれましては、「こういう感じで考えた」みたいな情報を教えてくださると助かります。
こういうの買って読んだらいいんですかね?