2012-12-06
■ [rumcoke] RumCokeという言語を作っています
altjs Advent Calendar 6日目の記事です。
「altjs」とは、JavaScriptにコンパイルされる or JavaScriptで実装された言語(処理系)のこと。 僕自身もBiwaSchemeというaltjs処理系を作っていますが、 秋のILC参加中に「もしCoffeeScriptがS式ベースだったら...?」というアイデアを思いついて、RumCokeというLisp風のaltjs言語を作り始めました。
例
Hello Worldです。
(define util (require "util"))(util.puts "Hello, world!")
あと、処理系自身がRumCokeで書かれているので、いまのところそれが一番大きな例です。 このプログラムが、このように変換されます。
RumCokeの特徴
- JSの薄いラッパー言語である
CoffeeScriptやTypeScriptのように、なるべくJSに近いsemanticsを意識しています。
- Scheme風の構文
JSはLisp-1なんで、Schemeが合うかなと思いました。
- Lispだけどリストがない
S式がArrayベースだったらどうなるんだろう?という実験のつもりでしたが、昨日のJSLispがもうやってましたね…。
- 構文木レベルのマクロ
SibilantJSのように文字列レベルのマクロだったり、 LispyScriptのように任意のコードが書けないものと違って、 ちゃんと「構文木を構文木に変換するもの」としてマクロが書けます。*1
- self-hosting
GHCやCoffeeScriptのように、その言語自身で自分の処理系を書くというのをやってみたかったのでした。 手順としては、
- まず素のJSで処理系を書く (このとき、なるべく使用するJSの構文要素を減らすことが望ましい)
- 簡単なRumCokeプログラムをJSに変換できるようにする
- 現在の処理系の1行目を生成するようなRumCokeプログラムを書く
- それをJSに変換できるように処理系を拡張する
- 現在の処理系の2行目を生成するようなRumCokeプログラムを書く
- それをJSに変換できるように処理系を拡張する
- ...
- 現在の処理系の最後の行を生成するようなRumCokeプログラムを書く
- それをJSに変換できるように処理系を拡張する
- さあ、手元には現在の処理系を生成するようなRumCokeプログラムがあるぞ。それを現在の処理系でJSに変換するぞ。
- 生成されたJSは、現在の処理系と全く同じであるはずだ。おめでとう、君はself-hostingに成功した。
- 古い処理系はもう要らないので捨てる。ここからは、RumCoke版の処理系だけをメンテすればいい。
という感じになります。Quineみたいでややこしいけど非常に面白かった。 以降は、処理系に新しい機能を追加する→その機能を使って処理系をリファクタリングする、みたいなループになります。
実装状況
quasiquoteを足そうとしたところで止まっています。そのうち暇を見つけて再開する予定です。
JS言語の作成に関してはいろいろ新たなノウハウを得たので、今月中にまた何か書くかもしれません。
*1 と言って、define-macroを用意してないのでユーザレベルではまだ書けないですが