control.test 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. ;;;; -*- scheme -*-
  2. ;;;; control.test --- test suite for delimited continuations
  3. ;;;;
  4. ;;;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
  5. ;;;;
  6. ;;;; This library is free software; you can redistribute it and/or
  7. ;;;; modify it under the terms of the GNU Lesser General Public
  8. ;;;; License as published by the Free Software Foundation; either
  9. ;;;; version 3 of the License, or (at your option) any later version.
  10. ;;;;
  11. ;;;; This library is distributed in the hope that it will be useful,
  12. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;;;; Lesser General Public License for more details.
  15. ;;;;
  16. ;;;; You should have received a copy of the GNU Lesser General Public
  17. ;;;; License along with this library; if not, write to the Free Software
  18. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. (define-module (test-suite test-control)
  20. #:use-module (ice-9 control)
  21. #:use-module (system vm vm)
  22. #:use-module (srfi srfi-11)
  23. #:use-module (test-suite lib))
  24. ;; For these, the compiler should be able to prove that "k" is not referenced,
  25. ;; so it avoids reifying the continuation. Since that's a slightly different
  26. ;; codepath, we test them both.
  27. (with-test-prefix/c&e "escape-only continuations"
  28. (pass-if "no values, normal exit"
  29. (equal? '()
  30. (call-with-values
  31. (lambda ()
  32. (% (values)
  33. (lambda (k . args)
  34. (error "unexpected exit" args))))
  35. list)))
  36. (pass-if "no values, abnormal exit"
  37. (equal? '()
  38. (% (begin
  39. (abort)
  40. (error "unexpected exit"))
  41. (lambda (k . args)
  42. args))))
  43. (pass-if "single value, normal exit"
  44. (equal? '(foo)
  45. (call-with-values
  46. (lambda ()
  47. (% 'foo
  48. (lambda (k . args)
  49. (error "unexpected exit" args))))
  50. list)))
  51. (pass-if "single value, abnormal exit"
  52. (equal? '(foo)
  53. (% (begin
  54. (abort 'foo)
  55. (error "unexpected exit"))
  56. (lambda (k . args)
  57. args))))
  58. (pass-if "multiple values, normal exit"
  59. (equal? '(foo bar baz)
  60. (call-with-values
  61. (lambda ()
  62. (% (values 'foo 'bar 'baz)
  63. (lambda (k . args)
  64. (error "unexpected exit" args))))
  65. list)))
  66. (pass-if "multiple values, abnormal exit"
  67. (equal? '(foo bar baz)
  68. (% (begin
  69. (abort 'foo 'bar 'baz)
  70. (error "unexpected exit"))
  71. (lambda (k . args)
  72. args)))))
  73. ;;; And the case in which the compiler has to reify the continuation.
  74. (with-test-prefix/c&e "reified continuations"
  75. (pass-if "no values, normal exit"
  76. (equal? '()
  77. (call-with-values
  78. (lambda ()
  79. (% (values)
  80. (lambda (k . args)
  81. (error "unexpected exit" k args))))
  82. list)))
  83. (pass-if "no values, abnormal exit"
  84. (equal? '()
  85. (cdr
  86. (% (begin
  87. (abort)
  88. (error "unexpected exit"))
  89. (lambda args
  90. args)))))
  91. (pass-if "single value, normal exit"
  92. (equal? '(foo)
  93. (call-with-values
  94. (lambda ()
  95. (% 'foo
  96. (lambda (k . args)
  97. (error "unexpected exit" k args))))
  98. list)))
  99. (pass-if "single value, abnormal exit"
  100. (equal? '(foo)
  101. (cdr
  102. (% (begin
  103. (abort 'foo)
  104. (error "unexpected exit"))
  105. (lambda args
  106. args)))))
  107. (pass-if "multiple values, normal exit"
  108. (equal? '(foo bar baz)
  109. (call-with-values
  110. (lambda ()
  111. (% (values 'foo 'bar 'baz)
  112. (lambda (k . args)
  113. (error "unexpected exit" k args))))
  114. list)))
  115. (pass-if "multiple values, abnormal exit"
  116. (equal? '(foo bar baz)
  117. (cdr
  118. (% (begin
  119. (abort 'foo 'bar 'baz)
  120. (error "unexpected exit"))
  121. (lambda args
  122. args)))))
  123. (pass-if "reified pending call frames, instantiated elsewhere on the stack"
  124. (equal? 'foo
  125. ((call-with-prompt
  126. 'p0
  127. (lambda ()
  128. (identity ((abort-to-prompt 'p0) 'foo)))
  129. (lambda (c) c))
  130. (lambda (x) x)))))
  131. ;; The variants check different cases in the compiler.
  132. (with-test-prefix/c&e "restarting partial continuations"
  133. (pass-if "in side-effect position"
  134. (let ((k (% (begin (abort) 'foo)
  135. (lambda (k) k))))
  136. (eq? (k)
  137. 'foo)))
  138. (pass-if "passing values to side-effect abort"
  139. (let ((k (% (begin (abort) 'foo)
  140. (lambda (k) k))))
  141. (eq? (k 'qux 'baz 'hello)
  142. 'foo)))
  143. (pass-if "called for one value"
  144. (let ((k (% (+ (abort) 3)
  145. (lambda (k) k))))
  146. (eqv? (k 39)
  147. 42)))
  148. (pass-if "called for multiple values"
  149. (let ((k (% (let-values (((a b . c) (abort)))
  150. (list a b c))
  151. (lambda (k) k))))
  152. (equal? (k 1 2 3 4)
  153. '(1 2 (3 4)))))
  154. (pass-if "in tail position"
  155. (let ((k (% (abort)
  156. (lambda (k) k))))
  157. (eq? (k 'xyzzy)
  158. 'xyzzy))))
  159. ;; Here we test different cases for the `prompt'.
  160. (with-test-prefix/c&e "prompt in different contexts"
  161. (pass-if "push, normal exit"
  162. (car (call-with-prompt
  163. 'foo
  164. (lambda () '(#t))
  165. (lambda (k) '(#f)))))
  166. (pass-if "push, nonlocal exit"
  167. (car (call-with-prompt
  168. 'foo
  169. (lambda () (abort-to-prompt 'foo) '(#f))
  170. (lambda (k) '(#t)))))
  171. (pass-if "push with RA, normal exit"
  172. (car (letrec ((test (lambda ()
  173. (call-with-prompt
  174. 'foo
  175. (lambda () '(#t))
  176. (lambda (k) '(#f))))))
  177. (test))))
  178. (pass-if "push with RA, nonlocal exit"
  179. (car (letrec ((test (lambda ()
  180. (call-with-prompt
  181. 'foo
  182. (lambda () (abort-to-prompt 'foo) '(#f))
  183. (lambda (k) '(#t))))))
  184. (test))))
  185. (pass-if "tail, normal exit"
  186. (call-with-prompt
  187. 'foo
  188. (lambda () #t)
  189. (lambda (k) #f)))
  190. (pass-if "tail, nonlocal exit"
  191. (call-with-prompt
  192. 'foo
  193. (lambda () (abort-to-prompt 'foo) #f)
  194. (lambda (k) #t)))
  195. (pass-if "tail with RA, normal exit"
  196. (letrec ((test (lambda ()
  197. (call-with-prompt
  198. 'foo
  199. (lambda () #t)
  200. (lambda (k) #f)))))
  201. (test)))
  202. (pass-if "tail with RA, nonlocal exit"
  203. (letrec ((test (lambda ()
  204. (call-with-prompt
  205. 'foo
  206. (lambda () (abort-to-prompt 'foo) #f)
  207. (lambda (k) #t)))))
  208. (test)))
  209. (pass-if "drop, normal exit"
  210. (begin
  211. (call-with-prompt
  212. 'foo
  213. (lambda () #f)
  214. (lambda (k) #f))
  215. #t))
  216. (pass-if "drop, nonlocal exit"
  217. (begin
  218. (call-with-prompt
  219. 'foo
  220. (lambda () (abort-to-prompt 'foo))
  221. (lambda (k) #f))
  222. #t))
  223. (pass-if "drop with RA, normal exit"
  224. (begin
  225. (letrec ((test (lambda ()
  226. (call-with-prompt
  227. 'foo
  228. (lambda () #f)
  229. (lambda (k) #f)))))
  230. (test))
  231. #t))
  232. (pass-if "drop with RA, nonlocal exit"
  233. (begin
  234. (letrec ((test (lambda ()
  235. (call-with-prompt
  236. 'foo
  237. (lambda () (abort-to-prompt 'foo) #f)
  238. (lambda (k) #f)))))
  239. (test))
  240. #t)))
  241. (define fl (make-fluid))
  242. (fluid-set! fl 0)
  243. ;; Not c&e as it assumes this block executes once.
  244. ;;
  245. (with-test-prefix "suspend/resume with fluids"
  246. (pass-if "normal"
  247. (zero? (% (fluid-ref fl)
  248. error)))
  249. (pass-if "with-fluids normal"
  250. (equal? (% (with-fluids ((fl (1+ (fluid-ref fl))))
  251. (fluid-ref fl))
  252. error)
  253. 1))
  254. (pass-if "normal (post)"
  255. (zero? (fluid-ref fl)))
  256. (pass-if "with-fluids and fluid-set!"
  257. (equal? (% (with-fluids ((fl (1+ (fluid-ref fl))))
  258. (fluid-set! fl (1+ (fluid-ref fl)))
  259. (fluid-ref fl))
  260. error)
  261. 2))
  262. (pass-if "normal (post2)"
  263. (zero? (fluid-ref fl)))
  264. (pass-if "normal fluid-set!"
  265. (equal? (begin
  266. (fluid-set! fl (1+ (fluid-ref fl)))
  267. (fluid-ref fl))
  268. 1))
  269. (pass-if "reset fluid-set!"
  270. (equal? (begin
  271. (fluid-set! fl (1- (fluid-ref fl)))
  272. (fluid-ref fl))
  273. 0))
  274. (let ((k (% (with-fluids ((fl (1+ (fluid-ref fl))))
  275. (abort)
  276. (fluid-ref fl))
  277. (lambda (k) k))))
  278. (pass-if "pre"
  279. (equal? (fluid-ref fl) 0))
  280. (pass-if "res"
  281. (equal? (k) 1))
  282. (pass-if "post"
  283. (equal? (fluid-ref fl) 0))))
  284. (with-test-prefix/c&e "rewinding prompts"
  285. (pass-if "nested prompts"
  286. (let ((k (% 'a
  287. (% 'b
  288. (begin
  289. (abort-to-prompt 'a)
  290. (abort-to-prompt 'b #t))
  291. (lambda (k x) x))
  292. (lambda (k) k))))
  293. (k))))
  294. (with-test-prefix/c&e "abort to unknown prompt"
  295. (pass-if-exception "foo" '(misc-error . "^Abort to unknown prompt")
  296. (abort-to-prompt 'does-not-exist)))
  297. (with-test-prefix/c&e "the-vm"
  298. (pass-if "unwind changes VMs"
  299. (let ((new-vm (make-vm))
  300. (prev-vm (the-vm))
  301. (proc (lambda (x y)
  302. (expt x y)))
  303. (call (lambda (p x y)
  304. (p x y))))
  305. (catch 'foo
  306. (lambda ()
  307. (call-with-vm new-vm (lambda () (throw 'foo (the-vm)))))
  308. (lambda (key vm)
  309. (and (eq? key 'foo)
  310. (eq? vm new-vm)
  311. (eq? (the-vm) prev-vm)))))))
  312. ;; These tests from Oleg Kiselyov's delim-control-n.scm, available at
  313. ;; http://okmij.org/ftp/Scheme/delim-control-n.scm. Public domain.
  314. ;;
  315. (with-test-prefix "shift and reset"
  316. (pass-if (equal?
  317. 117
  318. (+ 10 (reset (+ 2 (shift k (+ 100 (k (k 3)))))))))
  319. (pass-if (equal?
  320. 60
  321. (* 10 (reset (* 2 (shift g (* 5 (shift f (+ (f 1) 1)))))))))
  322. (pass-if (equal?
  323. 121
  324. (let ((f (lambda (x) (shift k (k (k x))))))
  325. (+ 1 (reset (+ 10 (f 100)))))))
  326. (pass-if (equal?
  327. 'a
  328. (car (reset
  329. (let ((x (shift f
  330. (shift f1 (f1 (cons 'a (f '())))))))
  331. (shift g x))))))
  332. ;; Example by Olivier Danvy
  333. (pass-if (equal?
  334. '(1 2 3 4 5)
  335. (let ()
  336. (define (traverse xs)
  337. (define (visit xs)
  338. (if (null? xs)
  339. '()
  340. (visit (shift*
  341. (lambda (k)
  342. (cons (car xs) (k (cdr xs))))))))
  343. (reset* (lambda () (visit xs))))
  344. (traverse '(1 2 3 4 5))))))