フロントエンドの移行と互換性

nmosh(と、元となっているmosh)は、3種類のSchemeを持っている。

(psyntax-moshとvanilla-moshは、そもそもnmoshの導入にあたって導入した用語で、id:higepon公式の呼び方でない)
vanilla-moshはR5RS + R6RS手続き - syntax-rules + define-macroといった風情で、他2つはR6RSライブラリに対応したexpanderとなっている。
現在進めているR7RS small対応は、さらに2種類のSchemeを追加する。

  • r7x - R7RS small対応フロントエンド(R6RSのうち、syntax-caseとidentifier-macro、その他syntax関連手続きが無い)
  • cmosh - vanilla-moshのサブセット(define-macroが無い)

r7xはnmoshのデフォルトフロントエンドになるが、互換性のためR6RSライブラリを使用したスクリプトはnmoshフロントエンドでexpandする。nmoshでは既に3MiBを越える量のスクリプトが書かれていて、多くは今でも運用されているので互換性の達成は必達と言える。(特にGUIアプリが辛い...)

フロントエンド間でのマクロの共有

r7xもnmoshもexplicit-renamingスタイルのexpanderとなっている。どちらも、実行前に入力スクリプトを完全にrenameしてしまう( http://d.hatena.ne.jp/mjt/20101013/p1 )。
このため、フロントエンド間での手続きの共有は特に問題なく可能となっている。
例えば、nmosh側にはex:expand-sequence手続きがあるので、任意のライブラリ中シンボルの"vanilla-mosh"名を取得できる。

oku@cage ~
$ nmosh
nmosh top program
nmosh> (library (hoge) (export a) (import (rnrs)) (define (a) 'ok))
nmosh> (import (primitives ex:expand-sequence))
nmosh> (ex:expand-sequence '((import (hoge)) a))
((begin (ex:import-libraries-for-run '(((hoge) 0)) '(&build~1itJjL1N0~11) 0) &a~1itJjL1N0~8))
nmosh>

ここでは、(hoge)のaは&a~1itJjL1N0~8とrenameされている。
問題はマクロの共有で、今のところ良い解が無い。
異なるフロントエンドでexpandされたマクロを共有するためには、identifierを共有する必要がある。r6rsにはfree-identifier=?のような手続きがあり、R7RSのsyntax-rulesでもkeywordsとして同様のことが行えてしまう。
このため、実際のマクロを使用しなかったとしても、(さらには、当該シンボルがマクロでなかったとしても)、同じライブラリから由来するidentifierの同一性をフロントエンド間で矛盾なく共有しなければならない。
r7x側で定義したマクロをnmosh側で使うことには大きな問題はない。nmosh側では古典的なマクロが使えるので、単にnmosh的なidentifierオブジェクトを捏造して返せば、どのような方法で記述されていても正当なマクロとなる。
nmosh側で定義されたマクロをr7x側で使う良い方法がなかなか思い当たらない。r7xはsyntax-rulesをインタプリタによって実装するため、一般のscheme手続きをコードに対して作用させられない。専用のブリッジを追加するのが良いような気もするが、どの程度実用的なのかは未知数。

フロントエンド置き換えの効果

ここまでしてフロントエンドを置き換えるのは、フロントエンドで使用されるランタイムライブラリを軽量化することと、コードカバレッジやedit-and-continueのようなモダンなフロントエンド機能を実装するため。
nmoshはランタイムのロードが遅いため起動に時間がかかり、Gaucheのようなフロントエンドの多くをネイティブコードで実装している処理系に比べて起動時間の面で不利になる。
現状のnmoshでもexpanderの部分の切り離しはサポートしているが、現状のcacheメカニズムではマクロをどうしてもinstanciateしてしまう。また、nmoshはsyntax-caseを完全にSchemeコードにexpandしてしまうため、expand結果が単純に巨大になってしまうという問題もある。
というわけで、起動時間を意識し、cache awareなexpanderをゼロベースで作ることには一定の意義が有る。