2014-07-24

バグは寝かせてみるといい

かなり長めに寝かせていたバグの糸口を掴んだのでメモ。

問題になるのは以下のようなコード
(import (rnrs))
(define-syntax wrap-let
  (syntax-rules ()
    ((_ expr)
     (let-syntax ((foo (lambda (x) (syntax-case x () ((_) #'expr)))))
       (foo)))))

(define-syntax wrap
  (lambda (x)
    (syntax-case x ()
      ((_ expr)
       #'(let ((temp expr))
           (wrap-let (car temp)))))))

(wrap '(a b c))
これがなぜ問題になるのかというのが重要で、展開された後を見るとなんとなく答えが出てくる。以下が展開形コードのイメージ。
(let ((temp.0 '(a b c)))
  (let-syntax ((foo (lambda (x) (syntax-case x () ((_) #'(car temp.0))))))
    (foo)))
問題はここからで、let-syntaxの中にある#'(car temp.0)が原因。Sagittariusのマクロ展開器は現状syntax-caseのパターン及びテンプレートを全てリネームする。さらにsyntaxが展開されるときにもリネームする。そうすると、元々のtemp.0は持っていない構文情報を付加されてしまい、結果的に一意の識別子になってしまう。

ならば、テンプレート変数と分かっている場合はリネームしなければいいだけのように見えるのだが、そうも行かないのが面倒なところ。テンプレート変数はリネームされなければならないのだ。とりあえずマクロ展開形が局所マクロを含んでいるというのは(おそらく)なんとか分かる気がするので、その場合のみを特殊扱いするという感じでいこうかと思う。既に不安材料が見えているのでそれが正しいのかは今一よく分からないのではあるが・・・

このバグ、6ヶ月くらい寝かせてあったのだが、最近になって気運が高まってきたのか原因が掴めるところまできた。どうやら困難なバグほど寝かせておいた方が角が取れて消化しやすくなるらしい。

No comments:

Post a Comment