組込みの手続きをサポートする - Scheme VM を書く
cons, +, number?, pair? などの手続きをサポートしたい。
やることは大まかに2つに分けられる。
- 各手続きが他の手続きから見えるようにする
- 名前にマッピングされる手続き本体を記述する
ある手続き proc から number? が見えるというのは
;; 外側に free variable number. (lambda () (proc) )
と呼び出したときに free variable として number? が存在すれば実現できるのではないかな。
これは display closure に number? の参照を放りこんでおけば良さそう。
具体的にはコンパイル時に
(compile '(number? 3) '(() number?) '() '(halt))
e に number? を入れておくと、カレントフレームからの index を参照する形でコードがコンパイルされる。
compile の第2引数は quote されているので number? というシンボルを登録しているだけなことに注意。
実際の number? 本体は display closre の free variable として VM に渡される。
スタックに number? の本体を push し、その後 closure 命令で closure を作る。
(define (evalute-with-numberp x . args) (let* ((code (compile x '(() number?) '() '(halt))) (dummy (push number? 0)) (clo (closure code 1 1))) (VM clo code 0 clo 0) ))
ここまでやれば、VM 実行時に本来 closure が置かれる場所に number? が直接置かれるようになる。
VM も変更が必要で (apply) 時に accumulator に置かれた closure を参照している部分で分岐。
[apply () (if (procedure? a) (VM (apply a (list (index s 0))) '(return 1) f c s) (VM a (closure-body a) s a s)) ]
accumulator から number? を取り出し、スタックから引数を取り出す。
その後 native の apply で実際に手続きを呼んで accumulator 置いて (return) で処理を継続する。