メモ

自作のコンパイラにまだこんな致命的なバグが残っていてのけぞる。

(let ((x 1)) (let ((x 3)) 999) x) => 3 ;; 誤り
(let ((x 1)) (let ((x 3)) 999) x) => 1 ;; 正

新しく書いた assignment conversion (3.12) のせいかと思ったらずっとまえからこのバグはあったようだ。

その assignment conversion もバグでまくり。再帰的に S式を変換していく際に変換し忘れ。修正。
変数に対してサイズ1の vector に変換して変更可能にする、という理解だけど、

gosh> (print (assignment-conversion 
'(let ((x (+ 1 2)))
 (let ((x (+ x 4))) x))))
=>
  (let ((x (make-vector 1)))
    (vector-set! x 0 (+ 1 2))
    (let ((x (make-vector 1)))
       (vector-set! x 0 (+ (vector-ref x 0) 4)) ;; bug
       (vector-ref x 0)))

この変換は間違い。2番目に作った vector の(初期化されていない)0番目の要素を参照してしまっている。(make-vector 1) を止めて単に (vector expr) を使うことで解決した(つもり)。

まだ先は長い。

追記。

  • 一つテストをパスするのに一つ修正を繰り返す。3.12 は説明少なすぎる。
  • 変数が導入されるのは let と lambda. lambda にも対応。
  • 順番を間違えていた。私の実装だと closure 変換を行うと lambda は無くなってしまう=よって assignment conversioon を先、その後で closure 変換。
  • ようやく、まだ挙動が怪しいが counter が動くようになった。
(run-program '(let ((make-counter
                     (lambda ()
                       (let ((counter -1))
                         (lambda ()
                           (set! counter (add1 counter))
                           counter)))))
                (let ((c0 (funcall make-counter))
                      (c1 (funcall make-counter)))
                  (funcall c0)
                  (funcall c0)
                  (funcall c1)
                  (funcall c0)
                  (funcall c0)
                  (cons (funcall c0) (funcall c1)))))
=> (4 . 1) ;; ok