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 が出てくるまでもう少し英語がソレ
# っていいのかなぁ。