バグ修正 do の経過

でかけ先でちょっと時間ができたのでバグ修正。
leque さんによる、doフォームのバグ指摘。

  • 簡単な修正で対応できるが多少のコストをかけて、R6RS にある do のマクロ実装を define-macro と match で書きなおそうと決意。
  • 書きなおしたがうまく動かない。
  • Gaucheで動かしてみて動いた
  • do のマクロ展開後の形が知りたいので macroexpand を実装
  • よく分からない
  • Gauche の結果と match マクロの展開結果が違うことが判明←今ここ
;; mosh
(let ((G7 '(do2 ((i 0) (j 0)) ((zero? j) (print 1) (print 2) (print 3))))) (if (and (pair? G7) (equal? (car G7) 'do2) (pair? (cdr G7)) (pair? (cadr G7)) (pair? (caadr G7)) (pair? (cdaadr G7)) (pair? (cdr (cdaadr G7))) (pair? (cddr (cdaadr G7))) (equal? (caddr (cdaadr G7)) 0) (null? (cdddr (cdaadr G7))) (pair? (cdadr G7)) (equal? (cadadr G7) 0) (null? (cddadr G7)) (pair? (cddr G7)) (pair? (caddr G7)) (pair? (cdaddr G7)) (pair? (cdr (cdaddr G7))) (equal? (cadr (cdaddr G7)) 0) (null? (cddr (cdaddr G7))) (pair? (cdddr G7)) (pair? (cddddr G7)) (equal? (car (cddddr G7)) 0) (null? (cdr (cddddr G7)))) ((lambda (var init step test expr command) (print "match")) (caaadr G7) (car (cdaadr G7)) (cadr (cdaadr G7)) (caaddr G7) (car (cdaddr G7)) (cadddr G7)) ((lambda (else) (print "malformed do2")) G7)))

;; gosh
(let ((G21 `(do2 ((i 0) (j 0)) ((zero? j) (print 1) (print 2) (print 3))))) (let ((G38 (lambda (else) (print "malformed do2")))) (if (and (pair? G21) (equal? (car G21) 'do2) (pair? (cdr G21)) (list? (cadr G21))) (let G26 ((G27 (cadr G21)) (G28 '()) (G29 '()) (G30 '())) (if (null? G27) (if (and (pair? (cddr G21)) (pair? (caddr G21)) (list? (cdaddr G21)) (list? (cdddr G21))) ((lambda (var init step test expr command) (print "match")) (reverse G30) (reverse G29) (reverse G28) (caaddr G21) (cdaddr G21) (cdddr G21)) (G38 G21)) (if (and (pair? (car G27)) (pair? (cdar G27)) (list? (cddar G27))) (G26 (cdr G27) (cons (cddar G27) G28) (cons (cadar G27) G29) (cons (caar G27) G30)) (G38 G21)))) (G38 G21))))


さてここからの切りわけが難しいんだよね。
可能性としては

  • match.scm がそもそも異なる(移植ミスとか)
  • match の展開後に関して Mosh のバグ
  • Mosh の match 展開のバグである

あたりかな。
感触的にはどれもありそうな話なので検証の手間が少ないものからやってみるか。

match の展開後に関して Mosh のバグか?

  • gosh で展開されたコードを Mosh で動かす
    • →意図通り
  • mosh で展開されたコードを Gauche で動かす
    • →動かない

Mosh で展開されたコードがおかしいということか。

比較

最小再現コードを作ろう。

(write
 (macroexpand
  '(match '(3)
     [(expr ...)
      (print "match")]
     [else
      (print "unmatch")])))
(print "\n\n")

できた。

プリコンパイルが犯人かも

Scheme で書かれた Mosh だと再現しない。
あと match の移植ミスの線は消えた。

sewashi% echo "(use srfi-1)(load \"./match.scm\")" |cat - huga.scm |gosh && ./vm.scm ./huga.scm

の結果が同じ。

犯人はパーサーの strtol だった

match の ... (リストの最後の要素の繰り返しに使われるシンボル)が、 (read) されたとき 0 になっていた。
strtol に "..." を渡すとエラーのなるのを期待していたのだけど、どうもエラーにならず 0 が返るっぽい。(errnoに何も設定されない)