3imp 読んでみる (8)
lambda 以降のソレについて試験。
とりあえず lambda から set! まで。まだ試験は足りてません。
(test-section "lambda") (test* "(compile '(lambda (x) 1) '(halt))" '(close (x) (constant 1 (return)) (halt)) (compile '(lambda (x) 1) '(halt))) ;; it needs additional test (test-section "if") (test* "(compile '(if x 1 2) '(halt))" '(refer x (test (constant 1 (halt)) (constant 2 (halt)))) (compile '(if x 1 2) '(halt))) ;; it needs additional test (test-section "set!") (test* "(compile '(set! x 1) '(halt))" '(constant 1 (assign x (halt))) (compile '(set! x 1) '(halt))) ;; it needs additional test
で、call/cc ですがまず以下を作成してパス
(test* "(compile '(call/cc (lambda (cont) 1)) '(halt))" '(frame (halt) (conti (argument (close (cont) (constant 1 (return)) (apply))))) (compile '(call/cc (lambda (cont) 1)) '(halt)))
次に tail? が真を戻す next を試験しようとして
(test* "(compile '(lambda (x) (call/cc (lambda (cont) 1))))" '(close (x) (conti (argument (close (cont) (constant 1 (return))))) (return)) (compile '(lambda (x) (call/cc (lambda (cont) 1)))))
な試験をでっち上げたら通らない。以下は整形したもの
discrepancies found. Errors are: test (compile '(lambda (x) (call/cc (lambda (cont) 1)))): expects (close (x) (conti (argument (close (cont) (constant 1 (return))))) (return)) => got #<error "wrong number of arguments for #<closure compile> (required 2, got 1)">
これはどーゆーコトかいな。と思ったら試験が駄目なのか。で以下に修正して
(test* "(compile '(lambda (x) (call/cc (lambda (cont) 1))) '(halt))" '(close (x) (conti (argument (close (cont) (constant 1 (return))))) (return)) (compile '(lambda (x) (call/cc (lambda (cont) 1))) '(halt)))
試験したら NG
discrepancies found. Errors are: test (compile '(lambda (x) (call/cc (lambda (cont) 1))) '(halt)): expects (close (x) (conti (argument (close (cont) (constant 1 (return))))) (return)) => got (close (x) (conti (argument (close (cont) (constant 1 (return)) (apply)))) (halt))
確かによく見るとこっちが明らかにおかしい。(compile x '(apply)) で戻るのは
(close (cont) (constant 1 (return)) (apply))
だな。あとはこれを元にリストを作ればええのか
(conti (argument (close (cont) (constant 1 (return)) (apply))))
が戻りのはず。あ、違う。これは call/cc をコンパイルしたソレが戻すリストなのでこれをさらに lambda を compile したソレでくるむ必要あり。
(close (x) (conti (argument (close (cont) (constant 1 (return)) (apply)))) (halt))
かな。OK です。どーでも良いのですが試験が凄く見づらい。call/cc は単体試験ベースだとこれで良いのかなぁ。試験は以下
(test* "(compile '(lambda (x) (call/cc (lambda (cont) 1))) '(halt))" '(close (x) (conti (argument (close (cont) (constant 1 (return)) (apply)))) (halt)) (compile '(lambda (x) (call/cc (lambda (cont) 1))) '(halt)))
次は手続きなソレなんですが、args を全て compile した時点で next が return なケイスとそうでないケイスの試験をする必要があるのか。ちなみに application な else の処理は以下なんですが
(recur loop ([args (cdr x)] [c (compile (car x) '(apply))]) (if (null? args) (if (tail? next) c (list 'frame next c)) (loop (cdr args) (compile (car args) (list 'argument c)))))])]
x とか next とかは compile の引数なソレになる。next が '(return) になるケイスというのは lambda 式の body をコンパイルする時ですか。こんな式かなぁ。
((lambda (x) (p 1)) 1)
確かに (p 1) は末尾呼び出しではあるな。これを compile したらどうなるかってこれキッツいなぁ。とりあえず (compile (lambda (x) (p 1)) '(apply)) したら
(close (x) ... (apply))
が出てくるか。(p 1) を compile なソレは (compile (p 1) (return)) で出てくるのが何か、というコトなんですがとりあえず (compile p (apply)) で
(refer p (apply))
が出てきてこうなるのかな??
(constant 1 (argument (refer p (apply))))
なので (compile (lambda (x) (p 1)) (apply)) の戻りは
(close (x) (constant 1 (argument (refer p (apply)))) (apply))
が戻るで良いのでしょうか。これが c にセットされてこれが戻る??
(frame (halt) (constant 1 (argument (close (x) (constant 1 (argument (refer p (apply)))) (apply)))))
うえー。多分違うと思うけどヤッてみます。で、ダメモトで試験してみたら通った。わははは。調子に乗って普通のパターンも。面倒なので (p 1) で。これは
(compile (p 1) (halt))
が何を戻すか、ですが以下??
(frame (halt) (constant 1 (argument (refer p (apply)))))
いえーい。とりあえずこれで compile はざくっと OK ってコトに。VM が出てくるまでもう少し英語がソレ
# っていいのかなぁ。