loop.scm 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. ;;; -*- Mode: Scheme -*-
  2. ;;;; Extensible Looping Macros, version 9 (BETA)
  3. ;;; Copyright (c) 2008, Taylor R. Campbell
  4. ;;;
  5. ;;; Redistribution and use in source and binary forms, with or without
  6. ;;; modification, are permitted provided that the following conditions
  7. ;;; are met:
  8. ;;;
  9. ;;; * Redistributions of source code must retain the above copyright
  10. ;;; notice, this list of conditions and the following disclaimer.
  11. ;;;
  12. ;;; * Redistributions in binary form must reproduce the above copyright
  13. ;;; notice, this list of conditions and the following disclaimer in
  14. ;;; the documentation and/or other materials provided with the
  15. ;;; distribution.
  16. ;;;
  17. ;;; * Neither the names of the authors nor the names of contributors
  18. ;;; may be used to endorse or promote products derived from this
  19. ;;; software without specific prior written permission.
  20. ;;;
  21. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
  22. ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  23. ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  25. ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  27. ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  29. ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30. ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31. ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. ;;; This is a variation on Alex Shinn's looping macros described in
  33. ;;; message-id <1157562097.001179.11470@i42g2000cwa.googlegroups.com>.
  34. ;;; It has diverged substantially from the original macros, and is now
  35. ;;; documented at <http://mumble.net/~campbell/tmp/foof-loop.txt> [for
  36. ;;; the beta period of foof-loop version 9].
  37. ;;;
  38. ;;; This file depends on syn-param.scm, also by Taylor R. Campbell, and
  39. ;;; SRFI 11 (LET-VALUES). Ideally, the implementation of LET-VALUES
  40. ;;; should gracefully handle single-value clauses to elide superfluous
  41. ;;; uses of CALL-WITH-VALUES.
  42. (define-syntax loop
  43. (syntax-rules ()
  44. ((LOOP ((loop-clause0 loop-clause1+ ...) ...)
  45. body
  46. ...)
  47. (LOOP ANONYMOUS-LOOP ((loop-clause0 loop-clause1+ ...) ...)
  48. body
  49. ...
  50. (ANONYMOUS-LOOP)))
  51. ((LOOP name ((loop-clause0 loop-clause1+ ...) ...) body ...)
  52. (SYNTACTIC-ERROR-IF-NOT-NAME name ("Malformed loop name:" name)
  53. (%LOOP START name ((loop-clause0 loop-clause1+ ...) ...) (body ...))))))
  54. ;;; We must be very careful about where to add laziness annotations.
  55. ;;; In particular, we don't want to wrap only the loop's body, because
  56. ;;; if we did that, the outer bindings produced by the iterators would
  57. ;;; be evaluate eagerly, which is too soon. So instead, we wrap the
  58. ;;; whole thing in a LAZY, and then wrap every call to the loop as
  59. ;;; well.
  60. (define-syntax lazy-loop
  61. (syntax-rules (=>)
  62. ((LAZY-LOOP name (loop-clause ...) => result body0 body1+ ...)
  63. (SYNTACTIC-ERROR-IF-NOT-NAME name ("Invalid lazy loop name:" name)
  64. (LAZY (LOOP EAGER-LOOP (loop-clause ...)
  65. => result
  66. (LET-SYNTAX ((name
  67. (SYNTAX-RULES ()
  68. ((name . arguments)
  69. (LAZY (EAGER-LOOP . arguments))))))
  70. body0 body1+ ...)))))))
  71. ;;;; Error Reporting
  72. ;;; Use this definition of SYNTACTIC-ERROR if your favourite Scheme
  73. ;;; doesn't have one already. Note that this is distinct from a
  74. ;;; SYNTAX-ERROR procedure, since it must signal a compile-time error.
  75. (define-syntax syntactic-error (syntax-rules ()))
  76. (define-syntax syntactic-name?
  77. (syntax-rules ()
  78. ((SYNTACTIC-NAME? (a . d) if-yes if-no) if-no)
  79. ((SYNTACTIC-NAME? #(v ...) if-yes if-no) if-no)
  80. ((SYNTACTIC-NAME? datum if-yes if-no)
  81. (LET-SYNTAX ((TEST-ELLIPSIS
  82. (SYNTAX-RULES ()
  83. ((TEST-ELLIPSIS (VARIABLE datum) YES NO) YES)
  84. ((TEST-ELLIPSIS OTHERWISE YES NO) NO))))
  85. (TEST-ELLIPSIS (MAGICAL MYSTERY LIST)
  86. if-yes
  87. (LET-SYNTAX ((TEST-NAME
  88. (SYNTAX-RULES ()
  89. ((TEST-NAME datum YES NO) YES)
  90. ((TEST-NAME OTHERWISE YES NO) NO))))
  91. (TEST-NAME MAGICAL-MYSTERY-SYMBOL if-yes if-no)))))))
  92. (define-syntax syntactic-ellipsis?
  93. (syntax-rules ()
  94. ((SYNTACTIC-ELLIPSIS? (a . d) if-yes if-no) if-no)
  95. ((SYNTACTIC-ELLIPSIS? #(v ...) if-yes if-no) if-no)
  96. ((SYNTACTIC-ELLIPSIS? datum if-yes if-no)
  97. (LET-SYNTAX ((TEST-ELLIPSIS
  98. (SYNTAX-RULES ()
  99. ((TEST-ELLIPSIS (VARIABLE datum) YES NO) YES)
  100. ((TEST-ELLIPSIS OTHERWISE YES NO) NO))))
  101. (TEST-ELLIPSIS (MAGICAL MYSTERY LIST) if-yes if-no)))))
  102. (define-syntax syntactic-error-if-not-name
  103. (syntax-rules ()
  104. ((SYNTACTIC-ERROR-IF-NOT-NAME name (message irritant ...) if-ok)
  105. (SYNTACTIC-NAME? name
  106. if-ok
  107. (SYNTACTIC-ERROR message irritant ...)))))
  108. (define-syntax syntactic-error-if-not-names
  109. (syntax-rules ()
  110. ((SYNTACTIC-ERROR-IF-NOT-NAMES () (message irritant ...) if-ok)
  111. if-ok)
  112. ((SYNTACTIC-ERROR-IF-NOT-NAMES (name0 name1+ ...) (message irritant ...)
  113. if-ok)
  114. (SYNTACTIC-ERROR-IF-NOT-NAME name0 (message irritant ...)
  115. (SYNTACTIC-ERROR-IF-NOT-NAMES (name1+ ...) (message irritant ...)
  116. if-ok)))))
  117. ;;; Implement these if it is expedient in your Scheme system.
  118. (define-syntax syntactic-error-if-not-bvl
  119. (syntax-rules ()
  120. ((SYNTACTIC-ERROR-IF-NOT-BVL bvl (message irritant ...) if-ok)
  121. if-ok)))
  122. (define-syntax syntactic-error-if-not-bvls
  123. (syntax-rules ()
  124. ((SYNTACTIC-ERROR-IF-NOT-BVLS (bvl ...) (message irritant ...) if-ok)
  125. if-ok)))
  126. ;;; Utilities for reporting syntax errors in LOOP clauses.
  127. (define-syntax loop-clause-error
  128. (syntax-rules (CONTEXT)
  129. ((LOOP-CLAUSE-ERROR (CONTEXT iterator (variable ...) arguments))
  130. (SYNTACTIC-ERROR "Malformed LOOP clause:"
  131. (FOR variable ... (iterator . arguments))))
  132. ;; Old style.
  133. ((LOOP-CLAUSE-ERROR (iterator (variable ...) arguments message))
  134. (SYNTACTIC-ERROR message (FOR variable ... (iterator . arguments))))))
  135. (define-syntax %loop-check
  136. (syntax-rules ()
  137. ((%LOOP-CHECK syntactic-check operand
  138. (CONTEXT iterator (variable ...) arguments)
  139. if-ok)
  140. (syntactic-check operand
  141. ("Malformed LOOP clause:" (FOR variable ... (iterator . arguments)))
  142. if-ok))
  143. ((%LOOP-CHECK syntactic-check operand
  144. (iterator (variable ...) arguments message)
  145. if-ok)
  146. (syntactic-check operand
  147. (message (FOR variable ... (iterator . arguments)))
  148. if-ok))))
  149. (define-syntax loop-clause-error-if-not-name
  150. (syntax-rules ()
  151. ((LOOP-CLAUSE-ERROR-IF-NOT-NAME name error-context if-ok)
  152. (%LOOP-CHECK SYNTACTIC-ERROR-IF-NOT-NAME name error-context if-ok))))
  153. (define-syntax loop-clause-error-if-not-names
  154. (syntax-rules ()
  155. ((LOOP-CLAUSE-ERROR-IF-NOT-NAMES names error-context if-ok)
  156. (%LOOP-CHECK SYNTACTIC-ERROR-IF-NOT-NAMES names error-context if-ok))))
  157. (define-syntax loop-clause-error-if-not-bvl
  158. (syntax-rules ()
  159. ((LOOP-CLAUSE-ERROR-IF-NOT-BVL bvl error-context if-ok)
  160. (%LOOP-CHECK SYNTACTIC-ERROR-IF-NOT-BVL bvl error-context if-ok))))
  161. (define-syntax loop-clause-error-if-not-bvls
  162. (syntax-rules ()
  163. ((LOOP-CLAUSE-ERROR-IF-NOT-BVLS bvls error-context if-ok)
  164. (%LOOP-CHECK SYNTACTIC-ERROR-IF-NOT-BVLS bvls error-context if-ok))))
  165. ;;;; The Guts of LOOP
  166. (define-syntax %loop
  167. (syntax-rules (=> FOR WHERE LET LET-VALUES WHILE UNTIL
  168. START GO PARSE-FOR CONTINUE FINISH SIMPLIFY-BODY)
  169. ((%LOOP START name loop-clauses body)
  170. (%LOOP GO name (() () () () () () () ()) loop-clauses body))
  171. ;; Simple case of a single variable, for clarity.
  172. ((%LOOP GO name state
  173. ((FOR variable (iterator argument ...))
  174. . loop-clauses)
  175. body)
  176. (iterator (variable) (argument ...)
  177. %LOOP CONTINUE iterator name state loop-clauses body))
  178. ;; FOR handler with tail patterns. Unfortunately, tail patterns are non-
  179. ;; standard, so we need the next four clauses rather than this one...
  180. ;;
  181. ;; ((%LOOP GO name state
  182. ;; ((FOR variable0 variable1+ ... (iterator argument ...))
  183. ;; . loop-clauses)
  184. ;; body)
  185. ;; (iterator (variable0 variable1+ ...)
  186. ;; (argument ...)
  187. ;; %LOOP CONTINUE iterator name state loop-clauses body))
  188. ;;;;; FOR Clauses: Dealing with Iterators
  189. ((%LOOP GO name state
  190. ((FOR variable0 variable1 variable2+ ...) . loop-clauses)
  191. body)
  192. (%LOOP PARSE-FOR (variable0 variable1 variable2+ ...)
  193. ()
  194. (FOR variable0 variable1 variable2+ ...) ;Copy for error message.
  195. name state loop-clauses body))
  196. ((%LOOP PARSE-FOR ((iterator argument ...))
  197. variables
  198. original-clause name state loop-clauses body)
  199. (iterator variables (argument ...)
  200. %LOOP CONTINUE iterator name state loop-clauses body))
  201. ((%LOOP PARSE-FOR (next-variable more0 more1+ ...)
  202. (variable ...)
  203. original-clause name state loop-clauses body)
  204. (%LOOP PARSE-FOR (more0 more1+ ...)
  205. (variable ... next-variable)
  206. original-clause name state loop-clauses body))
  207. ((%LOOP PARSE-FOR (non-list)
  208. variables
  209. original-clause name state loop-clauses body)
  210. (SYNTACTIC-ERROR "Malformed FOR clause in LOOP:" original-clause))
  211. ((%LOOP ((outer-bvl outer-producer) ...)
  212. ((loop-variable loop-initializer loop-stepper) ...)
  213. ((entry-bvl entry-producer) ...)
  214. (termination-condition ...)
  215. ((body-bvl body-producer) ...)
  216. ((final-bvl final-producer) ...)
  217. CONTINUE
  218. iterator
  219. name
  220. ((loop-variables ...)
  221. user-bindings
  222. user-termination-conditions
  223. outer-bindings
  224. entry-bindings
  225. termination-conditions
  226. body-bindings
  227. final-bindings)
  228. loop-clauses
  229. body)
  230. (SYNTACTIC-ERROR-IF-NOT-NAMES (loop-variable ...)
  231. ("Internal error -- Malformed loop variables from iterator:" iterator)
  232. (SYNTACTIC-ERROR-IF-NOT-BVLS
  233. (outer-bvl ... entry-bvl ... body-bvl ... final-bvl ...)
  234. ("Internal error -- Malformed BVLs from iterator:" iterator)
  235. (%LOOP GO name
  236. ((loop-variables ... ;** Preserve order.
  237. (loop-variable loop-initializer loop-stepper) ...)
  238. user-bindings
  239. user-termination-conditions
  240. ((outer-bvl outer-producer) ... . outer-bindings)
  241. ((entry-bvl entry-producer) ... . entry-bindings)
  242. (termination-condition ... . termination-conditions)
  243. ((body-bvl body-producer) ... . body-bindings)
  244. ((final-bvl final-producer) ... . final-bindings))
  245. loop-clauses
  246. body))))
  247. ;;;;; User-Directed Clauses
  248. ((%LOOP GO name state
  249. ((WHERE variable initializer) . loop-clauses)
  250. body)
  251. (SYNTACTIC-ERROR-IF-NOT-NAME variable
  252. ("Malformed WITH clause in LOOP:" (WHERE variable initializer))
  253. (%LOOP GO name state
  254. ((WHERE variable initializer variable) . loop-clauses)
  255. body)))
  256. ((%LOOP GO name
  257. ((loop-variable ...) . more-state)
  258. ((WHERE variable initializer stepper) . loop-clauses)
  259. body)
  260. (SYNTACTIC-ERROR-IF-NOT-NAME variable
  261. ("Malformed WITH clause in LOOP:" (WHERE variable initializer stepper))
  262. (%LOOP GO name
  263. ;; Preserve ordering of the user's loop variables.
  264. ((loop-variable ... (variable initializer stepper))
  265. . more-state)
  266. loop-clauses
  267. body)))
  268. ((%LOOP GO name state ((LET variable expression) . loop-clauses) body)
  269. (SYNTACTIC-ERROR-IF-NOT-NAME variable
  270. ("Malformed LET clause in LOOP:" (LET variable expression))
  271. (%LOOP GO name state ((LET-VALUES (variable) expression) . loop-clauses)
  272. body)))
  273. ((%LOOP GO name (loop-variables (user-binding ...) . more-state)
  274. ((LET-VALUES user-bvl user-producer) . loop-clauses)
  275. body)
  276. (SYNTACTIC-ERROR-IF-NOT-BVL user-bvl
  277. ("Malformed LET-VALUES clause in LOOP:"
  278. (LET-VALUES user-bvl user-producer))
  279. (%LOOP GO name (loop-variables
  280. ;; Preserve order of the user's termination conditions.
  281. (user-binding ... (user-bvl user-producer))
  282. . more-state)
  283. loop-clauses
  284. body)))
  285. ;;;;;; User-Directed Clauses, continued
  286. ((%LOOP GO name state ((WHILE condition) . loop-clauses) body)
  287. (%LOOP GO name state ((UNTIL (NOT condition)) . loop-clauses) body))
  288. ((%LOOP GO name (loop-variables
  289. user-bindings
  290. (user-termination-condition ...)
  291. . more-state)
  292. ((UNTIL user-termination-condition*) . loop-clauses)
  293. body)
  294. (%LOOP GO name
  295. (loop-variables
  296. user-bindings
  297. (user-termination-condition ... user-termination-condition*)
  298. . more-state)
  299. loop-clauses
  300. body))
  301. ;; Compatibility forms. These clauses *must* come after all
  302. ;; others, because there is no keyword, so these would shadow any
  303. ;; clauses with keywords.
  304. ((%LOOP GO name state ((variable initializer) . loop-clauses) body)
  305. (SYNTACTIC-ERROR-IF-NOT-NAME variable
  306. ("Malformed named-LET-style clause in LOOP:" (variable initializer))
  307. (%LOOP GO name state
  308. ((WHERE variable initializer) . loop-clauses)
  309. body)))
  310. ((%LOOP GO name state ((variable initializer stepper) . loop-clauses) body)
  311. (SYNTACTIC-ERROR-IF-NOT-NAME variable
  312. ("Malformed DO-style clause in LOOP:" (variable initializer stepper))
  313. (%LOOP GO name state
  314. ((WHERE variable initializer stepper) . loop-clauses)
  315. body)))
  316. ((%LOOP GO name state (clause . loop-clauses) body)
  317. (SYNTACTIC-ERROR "Malformed LOOP clause:" clause))
  318. ;;;;; Finishing -- Generating Output
  319. ((%LOOP GO name state () (=> result-form . body))
  320. (%LOOP FINISH name state result-form body))
  321. ((%LOOP GO name state () body)
  322. (%LOOP FINISH name state (IF #F #F) body))
  323. ((%LOOP FINISH name
  324. (((loop-variable loop-initializer loop-stepper) ...)
  325. user-bindings
  326. user-termination-conditions
  327. outer-bindings
  328. entry-bindings
  329. termination-conditions
  330. body-bindings
  331. final-bindings)
  332. result-form
  333. body)
  334. (LET-VALUES outer-bindings
  335. (DEFINE (LOOP-PROCEDURE loop-variable ...)
  336. (LET-VALUES entry-bindings
  337. (%LOOP SIMPLIFY-BODY
  338. termination-conditions
  339. (LET-VALUES final-bindings
  340. (WITH-EXTENDED-PARAMETER-OPERATORS
  341. ((name
  342. (LOOP-PROCEDURE (loop-variable . loop-stepper)
  343. ...)))
  344. result-form))
  345. body-bindings
  346. user-bindings
  347. user-termination-conditions
  348. (WITH-EXTENDED-PARAMETER-OPERATORS
  349. ((name
  350. (LOOP-PROCEDURE (loop-variable . loop-stepper)
  351. ...)))
  352. . body))))
  353. (LOOP-PROCEDURE loop-initializer ...)))
  354. ;;;;;; Simplifying the Body
  355. ;; No iterator- or user-introduced termination conditions at all.
  356. ;; No test or closure needed.
  357. ((%LOOP SIMPLIFY-BODY
  358. ()
  359. final-form
  360. body-bindings
  361. user-bindings
  362. ()
  363. body-form)
  364. (LET-VALUES body-bindings
  365. (LET-VALUES user-bindings
  366. body-form)))
  367. ;; Iterator-introduced termination conditions only. One test and
  368. ;; no closure needed.
  369. ((%LOOP SIMPLIFY-BODY
  370. (termination-condition ...)
  371. final-form
  372. body-bindings
  373. user-bindings
  374. () ;No user termination conditions
  375. body-form)
  376. (IF (OR termination-condition ...)
  377. final-form
  378. (LET-VALUES body-bindings
  379. (LET-VALUES user-bindings
  380. body-form))))
  381. ;; The closure is needed here because the body bindings shouldn't
  382. ;; be visible in the final form.
  383. ((%LOOP SIMPLIFY-BODY
  384. ()
  385. final-form
  386. body-bindings
  387. user-bindings
  388. (user-termination-condition ...)
  389. body-form)
  390. (LET ((FINISH (LAMBDA () final-form)))
  391. (LET-VALUES body-bindings
  392. (LET-VALUES user-bindings
  393. (IF (OR user-termination-condition ...)
  394. (FINISH)
  395. body-form)))))
  396. ((%LOOP SIMPLIFY-BODY
  397. (termination-condition ...)
  398. final-form
  399. body-bindings
  400. user-bindings
  401. (user-termination-condition ...)
  402. body-form)
  403. (LET ((FINISH (LAMBDA () final-form)))
  404. (IF (OR termination-condition ...)
  405. (FINISH)
  406. (LET-VALUES body-bindings
  407. (LET-VALUES user-bindings
  408. (IF (OR user-termination-condition ...)
  409. (FINISH)
  410. body-form))))))))
  411. ;;;; Accumulators
  412. ;;; Accumulators have the following syntax:
  413. ;;;
  414. ;;; (FOR <result> (ACCUMULATING <generator>))
  415. ;;; (FOR <result> (ACCUMULATING <generator> (IF <condition>)))
  416. ;;; (FOR <result> (ACCUMULATING <generator> => <mapper>)) ;COND-style
  417. ;;; (FOR <result> (ACCUMULATING <generator> <tester> ;SRFI-61-style
  418. ;;; => <mapper>))
  419. ;;;
  420. ;;; In addition, some of them support initial values, which are
  421. ;;; specified with an optional first argument of (INITIAL <initial
  422. ;;; value>). For example, to accumulate a list starting with some tail
  423. ;;; <tail>, write
  424. ;;;
  425. ;;; (FOR <result-list> (LISTING (INITIAL <tail>) <element>)).
  426. (define-syntax listing
  427. (syntax-rules (INITIAL)
  428. ((LISTING variables ((INITIAL tail-expression) . arguments) next . rest)
  429. (%ACCUMULATING variables arguments (((TAIL) tail-expression))
  430. ('() CONS (LAMBDA (RESULT)
  431. (APPEND-REVERSE RESULT TAIL)))
  432. (CONTEXT LISTING
  433. variables
  434. ((INITIAL tail-expression) . arguments))
  435. next . rest))
  436. ((LISTING variables arguments next . rest)
  437. (%ACCUMULATING variables arguments ()
  438. ('() CONS REVERSE)
  439. (CONTEXT LISTING variables arguments)
  440. next . rest))))
  441. (define-syntax listing-reverse
  442. (syntax-rules (INITIAL)
  443. ((LISTING-REVERSE variables ((INITIAL tail-expression) . arguments)
  444. next . rest)
  445. (%ACCUMULATING variables arguments (((TAIL) tail-expression))
  446. (TAIL CONS)
  447. (CONTEXT LISTING-REVERSE
  448. variables
  449. ((INITIAL tail-expression) . arguments))
  450. next . rest))
  451. ((LISTING-REVERSE variables arguments next . rest)
  452. (%ACCUMULATING variables arguments ()
  453. ('() CONS)
  454. (CONTEXT LISTING-REVERSE variables arguments)
  455. next . rest))))
  456. ;;; This is non-reentrant but produces precisely one garbage cons cell.
  457. (define-syntax listing!
  458. (syntax-rules ()
  459. ((LISTING! variables arguments next . rest)
  460. (%LISTING! variables arguments (CONS #F '())
  461. (CONTEXT LISTING! variables arguments)
  462. next . rest))))
  463. (define-syntax listing-into!
  464. (syntax-rules ()
  465. ((LISTING-INTO! variables (first-expression . arguments) next . rest)
  466. (%LISTING! variables arguments first-expression
  467. (CONTEXT LISTING-INTO!
  468. variables
  469. (first-expression . arguments))
  470. next . rest))))
  471. (define-syntax %listing!
  472. (syntax-rules (INITIAL)
  473. ((%LISTING! variables ((INITIAL tail-expression) . arguments)
  474. first-expression
  475. error-context
  476. next . rest)
  477. (%ACCUMULATING variables arguments
  478. (((FIRST TAIL)
  479. (LET ((FIRST first-expression)
  480. (TAIL tail-expression))
  481. (SET-CDR! FIRST TAIL)
  482. (VALUES FIRST TAIL))))
  483. (FIRST (LAMBDA (DATUM PREVIOUS-CELL)
  484. (LET ((NEXT-CELL (CONS DATUM TAIL)))
  485. (SET-CDR! PREVIOUS-CELL NEXT-CELL)
  486. NEXT-CELL))
  487. (LAMBDA (CELL) CELL (CDR FIRST)))
  488. error-context
  489. next . rest))
  490. ((%LISTING! variables arguments first-expression error-context next . rest)
  491. (%LISTING! variables ((INITIAL '()) . arguments)
  492. first-expression
  493. error-context
  494. next . rest))))
  495. ;;;;; List Appending Accumulators
  496. (define-syntax appending
  497. (syntax-rules (INITIAL)
  498. ((APPENDING variables ((INITIAL tail-expression) . arguments)
  499. next . rest)
  500. (%ACCUMULATING variables arguments (((TAIL) tail-expression))
  501. ('() APPEND-REVERSE (LAMBDA (RESULT)
  502. (APPEND-REVERSE RESULT TAIL)))
  503. (CONTEXT APPENDING
  504. variables
  505. ((INITIAL tail-expression) . arguments))
  506. next . rest))
  507. ((APPENDING variables arguments next . rest)
  508. (%ACCUMULATING variables arguments ()
  509. ('() APPEND-REVERSE REVERSE)
  510. (CONTEXT APPENDING variables arguments)
  511. next . rest))))
  512. (define-syntax appending-reverse
  513. (syntax-rules (INITIAL)
  514. ((APPENDING-REVERSE variables ((INITIAL tail-expression) . arguments)
  515. next . rest)
  516. (%ACCUMULATING variables arguments (((TAIL) tail-expression))
  517. (TAIL APPEND-REVERSE)
  518. (CONTEXT APPENDING-REVERSE
  519. variables
  520. ((INITIAL tail-expression) . arguments))
  521. next . rest))
  522. ((APPENDING-REVERSE variables arguments next . rest)
  523. (%ACCUMULATING variables arguments ()
  524. ('() APPEND-REVERSE)
  525. (CONTEXT APPENDING-REVERSE variables arguments)
  526. next . rest))))
  527. ;; (define (append-reverse list tail)
  528. ;; (loop ((FOR elt (IN-LIST list))
  529. ;; (FOR result (LISTING-REVERSE (INITIAL tail) elt)))
  530. ;; => result))
  531. (define (append-reverse list tail)
  532. (if (pair? list)
  533. (append-reverse (cdr list) (cons (car list) tail))
  534. tail))
  535. ;;;;; Numerical Accumulators
  536. (define-syntax summing
  537. (syntax-rules (INITIAL)
  538. ((SUMMING variables ((INITIAL initial-expression) . arguments) next . rest)
  539. (%ACCUMULATING variables arguments () (initial-expression +)
  540. (CONTEXT SUMMING
  541. variables
  542. ((INITIAL initial-expression) . arguments))
  543. next . rest))
  544. ((SUMMING variables arguments next . rest)
  545. (%ACCUMULATING variables arguments () (0 +)
  546. (CONTEXT SUMMING variables arguments)
  547. next . rest))))
  548. (define-syntax multiplying
  549. (syntax-rules (INITIAL)
  550. ((MULTIPLYING variables ((INITIAL initial-expression) . arguments)
  551. next . rest)
  552. (%ACCUMULATING variables arguments () (initial-expression *)
  553. (CONTEXT MULTIPLYING
  554. variables
  555. ((INITIAL initial-expression) . arguments))
  556. next . rest))
  557. ((MULTIPLYING variables arguments next . rest)
  558. (%ACCUMULATING variables arguments () (1 *)
  559. (CONTEXT MULTIPLYING variables arguments)
  560. next . rest))))
  561. (define-syntax maximizing
  562. (syntax-rules ()
  563. ((MAXIMIZING variables arguments next . rest)
  564. (%EXTREMIZING variables arguments MAX
  565. (CONTEXT MAXIMIZING variables arguments)
  566. next . rest))))
  567. (define-syntax minimizing
  568. (syntax-rules ()
  569. ((MINIMIZING variables arguments next . rest)
  570. (%EXTREMIZING variables arguments MIN
  571. (CONTEXT MINIMIZING variables arguments)
  572. next . rest))))
  573. (define-syntax %extremizing
  574. (syntax-rules (INITIAL)
  575. ((%EXTREMIZING variables ((INITIAL initial-expression) . arguments)
  576. chooser
  577. error-context next . rest)
  578. (%ACCUMULATING variables arguments (((INITIAL-VALUE) initial-expression))
  579. (INITIAL-VALUE chooser)
  580. error-context next . rest))
  581. ((%EXTREMIZING variables arguments chooser error-context next . rest)
  582. (%ACCUMULATING variables arguments ()
  583. (#F (LAMBDA (DATUM EXTREME)
  584. (IF (AND DATUM EXTREME)
  585. (chooser DATUM EXTREME)
  586. (OR DATUM EXTREME))))
  587. error-context next . rest))))
  588. (define-syntax %accumulating
  589. (syntax-rules ()
  590. ;; There is a finalization step, so the result variable cannot be
  591. ;; the accumulator variable, and we must apply the finalizer at the
  592. ;; end.
  593. ((%ACCUMULATING (result-variable) arguments outer-bindings
  594. (initializer combiner finalizer)
  595. error-context
  596. next . rest)
  597. (LOOP-CLAUSE-ERROR-IF-NOT-NAME result-variable error-context
  598. (%%ACCUMULATING arguments (ACCUMULATOR initializer combiner)
  599. outer-bindings
  600. (((result-variable) (finalizer ACCUMULATOR)))
  601. error-context
  602. next . rest)))
  603. ;; There is no finalizer step, so the accumulation is incremental,
  604. ;; and can be exploited; therefore, the result variable and the
  605. ;; accumulator variable are one and the same.
  606. ((%ACCUMULATING (accumulator-variable) arguments outer-bindings
  607. (initializer combiner)
  608. error-context
  609. next . rest)
  610. (LOOP-CLAUSE-ERROR-IF-NOT-NAME accumulator-variable error-context
  611. (%%ACCUMULATING arguments (accumulator-variable initializer combiner)
  612. outer-bindings
  613. ()
  614. error-context
  615. next . rest)))
  616. ;; The user supplied more than one variable. Lose lose.
  617. ((%ACCUMULATING variables arguments outer-bindings parameters
  618. error-context next . rest)
  619. (LOOP-CLAUSE-ERROR error-context))))
  620. (define-syntax %%%accumulating
  621. (syntax-rules ()
  622. ((%%%ACCUMULATING outer-bindings loop-variable final-bindings next . rest)
  623. (next outer-bindings
  624. (loop-variable)
  625. () ;Entry bindings
  626. () ;Termination conditions
  627. () ;Body bindings
  628. final-bindings
  629. . rest))))
  630. (define-syntax %%accumulating
  631. (syntax-rules (IF =>)
  632. ((%%ACCUMULATING (generator) ;No conditional
  633. (accumulator initializer combiner)
  634. outer-bindings final-bindings error-context next . rest)
  635. (%%%ACCUMULATING outer-bindings
  636. (accumulator initializer ;Loop variable
  637. (combiner generator accumulator))
  638. final-bindings next . rest))
  639. ((%%ACCUMULATING (generator (IF condition))
  640. (accumulator initializer combiner)
  641. outer-bindings final-bindings error-context next . rest)
  642. (%%%ACCUMULATING outer-bindings
  643. (accumulator initializer ;Loop variable
  644. (IF condition
  645. (combiner generator accumulator)
  646. accumulator))
  647. final-bindings next . rest))
  648. ((%%ACCUMULATING (generator => mapper)
  649. (accumulator initializer combiner)
  650. outer-bindings final-bindings error-context next . rest)
  651. (%%%ACCUMULATING outer-bindings
  652. (accumulator initializer ;Loop variable
  653. (COND (generator
  654. => (LAMBDA (DATUM)
  655. (combiner (mapper DATUM)
  656. accumulator)))
  657. (ELSE accumulator)))
  658. final-bindings next . rest))
  659. ((%%ACCUMULATING (generator tester => mapper)
  660. (accumulator initializer combiner)
  661. outer-bindings final-bindings error-context next . rest)
  662. (%%%ACCUMULATING outer-bindings
  663. (accumulator initializer ;Loop variable
  664. (RECEIVE ARGS generator
  665. (IF (APPLY tester ARGS)
  666. (combiner (APPLY mapper ARGS)
  667. accumulator)
  668. accumulator)))
  669. final-bindings next . rest))
  670. ((%%ACCUMULATING arguments parameters outer-bindings final-bindings
  671. error-context next . rest)
  672. (LOOP-CLAUSE-ERROR error-context))))
  673. ;;;; List Iteration
  674. ;;; (FOR <elt> [<pair>] (IN-LIST <list> [<successor>]))
  675. ;;; Step across <list>, letting <pair> be each successive pair in
  676. ;;; <list>, stepping by (<successor> <pair>), or (CDR <pair>) if no
  677. ;;; successor procedure is explicitly provided. Let <elt> be the car
  678. ;;; of <pair> in the body of the loop.
  679. (define-syntax in-list
  680. (syntax-rules ()
  681. ((IN-LIST (element-variable pair-variable)
  682. (list-expression successor-expression)
  683. next . rest)
  684. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES (element-variable pair-variable)
  685. (CONTEXT IN-LIST
  686. (element-variable pair-variable)
  687. (list-expression successor-expression))
  688. (next (((LIST) list-expression) ;Outer bindings
  689. ((SUCCESSOR) successor-expression))
  690. ((pair-variable LIST TAIL)) ;Loop variables
  691. () ;Entry bindings
  692. ((NOT (PAIR? pair-variable))) ;Termination conditions
  693. (((element-variable) (CAR pair-variable)) ;Body bindings
  694. ((TAIL) (SUCCESSOR pair-variable)))
  695. () ;Final bindings
  696. . rest)))
  697. ((IN-LIST (element-variable pair-variable) (list-expression) next . rest)
  698. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES (element-variable pair-variable)
  699. (CONTEXT IN-LIST (element-variable pair-variable) (list-expression))
  700. ;++ This is silly, but it will improve performance in Scheme
  701. ;++ systems that don't beta-reduce (LET ((X CDR)) ...).
  702. (next (((LIST) list-expression)) ;Outer bindings
  703. ((pair-variable LIST TAIL)) ;Loop variables
  704. () ;Entry bindings
  705. ((NOT (PAIR? pair-variable))) ;Termination conditions
  706. (((element-variable) (CAR pair-variable)) ;Body bindings
  707. ((TAIL) (CDR pair-variable)))
  708. () ;Final bindings
  709. . rest)))
  710. ((IN-LIST (element-variable) (list-expression successor) next . rest)
  711. (LOOP-CLAUSE-ERROR-IF-NOT-NAME element-variable
  712. (CONTEXT IN-LIST (element-variable) (list-expression successor))
  713. (IN-LIST (element-variable PAIR)
  714. (list-expression successor)
  715. next . rest)))
  716. ((IN-LIST (element-variable) (list-expression) next . rest)
  717. (LOOP-CLAUSE-ERROR-IF-NOT-NAME element-variable
  718. (CONTEXT IN-LIST (element-variable) (list-expression))
  719. (IN-LIST (element-variable PAIR) (list-expression) next . rest)))
  720. ((IN-LIST variables arguments next . rest)
  721. (LOOP-CLAUSE-ERROR (CONTEXT IN-LIST variables arguments)))))
  722. ;;;;; Parallel List Iteration
  723. (define-syntax in-lists
  724. (syntax-rules ()
  725. ((IN-LISTS (elements-variable pairs-variable)
  726. (lists-expression tail-expression)
  727. next . rest)
  728. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES (element-variable pair-variable)
  729. (CONTEXT IN-LISTS
  730. (elements-variable pairs-variable)
  731. (lists-expression tail-expression))
  732. (next (((LISTS) lists-expression)) ;Outer bindings
  733. ((pairs-variable LISTS CDRS)) ;Loop variables
  734. (((LOSE? CARS CDRS) ;Entry bindings
  735. (%CARS&CDRS pairs-variable tail-expression '())))
  736. (LOSE?) ;Termination conditions
  737. (((elements-variable) CARS)) ;Body bindings
  738. () ;Final bindings
  739. . rest)))
  740. ((IN-LISTS (elements-variable pairs-variable) (lists) next . rest)
  741. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES (elements-variable pair-variable)
  742. (CONTEXT IN-LISTS (elements-variable pairs-variable) (lists))
  743. (IN-LISTS (elements-variable pairs-variable) (lists '()) next . rest)))
  744. ((IN-LISTS (elements-variable) (lists tail) next . rest)
  745. (LOOP-CLAUSE-ERROR-IF-NOT-NAME elements-variable
  746. (CONTEXT IN-LISTS (elements-variable) (lists tail))
  747. (IN-LISTS (elements-variable PAIRS) (lists tail) next . rest)))
  748. ((IN-LISTS (elements-variable) (lists) next . rest)
  749. (LOOP-CLAUSE-ERROR-IF-NOT-NAME elements-variable
  750. (CONTEXT IN-LISTS (elements-variable) (lists))
  751. (IN-LISTS (elements-variable PAIRS) (lists '()) next . rest)))
  752. ((IN-LISTS variables arguments next . rest)
  753. (LOOP-CLAUSE-ERROR (CONTEXT IN-LISTS variables arguments)))))
  754. (define (%cars&cdrs lists cars-tail cdrs-tail)
  755. (loop proceed ((for list (in-list lists))
  756. (for cars (listing (initial cars-tail) (car list)))
  757. (for cdrs (listing (initial cdrs-tail) (cdr list))))
  758. => (values #f cars cdrs)
  759. (if (pair? list)
  760. (proceed)
  761. (values #t #f #f))))
  762. ;;;; Vector and String Iteration
  763. ;;; (FOR <elt> [<index>] (IN-VECTOR <vector> [<start> [<end>]]))
  764. ;;;
  765. ;;; IN-VECTOR-REVERSE, IN-STRING, and IN-STRING-REVERSE all have the
  766. ;;; same syntax.
  767. ;;;
  768. ;;; The reverse iterators run from end to start; the bounds are still
  769. ;;; given in the same order as the forward iterators.
  770. (define-syntax in-vector
  771. (syntax-rules ()
  772. ((IN-VECTOR variables (vector-expression start/end ...) next . rest)
  773. (%IN-VECTOR (FORWARD VECTOR-REF VECTOR 0 (VECTOR-LENGTH VECTOR))
  774. variables (vector-expression start/end ...)
  775. (CONTEXT IN-VECTOR
  776. variables
  777. (vector-expression start/end ...))
  778. next . rest))))
  779. (define-syntax in-vector-reverse
  780. (syntax-rules ()
  781. ((IN-VECTOR-REVERSE variables (vector-expression start/end ...)
  782. next . rest)
  783. (%IN-VECTOR (BACKWARD VECTOR-REF VECTOR (VECTOR-LENGTH VECTOR) 0)
  784. variables (vector-expression start/end ...)
  785. (CONTEXT IN-VECTOR-REVERSE
  786. variables
  787. (vector-expression start/end ...))
  788. next . rest))))
  789. (define-syntax in-string
  790. (syntax-rules ()
  791. ((IN-STRING variables (vector-expression start/end ...) next . rest)
  792. (%IN-VECTOR (FORWARD STRING-REF STRING 0 (STRING-LENGTH STRING))
  793. variables (vector-expression start/end ...)
  794. (CONTEXT IN-STRING
  795. variables
  796. (vector-expression start/end ...))
  797. next . rest))))
  798. (define-syntax in-string-reverse
  799. (syntax-rules ()
  800. ((IN-STRING-REVERSE variables (string-expression start/end ...)
  801. next . rest)
  802. (%IN-VECTOR (BACKWARD STRING-REF STRING (STRING-LENGTH STRING) 0)
  803. variables (string-expression start/end ...)
  804. (CONTEXT IN-STRING-REVERSE
  805. variables
  806. (string-expression start/end ...))
  807. next . rest))))
  808. ;;;;; Random-Access Sequence Generalization
  809. (define-syntax %in-vector
  810. (syntax-rules (FORWARD BACKWARD)
  811. ((%IN-VECTOR (FORWARD vector-ref vector-variable default-start default-end)
  812. (element-variable index-variable)
  813. (vector-expression start-expression end-expression)
  814. error-context next . rest)
  815. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES (element-variable index-variable)
  816. error-context
  817. (next (((vector-variable START END) ;Outer bindings
  818. (LET ((vector-variable vector-expression))
  819. (VALUES vector-variable start-expression end-expression))))
  820. ((index-variable START ;Loop variables
  821. (+ index-variable 1)))
  822. () ;Entry bindings
  823. ((>= index-variable END)) ;Termination conditions
  824. (((element-variable) ;Body bindings
  825. (vector-ref vector-variable index-variable)))
  826. () ;Final bindings
  827. . rest)))
  828. ((%IN-VECTOR (BACKWARD
  829. vector-ref vector-variable default-start default-end)
  830. (element-variable index-variable)
  831. (vector-expression start-expression end-expression)
  832. error-context next . rest)
  833. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES (element-variable index-variable)
  834. error-context
  835. (next (((vector-variable START END) ;Outer bindings
  836. (LET ((vector-variable vector-expression))
  837. (VALUES vector-variable start-expression end-expression))))
  838. ((index-variable START ;Loop variables
  839. index-variable))
  840. () ;Entry bindings
  841. ((<= index-variable END)) ;Termination conditions
  842. (((index-variable) ;Body bindings
  843. (- index-variable 1))
  844. ((element-variable)
  845. (vector-ref vector-variable (- index-variable 1))))
  846. () ;Final bindings
  847. . rest)))
  848. ;;;;;; %IN-VECTOR, continued
  849. ;; Supply an index variable if absent.
  850. ((%IN-VECTOR iteration-parameters (element-variable) arguments
  851. error-context next . rest)
  852. (LOOP-CLAUSE-ERROR-IF-NOT-NAME element-variable error-context
  853. (%IN-VECTOR iteration-parameters (element-variable INDEX) arguments
  854. error-context next . rest)))
  855. ;; Supply the default start index if necessary.
  856. ((%IN-VECTOR (direction vector-ref variable default-start default-end)
  857. variables (vector-expression)
  858. error-context next . rest)
  859. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES variables error-context
  860. (%IN-VECTOR (direction vector-ref variable default-start default-end)
  861. variables (vector-expression default-start)
  862. error-context next . rest)))
  863. ;; Supply the default end index if necessary.
  864. ((%IN-VECTOR (direction vector-ref variable default-start default-end)
  865. variables (vector-expression start-expression)
  866. error-context next . rest)
  867. (LOOP-CLAUSE-ERROR-IF-NOT-NAMES variables error-context
  868. (%IN-VECTOR (direction vector-ref variable default-start default-end)
  869. variables (vector-expression start-expression default-end)
  870. error-context next . rest)))
  871. ((%IN-VECTOR iteration-parameters modified-variables modified-arguments
  872. error-context next . rest)
  873. (LOOP-CLAUSE-ERROR error-context))))
  874. ;;;; Input
  875. ;;; (FOR <item> (IN-PORT <input-port> [<reader> [<eof?>]]))
  876. ;;;
  877. ;;; IN-FILE has the same syntax, but with a pathname in the place of
  878. ;;; the input port.
  879. (define-syntax in-port
  880. (syntax-rules ()
  881. ((IN-PORT (datum-variable)
  882. (port-expression reader-expression eof-predicate)
  883. next . rest)
  884. (LOOP-CLAUSE-ERROR-IF-NOT-NAME datum-variable
  885. (CONTEXT IN-PORT
  886. (datum-variable)
  887. (port-expression reader-expression eof-predicate))
  888. (next (((PORT) port-expression) ;Outer bindings
  889. ((READER) reader-expression)
  890. ((EOF?) eof-predicate))
  891. () ;Loop variables
  892. (((datum-variable) (READER PORT))) ;Entry bindings
  893. ((EOF? datum-variable)) ;Termination conditions
  894. () ;Body bindings
  895. () ;Final bindings
  896. . rest)))
  897. ;; Supply a reader if absent.
  898. ((IN-PORT (datum-variable) (port-expression) next . rest)
  899. (LOOP-CLAUSE-ERROR-IF-NOT-NAME datum-variable
  900. (CONTEXT IN-PORT (datum-variable) (port-expression))
  901. (IN-PORT (datum-variable) (port-expression READ-CHAR) next . rest)))
  902. ;; Supply an EOF predicate if absent.
  903. ((IN-PORT (datum-variable) (port-expression reader-expression) next . rest)
  904. (LOOP-CLAUSE-ERROR-IF-NOT-NAME datum-variable
  905. (CONTEXT IN-PORT (datum-variable) (port-expression reader-expression))
  906. (IN-PORT (datum-variable)
  907. (port-expression reader-expression EOF-OBJECT?)
  908. next . rest)))
  909. ((IN-PORT variables arguments next . rest)
  910. (LOOP-CLAUSE-ERROR (CONTEXT IN-PORT variables arguments)))))
  911. (define-syntax in-file
  912. (syntax-rules ()
  913. ((IN-FILE (datum-variable)
  914. (pathname-expression reader-expression eof-predicate)
  915. next . rest)
  916. (LOOP-CLAUSE-ERROR-IF-NOT-NAME datum-variable
  917. (CONTEXT IN-FILE
  918. (datum-variable)
  919. (pathname-expression reader-expression eof-predicate))
  920. (next (((PORT) ;Outer bindings
  921. (OPEN-INPUT-FILE pathname-expression))
  922. ((READER) reader-expression)
  923. ((EOF?) eof-predicate))
  924. () ;Loop variables
  925. (((datum-variable) (READER PORT))) ;Entry bindings
  926. ((EOF? datum-variable)) ;Termination conditions
  927. () ;Body bindings
  928. ((() ;Final bindings
  929. (BEGIN (CLOSE-INPUT-PORT PORT)
  930. (VALUES))))
  931. . rest)))
  932. ;; Supply a reader if absent.
  933. ((IN-FILE (datum-variable) (pathname-expression) next . rest)
  934. (LOOP-CLAUSE-ERROR-IF-NOT-NAME datum-variable
  935. (CONTEXT IN-FILE (datum-variable) (pathname-expression))
  936. (IN-FILE (datum-variable) (pathname-expression READ-CHAR) next . rest)))
  937. ;; Supply an EOF predicate if absent.
  938. ((IN-FILE (datum-variable)
  939. (pathname-expression reader-expression)
  940. next . rest)
  941. (LOOP-CLAUSE-ERROR-IF-NOT-NAME datum-varable
  942. (CONTEXT IN-FILE
  943. (datum-variable)
  944. (pathname-expression reader-expression))
  945. (IN-FILE (datum-variable)
  946. (pathname-expression reader-expression EOF-OBJECT?)
  947. next . rest)))
  948. ((IN-FILE variables arguments next . rest)
  949. (LOOP-CLAUSE-ERROR (CONTEXT IN-FILE variables arguments)))))
  950. ;;;; Iterating Up through Numbers
  951. (define-syntax up-from
  952. (syntax-rules (TO BY)
  953. ((UP-FROM (variable)
  954. (start-expression (TO end-expression)
  955. (BY step-expression))
  956. next . rest)
  957. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  958. (CONTEXT UP-FROM
  959. (variable)
  960. (start-expression (TO end-expression) (BY step-expression)))
  961. (next (((START) start-expression) ;Outer bindings
  962. ((END) end-expression)
  963. ((STEP) step-expression))
  964. ((variable START ;Loop variables
  965. (+ variable STEP)))
  966. () ;Entry bindings
  967. ((>= variable END)) ;Termination conditions
  968. () ;Body bindings
  969. () ;Final bindings
  970. . rest)))
  971. ((UP-FROM (variable)
  972. (start-expression (BY step-expression))
  973. next . rest)
  974. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  975. (CONTEXT UP-FROM (variable) (start-expression (BY step-expression)))
  976. (next (((START) start-expression) ;Outer bindings
  977. ((STEP) step-expression))
  978. ((variable START ;Loop variables
  979. (+ variable STEP)))
  980. () ;Entry bindings
  981. () ;Termination conditions
  982. () ;Body bindings
  983. () ;Final bindings
  984. . rest)))
  985. ;; Add a default step of 1.
  986. ((UP-FROM (variable)
  987. (start-expression (TO end-expression))
  988. next . rest)
  989. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  990. (CONTEXT UP-FROM (variable) (start-expression (TO end-expression)))
  991. (UP-FROM (variable)
  992. (start-expression (TO end-expression) (BY 1))
  993. next . rest)))
  994. ((UP-FROM (variable)
  995. (start-expression)
  996. next . rest)
  997. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  998. (CONTEXT UP-FROM (variable) (start-expression))
  999. (UP-FROM (variable)
  1000. (start-expression (BY 1))
  1001. next . rest)))
  1002. ((UP-FROM variables arguments next . rest)
  1003. (LOOP-CLAUSE-ERROR (CONTEXT UP-FROM variables arguments)))))
  1004. ;;;; Iterating Down through Numbers
  1005. (define-syntax down-from
  1006. (syntax-rules (TO BY)
  1007. ((DOWN-FROM (variable)
  1008. (start-expression (TO end-expression)
  1009. (BY step-expression))
  1010. next . rest)
  1011. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  1012. (CONTEXT DOWN-FROM
  1013. (variable)
  1014. (start-expression (TO end-expression) (BY step-expression)))
  1015. (next (((START) start-expression) ;Outer bindings
  1016. ((END) end-expression)
  1017. ((STEP) step-expression))
  1018. ((variable START variable)) ;Loop variables
  1019. () ;Entry bindings
  1020. ((<= variable END)) ;Termination conditions
  1021. (((variable) ;Body bindings
  1022. (- variable STEP)))
  1023. () ;Final bindings
  1024. . rest)))
  1025. ((DOWN-FROM (variable)
  1026. (start-expression (BY step-expression))
  1027. next . rest)
  1028. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  1029. (CONTEXT DOWN-FROM (variable) (start-expression (BY step-expression)))
  1030. (next (((START) start-expression) ;Outer bindings
  1031. ((STEP) step-expression))
  1032. ((variable START variable)) ;Loop variables
  1033. (((variable) (- variable STEP))) ;Entry bindings
  1034. () ;Termination conditions
  1035. () ;Body bindings
  1036. () ;Final bindings
  1037. . rest)))
  1038. ;; Add a default step of 1.
  1039. ((DOWN-FROM (variable)
  1040. (start-expression (TO end-expression))
  1041. next . rest)
  1042. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  1043. (CONTEXT DOWN-FROM (variable) (start-expression (TO end-expression)))
  1044. (DOWN-FROM (variable)
  1045. (start-expression (TO end-expression) (BY 1))
  1046. next . rest)))
  1047. ((DOWN-FROM (variable)
  1048. (start-expression)
  1049. next . rest)
  1050. (LOOP-CLAUSE-ERROR-IF-NOT-NAME variable
  1051. (CONTEXT DOWN-FROM (variable) (start-expression))
  1052. (DOWN-FROM (variable)
  1053. (start-expression (BY 1))
  1054. next . rest)))
  1055. ((DOWN-FROM variables arguments next . rest)
  1056. (LOOP-CLAUSE-ERROR (CONTEXT DOWN-FROM variables arguments)))))