gensymを使ったコードのテスト

gensymを使ってリストを返すコードのテストをしたいんだけど、単純にはできないので、マクロを書いたという話。(似たような話題はどこにでもありそうだし、どっかで読んだ気もするけど忘れた)

;; できない
(test* "シンボルを生成するコード"
  `(a b c ,(gensym))
  `(a b c ,(gensym)))
test シンボルを生成するコード, expects (a b c G0) ==> ERROR: GOT (a b c G1)
failed.

解決としては、正しい結果の中にプレースホルダ入れておいて、それは無視することにする方法もあると思うけど、どれかとどれかが同じシンボルだというのを検証したい場合に面倒そうだったので、gensymを内部的に制御することにした。

こんな感じに使える。

(mytest-sym* "シンボルを生成するコード"
             `(a b c ,(mygensym))
             `(a b c ,(mygensym)))
test シンボルを生成するコード, expects (a b c MG0) ==> ok

定義はこんな

(use gauche.parameter)

(load "./util.scm") ; mygensym, etc...

(define output (make-parameter ""))

;; body の出力を output にしまう版。
(define-macro (mytest* label value body)
  `(test* ,label ,value
          (let ((retval #f)
                (out (open-output-string)))
            (with-output-to-port out
              (lambda () 
                (set! retval ,body)))
            (output (get-output-string out))
            retval)))

;; gensym をリセットする版。
(define-macro (mytest-sym* label value body)
  (let ((newvalue (gensym))
        (newbody  (gensym)))
    `(begin
       (mygensym-count-init 0)
       (let1 ,newvalue ,value
         (mygensym-count-init 0)
         (let1 ,newbody ,body
           (mytest* ,label ,newvalue ,newbody))))))

mygensym ってのは、 mygensym-count-init でカウンタをリセットできる gensym 。