Let's start Scheme

2012-09-12

マクロ戦争ひとまず終結

マクロの不具合に出会うたびに戦争だといっているだけ。それくらいR6RSのマクロ周りは複雑怪奇だと僕は思っている。

一つ前と二つ前の記事でマクロ周りの不具合が(まだまだたくさん)残っていることを書いたが、黒魔術的な処方を用いて直すことに成功したのでちょっと備忘録。

何が問題だったか?
2つの問題があって、1つはマクロを生成するマクロが生成した識別子の問題。もう一つはリネームの問題。

識別子の問題
問題点は2つ前の記事に書いたので、どう解決したかだけ。問題になるのはsyntax-caseのテンプレート部分のみだったので、どこにも束縛されていない識別子のライブラリを展開されているライブラリに置き換えるようにした。記事のコードで言えばdummyがあたかも(test-lib)内で定義されるかのように振舞うよう変更した。(本来はそうあるべきだった)。
ただ、これだけのことでも一筋縄ではいかず、結局コンパイラに手を入れたりと結構な量の修正が入った。問題だったのは、ライブラリ内で展開されるマクロがそのライブラリで定義された値を知っている必要があって、Sagittariusではその情報はコンパイラのみが知ることができるもの (マクロ展開器は構文について一切知らない)なので。これを入れたので、恐らくやろうと思えば未定義の値の参照を検出したり、未定義なexportを検出したり出来るはず。(まだやらない)

リネームの問題
これは本当に苦労した。一つ前の記事で書いた動作の修正になる。これについてはあほみたいな黒魔術を使って直した感があるが、そのうちリファクタリングしてやるという意思表示のためにどう直したかという恥をさらす。
Sagittariusにはgensymがあるのだけど、それを少し拡張して、与えられたシンボルに戻すことが出来るreversible-gensymという手続きを導入した。なぜこんなものが必要だったかと言えば、syntax-rulesやsyntax-caseにあるリテラル(キーワード?)の処理に必要だったから。単純にリネームしただけではこれらのキーワードが比較不可能なシンボルに変換されてしまうが、それはマッチする際に比較できずパターンエラーになる。なので、マッチする際にリテラルを強引に元に戻すという荒業を使っている。スマートな解決策がほしいところだが、僕の頭ではいい案が出なかった。

 問題になるかもしれない変更点
 リネーム問題の解決するに伴い、「それどうよ?」的な変更が入っている。それは、syntax-rulesもしくはsyntax-caseで定義されたリテラルが暗黙の内にマクロとして定義される。まぁ、大きな問題としては、unboundだと思って&assertionを期待していると&syntaxが飛んでくるようになった程度か?

とりあえず、0.3.6でマクロ周りが多少改善されるはず。小宇宙が少し高まっただろうか?

No comments:

Post a Comment