Big, buggy commit

:for clauses now have finalizers! This means (in-file "path") now works. This meant I had to do some restructuring of many nasty pieces of code, but I believe it works. cl-next was broken up into cl-next/acc and cl-next/for. Accumulators have to pass :acc to (cl-next/acc ...). I plan for :for clauses to do the same.

I fixed tests.scm and README.md to reflect the de-racketification of the for loops.
This commit is contained in:
Linus 2020-11-25 20:40:48 +01:00
parent 1a826f86e2
commit 0c110dd080
4 changed files with 175 additions and 126 deletions

View file

@ -5,10 +5,10 @@ WARNING: CURRENTLY PRE-ALPHA. The examples in this document are not consistent w
goof-loops aims to be an amalgamation of the racket for loops and Alex Shinn's (chibi-loop). We are many that found racket's for loops a breeze of fresh air, but in the end their most general forms (for/fold and for/foldr) are kinda odd to work with. If you choose not to use those general for loops, you cannot express arbitrary transformations, like say a fibonacci sequence, since for clauses cannot reference eachother. goof-loop tries to fix this: goof-loops aims to be an amalgamation of the racket for loops and Alex Shinn's (chibi-loop). We are many that found racket's for loops a breeze of fresh air, but in the end their most general forms (for/fold and for/foldr) are kinda odd to work with. If you choose not to use those general for loops, you cannot express arbitrary transformations, like say a fibonacci sequence, since for clauses cannot reference eachother. goof-loop tries to fix this:
``` ```
(loop ((a (in 0 b)) (loop ((:for a (in 0 b))
(b (in 1 (+ a b))) (:for b (in 1 (+ a b)))
(count (up-from 0 (to 1000))) (count (up-from 0 (to 1000)))
(acc (listing b))) (:acc acc (listing b)))
=> acc => acc
(display b) (newline)) (display b) (newline))
``` ```
@ -19,23 +19,23 @@ Compared to foof-loop, some things are added. Apart from minor syntactic changes
``` ```
(define lst '((1 2) dud (3 4) (5 6))) (define lst '((1 2) dud (3 4) (5 6)))
(loop ((a (in-list lst)) (loop ((:for a (in-list lst))
:when (pair? a) :when (pair? a)
(b (in-list a)) (:for b (in-list a))
(acc (summing b))) (:acc acc (summing b)))
=> acc) => acc)
``` ```
This will sum all the sublists of lst and produce the result 21. Any :when, :unless, :break, or :subloop clause will break out a subloop if any subsequent for clauses are found. This will sum all the sublists of lst and produce the result 21. Any :when, :unless, :break, :final, or :subloop clause will break out a subloop if any subsequent for clauses are found.
Accumulators can be in any of the loop's stages: Accumulators can be in any of the loop's stages:
``` ```
(loop ((a (in-list '(1 2 3))) (loop ((:for a (in-list '(1 2 3)))
(aa (summing a)) (:acc aa (summing a))
:subloop :subloop
(b (up-from a (to (+ a 2)))) (:for b (up-from a (to (+ a 2))))
(ab (listing b))) (:acc ab (listing b)))
=> (values aa ab)) => (values aa ab))
;; => (values 6 (1 2 2 3 3 4)) ;; => (values 6 (1 2 2 3 3 4))
``` ```
@ -44,34 +44,32 @@ Accumulators can be in any of the loop's stages:
### syntactical ### syntactical
No more (for ...). Every clause is now a for-clause. This is because the addition of subloops and accumulators removed the usefulness of having a simple case that acts just as named let. for-clauses are split into :for and :let clauses. This is because the addition of subloops means we have to treat accumulators differently.
while and until are removed in favour of :break. while and until are removed in favour of :break.
:when and :unless are added to better control when the loop body is executed (and accumulators accumulated) :when and :unless are added to better control when the loop body is executed (and accumulators accumulated)
with-clauses are removed in favour of (var (in init [step [stop]])) or (var (folding init [step])) in case of accumulators. with-clauses are removed in favour of (:forvar (in init [step [stop]])) or (:acc var (folding init [step])) in case of accumulators.
### Regressions compared to foof-loop ### Regressions compared to foof-loop
only accumulating clauses are visible in the final-expression. This is due to sequence clauses not being promoted through to outer loops (since they should not keep their state). only accumulating clauses are visible in the final-expression. This is due to sequence clauses not being promoted through to outer loops (since they should not keep their state).
sequence clauses cannot finalize, due to the above thing. The reason for distinguishing between sequences and accumulators is to be able to promote accumulators outwards and finalizers inwards. This is not implemented yet, however.
Due to clause reordering, positional updates are not supported. If you want to update your loop vars, do so using named update (see below). Due to clause reordering, positional updates are not supported. If you want to update your loop vars, do so using named update (see below).
### changes ### changes
(with var [init [step [guard]]]) => (var (in init [step [stop-expr]])). guard was a procedure, but now it is an expression. (with var [init [step [guard]]]) => (:for var (in init [step [stop-expr]])). guard was a procedure, but now it is an expression.
(with var 10 (- var 1) negative?) => (var (in 10 (- var 10) (negative? var))) (with var 10 (- var 1) negative?) => (:for var (in 10 (- var 10) (negative? var)))
### similarities ### similarities
You can of course still have a larger control of your loops: You can of course still have a larger control of your loops:
``` ```
(loop loopy-loop ((a (up-from 1 (to 11)))) (loop loopy-loop ((:for a (up-from 1 (to 11))))
=> '() => '()
(if (odd? a) (if (odd? a)
(cons (* a (- a)) (loopy-loop)) (cons (* a (- a)) (loopy-loop))
@ -85,9 +83,9 @@ Named updates also work.
``` ```
;; Shamelessly stolen from Taylor Campbell's foof-loop documentation ;; Shamelessly stolen from Taylor Campbell's foof-loop documentation
(define (partition list predicate) (define (partition list predicate)
(loop continue ((element (in-list list)) (loop continue ((:for element (in-list list))
(satisfied (folding '())) (:acc satisfied (folding '()))
(unsatisfied (folding '()))) (:acc unsatisfied (folding '())))
=> (values (reverse satisfied) => (values (reverse satisfied)
(reverse unsatisfied)) (reverse unsatisfied))
(if (predicate element) (if (predicate element)
@ -100,11 +98,9 @@ Named updates also work.
## Todo ## Todo
Should we add finalizers for sequence-clauses? I can't see the need outside of a potential (in-file ...), which can't be properly supported anyway since I won't do any dynamic-wind stuff. Tests and documentation.
Add racket #:final clauses. Fix the inlining behavious of some of the :for iterators.
Add simple versions of loop. loop/list (done), loop/sum, loop/last, loop/first, and so on.
## foof, what a guy ## foof, what a guy

197
goof.scm
View file

@ -63,19 +63,20 @@
((loop (clauses ...) body ...) ((loop (clauses ...) body ...)
(cl (loop (clauses ...) body ...) (cl (loop (clauses ...) body ...)
loop-name loop-name
(()) (()) (()) (()) (()) () (()) (()) (()) () (()) (()) (()) (()) (()) () ((() ())) (()) (()) (()) ()
(clauses ...) (clauses ...)
body ... (loop-name))) body ... (loop-name)))
((loop name (clauses ...) . body) ((loop name (clauses ...) . body)
(cl (loop name (clauses ...) . body) (cl (loop name (clauses ...) . body)
name name
(()) (()) (()) (()) (()) () (()) (()) (()) () (()) (()) (()) (()) (()) () ((() ())) (()) (()) (()) ()
(clauses ...) (clauses ...)
. body)))) . body))))
(define-syntax push-new-subloop (define-syntax push-new-subloop
(syntax-rules () (syntax-rules ()
((_ orig name (lets ...) (accs ...) (vars ...) (checks ...) (refs ...) f (ul ...) (uw ...) (ub ...) uf clauses . body) ((_ orig name (lets ...) (accs ...) (vars ...) (checks ...) (refs ...) f (((ff-cur ...) (ff-above ...)) . ff-rest)
(ul ...) (uw ...) (ub ...) uf clauses . body)
(cl orig name (cl orig name
(() lets ...) (() lets ...)
(() accs ...) (() accs ...)
@ -83,6 +84,8 @@
(() checks ...) (() checks ...)
(() refs ...) (() refs ...)
f f
;; propagate :for-finalizers to subloop to be run in case of :break
((() (ff-cur ... ff-above ...)) ((ff-cur ...) (ff-above ...)) . ff-rest)
(() ul ...) (() ul ...)
(() uw ...) (() uw ...)
(() ub ...) (() ub ...)
@ -93,70 +96,73 @@
;; Clauses sorts all the clauses into subloops and positions everything where it should be. ;; Clauses sorts all the clauses into subloops and positions everything where it should be.
(define-syntax cl (define-syntax cl
(syntax-rules (=> :for :acc :when :unless :break :final :let :let* :subloop) (syntax-rules (=> :for :acc :when :unless :break :final :let :let* :subloop)
((_ orig name l a v c r f ul uw ub uf () => expr . body) ((_ orig name l a v c r f ff ul uw ub uf () => expr . body)
(emit orig name l a v c r f ul uw ub uf expr . body)) (emit orig name l a v c r f ff ul uw ub uf expr . body))
((_ orig name l a v c r f ul uw ub uf () . body) ((_ orig name l a v c r f ff ul uw ub uf () . body)
(emit orig name l a v c r f ul uw ub uf (if #f #f) . body)) (emit orig name l a v c r f ff ul uw ub uf (if #f #f) . body))
;; USER LETS ;; USER LETS
((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub uf (:let (id id* ... expr) clauses ...) . body) ((_ orig name l a v c r f ff ((cur-ul ...) . ul-rest) uw ub uf (:let (id id* ... expr) clauses ...) . body)
(cl orig name l a v c r f ((cur-ul ... (:let id id* ... expr)) . ul-rest) uw ub uf (clauses ...) . body)) (cl orig name l a v c r f ff ((cur-ul ... (:let id id* ... expr)) . ul-rest) uw ub uf (clauses ...) . body))
((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub uf (:let* (id id* ... expr) clauses ...) . body) ((_ orig name l a v c r f ff ((cur-ul ...) . ul-rest) uw ub uf (:let* (id id* ... expr) clauses ...) . body)
(cl orig name l a v c r f ((cur-ul ... (:let* id id* ... expr)) . ul-rest) uw ub uf (clauses ...) . body)) (cl orig name l a v c r f ff ((cur-ul ... (:let* id id* ... expr)) . ul-rest) uw ub uf (clauses ...) . body))
;; user-whens ;; user-whens
((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub uf (:when test clauses ...) . body) ((_ orig name l a v c r f ff ul ((cur-uw ...) . uw-rest) ub uf (:when test clauses ...) . body)
(cl orig name l a v c r f ul ((cur-uw ... test) . uw-rest) ub uf (clauses ...) . body)) (cl orig name l a v c r f ff ul ((cur-uw ... test) . uw-rest) ub uf (clauses ...) . body))
((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub uf (:unless test clauses ...) . body) ((_ orig name l a v c r f ff ul ((cur-uw ...) . uw-rest) ub uf (:unless test clauses ...) . body)
(cl orig name l a v c r f ul ((cur-uw ... (not test)) . uw-rest) ub uf (clauses ...) . body)) (cl orig name l a v c r f ff ul ((cur-uw ... (not test)) . uw-rest) ub uf (clauses ...) . body))
;; USER BREAKS ;; USER BREAKS
;; This pushes a #t to the user when expression, thus forcing a subloop if a for-clause is found afterwards. ;; This pushes a #t to the user when expression, thus forcing a subloop if a for-clause is found afterwards.
((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ((cur-ub ...) . ub-rest) uf (:break expr clauses ...) . body) ((_ orig name l a v c r f ff ul ((cur-uw ...) . uw-rest) ((cur-ub ...) . ub-rest) uf (:break expr clauses ...) . body)
(cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ((cur-ub ... expr) . ub-rest) uf (clauses ...) . body)) '(cl orig name l a v c r f ff ul ((cur-uw ... #t) . uw-rest) ((cur-ub ... expr) . ub-rest) uf (clauses ...) . body))
;; user final ;; user final
;; This pushes a #t to the user when expression, thus forcing a subloop if a for-clause is found afterwards. ;; This pushes a #t to the user when expression, thus forcing a subloop if a for-clause is found afterwards.
((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (cur-uf ...) (:final expr clauses ...) . body) ((_ orig name l a v c r f ff ul ((cur-uw ...) . uw-rest) ub (cur-uf ...) (:final expr clauses ...) . body)
(cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub (cur-uf ... expr) (clauses ...) . body)) '(cl orig name l a v c r f ff ul ((cur-uw ... #t) . uw-rest) ub (cur-uf ... expr) (clauses ...) . body))
;; Explicit subloop. Shorthand for (:when #t) ;; Explicit subloop. Shorthand for (:when #t)
((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub uf (:subloop clauses ...) . body) ((_ orig name l a v c r f ff ul ((cur-uw ...) . uw-rest) ub uf (:subloop clauses ...) . body)
(cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub uf (clauses ...) . body)) (cl orig name l a v c r f ff ul ((cur-uw ... #t) . uw-rest) ub uf (clauses ...) . body))
;; :for-clauses ;; :for-clauses
;; found a for clause when we have a :when or :unless clause. Push new subloop ;; found a for clause when we have a :when or :unless clause. Push new subloop
((_ orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub uf ((:for for-rest ...) clauses ...) . body) ((_ orig name l a v c r f ff ul ((uw uw* ...) . uw-rest) ub uf ((:for for-rest ...) clauses ...) . body)
(push-new-subloop orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub uf ((:for for-rest ...) clauses ...) . body)) (push-new-subloop orig name l a v c r f ff ul ((uw uw* ...) . uw-rest) ub uf ((:for for-rest ...) clauses ...) . body))
;; For clause with a sequence creator. ;; For clause with a sequence creator.
((_ orig name l a v c r f ul uw ub uf ((:for id ids ... (iterator source ...)) clauses ...) . body) ((_ orig name l a v c r f ff ul uw ub uf ((:for id ids ... (iterator source ...)) clauses ...) . body)
(iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub uf (clauses ...) . body)) (iterator ((id ids ...) (source ...)) cl-next/for orig name l a v c r f ff ul uw ub uf (clauses ...) . body))
((_ orig name l a v c r f ul uw ub uf ((:acc id ids ... (accumulator source ...)) clauses ...) . body) ;; accumulator clause
(accumulator :acc ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub uf (clauses ...) . body)) ((_ orig name l a v c r f ff ul uw ub uf ((:acc id ids ... (accumulator source ...)) clauses ...) . body)
(accumulator :acc ((id ids ...) (source ...)) cl-next/acc orig name l a v c r f ff ul uw ub uf (clauses ...) . body))
;; no :acc or :for: imlplicit for! ;; no :acc or :for: imlplicit for!
((_ orig name l a v c r f ul uw ub uf ((id ids ... (iterator source ...)) clauses ...) . body) ((_ orig name l a v c r f ff ul uw ub uf ((id ids ... (iterator source ...)) clauses ...) . body)
(cl orig name l a v c r f ul uw ub uf ((:for id ids ... (iterator source ...)) clauses ...) . body)) (cl orig name l a v c r f ff ul uw ub uf ((:for id ids ... (iterator source ...)) clauses ...) . body))
;; ERROR HANDLING? ;; ERROR HANDLING?
((_ orig name l a v c r f ul uw ub uf (clause . rest) . body) ((_ orig name l a v c r f ff ul uw ub uf (clause . rest) . body)
(syntax-error "Invalid clause in loop" clause orig)) '(syntax-error "Invalid clause in loop" clause orig))
)) ))
;; HOLY CODE-DUPLICATION-BATMAN! ;; HOLY CODE-DUPLICATION-BATMAN!
;; cl-next integrates any bindings introduced by a :for or :acc clause. The complexity comes from pushing :acc-clauses ;; cl-next/acc integrates all the bindings by an :acc clause. The complexity comes from pushing :acc-clauses
;; into the outer loops. Since accumulators need to be available in the (final-fun ...), they need to be visible also ;; into the outer loops. Since accumulators need to be available in the (final-fun ...), they need to be visible also
;; in the outer loops if the loop exits there. ;; in the outer loops if the loop exits there.
(define-syntax cl-next (define-syntax cl-next/acc
(syntax-rules (:for :acc) (syntax-rules (:acc)
((_ (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...) ;; :acc clause without any subloops
((_ :acc (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...)
orig name orig name
((lets ...)) ((lets ...))
((accs ...)) ((accs ...))
((vars ...)) ((vars ...))
((checks ...)) ((checks ...))
((refs ...)) ((refs ...))
(finals ...) ul uw ub uf clauses . body) (finals ...)
ff ul uw ub uf clauses . body)
(cl orig name (cl orig name
((lets ... new-lets ...)) ((lets ... new-lets ...))
((accs ... (accvar accinit accupdate) ...)) ((accs ... (accvar accinit accupdate) ...))
@ -164,16 +170,17 @@
((checks ... new-checks ...)) ((checks ... new-checks ...))
((refs ... new-refs ...)) ((refs ... new-refs ...))
(finals ... new-finals ...) (finals ... new-finals ...)
ul uw ub uf clauses . body)) ff ul uw ub uf clauses . body))
;; We have ONE subloop! ;; We have ONE subloop!
((_ (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...) ((_ :acc (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...)
orig name orig name
((lets ...) . lets-rest) ((lets ...) . lets-rest)
((accs ...) ((oldacc oldinit oldupdate) ...)) ((accs ...) ((oldacc oldinit oldupdate) ...))
((vars ...) . vars-rest) ((vars ...) . vars-rest)
((checks ...) . checks-rest) ((checks ...) . checks-rest)
((refs ...) . refs-rest) ((refs ...) . refs-rest)
(finals ...) ul uw ub uf clauses . body) (finals ...)
ff ul uw ub uf clauses . body)
(cl orig name (cl orig name
((lets ... new-lets ...) . lets-rest) ((lets ... new-lets ...) . lets-rest)
((accs ... (accvar accvar accupdate) ...) ((oldacc oldinit oldupdate) ... (accvar accinit accvar) ...)) ((accs ... (accvar accvar accupdate) ...) ((oldacc oldinit oldupdate) ... (accvar accinit accvar) ...))
@ -181,16 +188,17 @@
((checks ... new-checks ...) . checks-rest) ((checks ... new-checks ...) . checks-rest)
((refs ... new-refs ...) . refs-rest) ((refs ... new-refs ...) . refs-rest)
(finals ... new-finals ...) (finals ... new-finals ...)
ul uw ub uf clauses . body)) ff ul uw ub uf clauses . body))
;; We have several subloops! ;; We have several subloops!
((_ (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...) ((_ :acc (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...)
orig name orig name
((lets ...) . lets-rest) ((lets ...) . lets-rest)
((accs ...) ((oldacc oldinit oldupdate) ...) ... ((oldestacc oldestinit oldestupdate) ...)) ((accs ...) ((oldacc oldinit oldupdate) ...) ... ((oldestacc oldestinit oldestupdate) ...))
((vars ...) . vars-rest) ((vars ...) . vars-rest)
((checks ...) . checks-rest) ((checks ...) . checks-rest)
((refs ...) . refs-rest) ((refs ...) . refs-rest)
(finals ...) ul uw ub uf clauses . body) (finals ...)
ff ul uw ub uf clauses . body)
(cl orig name (cl orig name
((lets ... new-lets ...) . lets-rest) ((lets ... new-lets ...) . lets-rest)
((accs ... (accvar accvar accupdate) ...) ((oldacc oldinit oldupdate) ... (accvar accvar accvar) ...) ... ((accs ... (accvar accvar accupdate) ...) ((oldacc oldinit oldupdate) ... (accvar accvar accvar) ...) ...
@ -199,8 +207,33 @@
((checks ... new-checks ...) . checks-rest) ((checks ... new-checks ...) . checks-rest)
((refs ... new-refs ...) . refs-rest) ((refs ... new-refs ...) . refs-rest)
(finals ... new-finals ...) (finals ... new-finals ...)
ul uw ub uf clauses . body)) ff ul uw ub uf clauses . body))))
))
;; Integrating for clauses is not as involved, since they only want to be introduced into the current
;; loop. Any propagation of for finalizers (ff) is done by push-new-subloop
(define-syntax cl-next/for
(syntax-rules ()
((_ (new-lets ...) () (new-vars ...) (new-checks ...) (new-refs ...) (new-for-finals ...)
orig name
((lets ...) . lets-rest)
accs
((vars ...) . vars-rest)
((checks ...) . checks-rest)
((refs ...) . refs-rest)
finals
(((ff-cur ...) (ff-above ...)) . ff-rest)
ul uw ub uf clauses . body)
(cl orig name
((lets ... new-lets ...) . lets-rest)
accs
((vars ... new-vars ...) . vars-rest)
((checks ... new-checks ...) . checks-rest)
((refs ... new-refs ...) . refs-rest)
finals
(((ff-cur ... new-for-finals ...) (ff-above ...)) . ff-rest)
ul uw ub uf clauses . body))
((cl err ...)
'(cl err ...))))
(define-syntax user-let (define-syntax user-let
(syntax-rules (:let :let*) (syntax-rules (:let :let*)
@ -243,6 +276,7 @@
((checks ...)) ((checks ...))
((refs ...)) ((refs ...))
((final-binding final-value) ...) ((final-binding final-value) ...)
(((ff-cur ...) (ff-above ...)))
((user-lets ...)) ((user-whens ...)) ((user-breaks ...)) uf ((user-lets ...)) ((user-whens ...)) ((user-breaks ...)) uf
final-expr . body) final-expr . body)
(let* (lets ...) (let* (lets ...)
@ -250,7 +284,9 @@
final-expr) final-expr)
(define (loopy-loop accvar ... var ...) (define (loopy-loop accvar ... var ...)
(if (or checks ...) (if (or checks ...)
(final-fun final-value ...) (begin
ff-cur ...
(final-fun final-value ...))
(let (refs ...) (let (refs ...)
(user-let () () (user-lets ...) (user-let () () (user-lets ...)
(if (and user-whens ...) (if (and user-whens ...)
@ -258,9 +294,12 @@
(final-fun final-value ...) (final-fun final-value ...)
uf uf
(loopy-loop (accvar accstep) ... (var step) ...) (loopy-loop (accvar accstep) ... (var step) ...)
(if (or user-breaks ...) (cond
(final-fun final-value ...) ((or user-breaks ...)
(let () (if #f #f) . body))) ff-above ... ff-cur ...
(final-fun final-value ...))
(else
(let () (if #f #f) . body))))
(loopy-loop accvar ... step ...)))))) (loopy-loop accvar ... step ...))))))
(loopy-loop accinit ... init ...))))) (loopy-loop accinit ... init ...)))))
@ -274,6 +313,7 @@
(checks-next ... (checks ...)) (checks-next ... (checks ...))
(refs-next ... (refs ...)) (refs-next ... (refs ...))
((final-binding final-value) ...) ((final-binding final-value) ...)
(ff-next ... ((ff-cur ...) ()))
(ul-next ... (user-lets ...)) (ul-next ... (user-lets ...))
(uw-next ... (user-whens ...)) (uw-next ... (user-whens ...))
(ub-next ... (user-breaks ...)) (ub-next ... (user-breaks ...))
@ -285,12 +325,16 @@
(let outer-loop ((accvar accinit) ... (let outer-loop ((accvar accinit) ...
(var init) ...) (var init) ...)
(if (or checks ...) (if (or checks ...)
(final-fun final-value ...) (begin
ff-cur ...
(final-fun final-value ...))
(let (refs ...) (let (refs ...)
(user-let () () (user-lets ...) (user-let () () (user-lets ...)
(if (and user-whens ...) (if (and user-whens ...)
(cond (cond
((or user-breaks ...) (final-fun final-value ...)) ((or user-breaks ...)
ff-cur ...
(final-fun final-value ...))
(else (emit-many/rest orig (else (emit-many/rest orig
name name
(outer-loop accstep ... step ...) (outer-loop accstep ... step ...)
@ -301,6 +345,7 @@
(refs-next ...) (refs-next ...)
;; THIS IS NOW A COMPLETE call to final ;; THIS IS NOW A COMPLETE call to final
(final-fun final-value ...) (final-fun final-value ...)
(ff-next ...)
(ul-next ...) (ul-next ...)
(uw-next ...) (uw-next ...)
(ub-next ...) (ub-next ...)
@ -320,6 +365,7 @@
((checks ...)) ((checks ...))
((refs ...)) ((refs ...))
final final
(((ff-cur ...) (ff-above ...)))
((user-lets ...)) ((user-lets ...))
((user-whens ...)) ((user-whens ...))
((user-breaks ...)) ((user-breaks ...))
@ -329,12 +375,16 @@
(let innermost-loop ((accvar accinit) ... (let innermost-loop ((accvar accinit) ...
(var init) ...) (var init) ...)
(if (or checks ...) (if (or checks ...)
outer (begin
ff-cur ...
outer)
(let (refs ...) (let (refs ...)
(user-let () () (user-lets ...) (user-let () () (user-lets ...)
(if (and user-whens ...) (if (and user-whens ...)
(cond (cond
((or user-breaks ...) final) ((or user-breaks ...)
ff-above ... ff-cur ...
final)
(else (else
(let-kw-form name final uf (innermost-loop (accvar accstep) ... (var step) ...) (let-kw-form name final uf (innermost-loop (accvar accstep) ... (var step) ...)
. body))) . body)))
@ -350,6 +400,7 @@
(next-checks ... (checks ...)) (next-checks ... (checks ...))
(next-refs ... (refs ...)) (next-refs ... (refs ...))
final final
(next-ff ... ((ff-cur ...) (ff-above ...)))
(ul-next ... (user-lets ...)) (ul-next ... (user-lets ...))
(uw-next ... (user-whens ...)) (uw-next ... (user-whens ...))
(ub-next ... (user-breaks ...)) (ub-next ... (user-breaks ...))
@ -359,27 +410,31 @@
(let intermediate-loop ((accvar accinit) ... (let intermediate-loop ((accvar accinit) ...
(var init) ...) (var init) ...)
(if (or checks ...) (if (or checks ...)
outer (begin
ff-cur ...
outer)
(let (refs ...) (let (refs ...)
(user-let () () (user-lets ...) (user-let () () (user-lets ...)
(if (and user-whens ...) (if (and user-whens ...)
(if (or user-breaks ...) (cond
final ((or user-breaks ...)
(emit-many/rest ff-above ... ff-cur ...
orig final)
name (else (emit-many/rest orig
(intermediate-loop accstep ... step ...) name
(next-lets ...) (intermediate-loop accstep ... step ...)
(next-accs ...) (next-lets ...)
(next-vars ...) (next-accs ...)
(next-checks ...) (next-vars ...)
(next-refs ...) (next-checks ...)
final (next-refs ...)
(ul-next ...) final
(uw-next ...) (next-ff ...)
(ub-next ...) (ul-next ...)
uf (uw-next ...)
. body)) (ub-next ...)
uf
. body)))
(intermediate-loop accvar ... step ...)))))))))) (intermediate-loop accvar ... step ...))))))))))

View file

@ -177,23 +177,21 @@
;; ;;> \macro{(for ch (in-file [input-port [reader [eof?]]]))} ;; ;;> \macro{(for ch (in-file [input-port [reader [eof?]]]))}
;; (define-syntax in-file (define-syntax in-file
;; (syntax-rules () (syntax-rules ()
;; ((in-file ((var) source) next . rest) ((in-file ((var) source) next . rest)
;; (in-file ((var p) source) next . rest)) (in-file ((var p) source) next . rest))
;; ((in-file ((var p) (file)) next . rest) ((in-file ((var p) (file)) next . rest)
;; (in-file ((var p) (file read-char)) next . rest)) (in-file ((var p) (file read-char)) next . rest))
;; ((in-file ((var p) (file reader)) next . rest) ((in-file ((var p) (file reader)) next . rest)
;; (in-file ((var p) (file reader eof-object?)) next . rest)) (in-file ((var p) (file reader eof-object?)) next . rest))
;; ((in-file ((var p) (file reader eof?)) next . rest) ((in-file ((var p) (file reader eof?)) next . rest)
;; (next ((p (open-input-file file)) (r reader) (e? eof?)) (next ((p (open-input-file file)) (r reader) (e? eof?))
;; () ()
;; ((var (r p) (r p))) ((var (r p) (r p)))
;; ((e? var)) ((e? var))
;; () ()
;; ((dummy (clo ((close-input-port p)) . rest))))
;; se-input-port p)))
;; . rest))))
(define-syntax in-generator (define-syntax in-generator
@ -267,7 +265,7 @@
((accumulating :acc (kons final init) ((var cursor) ((initial i) . x)) n . rest) ((accumulating :acc (kons final init) ((var cursor) ((initial i) . x)) n . rest)
(accumulating :acc (kons final i) ((var cursor) x) n . rest)) (accumulating :acc (kons final i) ((var cursor) x) n . rest))
((accumulating :acc (kons final init) ((var cursor) (expr (if check))) n . rest) ((accumulating :acc (kons final init) ((var cursor) (expr (if check))) n . rest)
(n ((tmp-kons kons)) (n :acc ((tmp-kons kons))
((cursor init (if check (tmp-kons expr cursor) cursor))) ((cursor init (if check (tmp-kons expr cursor) cursor)))
() ()
() ()
@ -275,7 +273,7 @@
((var (final cursor))) ((var (final cursor)))
. rest)) . rest))
((accumulating :acc (kons final init) ((var cursor) (expr)) n . rest) ((accumulating :acc (kons final init) ((var cursor) (expr)) n . rest)
(n ((tmp-kons kons)) (n :acc ((tmp-kons kons))
((cursor init (tmp-kons expr cursor))) ((cursor init (tmp-kons expr cursor)))
() ()
() ()

View file

@ -1,25 +1,25 @@
;; This is just a file with things that should be written as a test. Dump file. ;; This is just a file with things that should be written as a test. Dump file.
(loop ((a (in-list '(((1) (2)) ((3) (4)) ((5) (6 7))))) (loop ((:for a (in-list '(((1) (2)) ((3) (4)) ((5) (6 7)))))
:when #t :when #t
(b (in-list a)) (:for b (in-list a))
:subloop :subloop
(c (in-list b)) (:for c (in-list b))
(acc (listing c))) (:acc acc (listing c)))
=> acc) => acc)
(loop ((a (in-list '((1 2) (3 4) (5 6)))) (loop ((:for a (in-list '((1 2) (3 4) (5 6))))
:subloop :subloop
(b (in-list a)) (:for b (in-list a))
(acc (listing b))) (:acc acc (listing b)))
=> acc) => acc)
(loop ((a (in-list '(1 2 3))) (loop ((:for a (in-list '(1 2 3)))
(oa (summing a)) (:acc oa (summing a))
:subloop :subloop
(b (up-from a (to (+ a 2)))) (:for b (up-from a (to (+ a 2))))
(ob (listing b))) (:acc ob (listing b)))
=> (values oa ob)) => (values oa ob))
;; Should return 6 and (1 2 2 3 3 4) ;; Should return 6 and (1 2 2 3 3 4)