rapid-scheme(R7RSで実装されたR7RSフロントエンド)がリリースされたので、Gambitに移植してみた。

rapid schemeはR7RSプログラムを入力し、マクロが展開された一本のR7RSプログラムを出力する。GambitはR5RSだけど、まぁその辺は気合で適当に。。最初はGambit付属のsyntax-rulesを使ったものの、ランタイムライブラリが正常にコンパイルされず単体のexecutbableにできなかったので、Gambit内蔵のdefine-macroに移植した。というわけでほぼR4RS部分しか使っていない。

rapid schemeをGambitに移植したのは、yuniの実装を進める上で実際に動作するフロントエンドで一度試しておきたかったため。自分でもyuni上のフロントエンドを実装しつつあるけど、(単体では)R7RS完全準拠にするつもりはあまり無いし、まだsyntax-rulesの実装が終ってないので。平たく言えば、GambitのFFIの評価を前倒しでやっておきたかったところにrapid-schemeが来た。なんというグッドタイミング。

現状でも、単体でR7RSスクリプトがそれなりに動くところまでは来ている。まだまだ未実装の手続きが多く残っているけど、rapid-schemeのテストはread系を除いて全て通っている。(readのテストはequal?がR6RS/R7RSのように循環構造で停止することを前提としているためまだ動かない) yuniのテストもevalとmatchが動かないくらいで他は大体動いている。

最大の問題は、マクロを完全に展開してしまうのでコードが膨張しコンパイルに死ぬほど時間が掛かる点。手元のPCでインタプリタをビルドするのに5分くらいかかる。普通にスクリプトを実行する分にはあまり困らないけど。。たぶん追加の最適化パスを書かないとコンパイラとして実用するのは厳しいと思う。

一応、現状のビルドでもlibgambitgscをリンクしていて、Gambitのコンパイラ機能(compile-file等の手続き)は一通り使えるようにしてある。真面目にコンパイラとして機能させるためには、ランタイムライブラリとかをどう配置するのかを考える必要がある。

LarcenyでwriteするとR6RS要素が出てくるのでGambitで正常に読めない問題 ... セクション名でもう言い切ってしまっているが、rapid-scheme自体はexpandするためにR7RS処理系を使ってbootstrapする必要がある。rapid-scheme推奨の処理系であるLarcenyを使ったが、これはR6RSでもあるので、expand後のコードをwriteするとsyntaxのようなR6RS要素もabbreviateしてしまう。 ( g6039_make-rtd ' <expression> ' ##'aux #f ) というわけで、Larceny上では何故かwrite-sharedするとabbreviateされないという挙動を利用し、かつ、write時に一旦コードをconsしなおして全体をコピーすることにした。

vectorとbytevectorがself-evaluateでない問題 R5RS/R6RSではvectorやbytevectorはself-evaluateオブジェクトでないため、プログラム中に書くにはquoteする必要がある。rapid-schemeは普通にこれらをquoteしない形で出力するため、ちょっとしたマクロ展開器を用意してそこで一緒に処理することにした。

ちなみに、Gambitにはcase-lambdaやlet-valuesも無いのでこれらも展開している。 ( define ( %%expand-input frm ) ( define ( do-expand orig head body ) ( case head (( quote ) orig ) (( let-values ) ( %%expand-input ( apply %%expand-let-values body ))) (( set!-values ) ( %%expand-input ( apply %%expand-set!-values body ))) (( case-lambda ) ( %%expand-input ( apply %%expand-case-lambda body ))) ( else ( cons head ( map expand-1 body ))))) ( define ( expand-1 frm ) ( cond (( and ( pair? frm ) ( list? frm )) ( let (( a ( car frm )) ( d ( cdr frm ))) ( cond (( pair? a ) ( map expand-1 frm )) ( else ( do-expand frm a d ))))) (( vector? frm ) `( quote , frm )) (( u8vector? frm ) `( quote , frm )) ( else frm ))) ( expand-1 frm ))