123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- ; Part of Scheme 48 1.9. See file COPYING for notices and license.
- ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Robert Ransom
- ; This builds the macro call to make the folder and constructs the arguments
- ; for the resulting fold procedure. The first three clauses add a loop variable
- ; and final expression if they are missing.
- ;
- ; I caved in and passed the body to the FOLDER macro instead of passing it in
- ; as a lambda to the procedure produced by the macro.
- (define-syntax reduce
- (syntax-rules ()
- ; Single state, no loop variable
- ((reduce (fold-vars ...) (state-var) body maybe-final ...)
- (iterate loop (fold-vars ...) (state-var) (loop body) maybe-final ...))
- ; No state, no loop variable
- ((reduce (fold-vars ...) () body maybe-final ...)
- (iterate loop (fold-vars ...) ()
- (begin body (loop))
- maybe-final ...))
- ; Multiple state, no loop variable
- ((reduce (fold-vars ...) (state-vars ...) body maybe-final ...)
- (iterate loop (fold-vars ...) (state-vars ...)
- (call-with-values (lambda () body) loop)
- maybe-final ...))))
- (define-syntax iterate
- (syntax-rules ()
- ; No final expression
- ((iterate loop (fold-vars ...) ((state-var init) ...) body)
- (iterate loop (fold-vars ...) ((state-var init) ...) body
- (values state-var ...)))
- ; Weird degenerate case with no iteration variables.
- ((iterate loop () ((state-var init) ...) body final)
- (let loop ((state-var init) ...) body))
- ; All there
- ((iterate loop
- ((type value-var args ...) ...)
- ((state-var init) ...)
- body
- final)
- ((folder ((type value-var args ...) ...) (state-var ...) loop body)
- (lambda (state-var ...)
- final)
- args ... ...
- init ...))))
- ; The entrance to all the rest of this. The first step is to make the lists
- ; of types, value variables (which will be bound to the elements of the
- ; sequences), and fold variables (which will be bound to the successive
- ; state values of the sequence producer).
- (define-syntax folder
- (syntax-rules ()
- ((folder ((type value-var args ...) ...) (state-var ...) loop body)
- (var-loop ((type value-var args ...) ...)
- #f () () () ()
- (state-var ...) loop body))))
- ; If we have reached the end of the sequences we go on to FOLDER-LOOP to build
- ; the body of the loop. Otherwise we make new variables to match the arguments
- ; to the next sequence and continue.
- (define-syntax var-loop
- (syntax-rules ()
- ((var-loop () seen-synched? (type ...)
- (value-var ...) ((fold-var init) ...) end-tests
- (state-var ...)
- body-loop
- body)
- (folder-loop (type ...)
- (let ((body-loop (lambda (state-var ...)
- (loop fold-var ... state-var ...))))
- body)
- ()
- ((fold-var init) ...)
- end-tests
- (state-var ...)
- loop
- final))
- ((var-loop ((type value-var args ...) more ...) stuff ...)
- (copy-vars (args ...) () (var-loop2 type value-var (more ...) stuff ...)))))
- ; This is the continuation to the COPY-VARS use above. We add the variables
- ; to the end of the variables list and then get the SYNC value.
- (define-syntax var-loop2
- (syntax-rules ()
- ((var-loop2 vars type value-var stuff ...)
- (type sync (var-loop3 (type value-var vars stuff ...))))))
- ; This is the continuation to the SYNC `call' in VAR-LOOP2. We get the state
- ; variable names.
- (define-syntax var-loop3
- (syntax-rules ()
- ((var-loop3 sync? (type value-var vars stuff ...))
- (type state-vars vars (var-loop4 (type sync? value-var vars stuff ...))))))
- ; This is the end of the VAR-LOOP body. We dispatch on whether TYPE, which
- ; has just been queried for its info, is synchronized and whether it is the
- ; first or a subsequent synchronized type. In all cases we add the various
- ; code fragments obtained from TYPE to the appropriate lists and then go back
- ; to the top of the loop.
- (define-syntax var-loop4
- (syntax-rules ()
- ; TYPE is the first synchronized type we have seen.
- ((var-loop4 ((fold-var init) ...)
- (type
- #t
- value-var
- vars
- more-types
- #f
- (types ...) (value-vars ...) (fold-init ...) end-tests
- stuff ...))
- (var-loop more-types
- #t
- ((type #t #f (fold-var ...) value-var vars)
- types ...)
- (value-vars ... value-var)
- (fold-init ... (fold-var init) ...)
- end-tests
- stuff ...))
- ; TYPE is a synchronized type but not the first we have seen.
- ((var-loop4 ((fold-var init) ...)
- (type
- #t
- value-var
- vars
- more-types
- #t
- (types ...) (value-vars ...) (fold-init ...)
- end-tests
- stuff ...))
- (var-loop more-types
- #t
- ((type #t #t (fold-var ...) value-var vars)
- types ...)
- (value-vars ... value-var)
- (fold-init ... (fold-var init) ...)
- ((type done vars (fold-var ...)) . end-tests)
- stuff ...))
- ; TYPE is not synchronized.
- ((var-loop4 ((fold-var init) ...)
- (type
- #f
- value-var
- vars
- more-types
- seen-synched?
- (types ...) (value-vars ...) (fold-init ...) end-tests
- stuff ...))
- (var-loop more-types
- seen-synched?
- ((type #f seen-synched? (fold-var ...) value-var vars)
- types ...)
- (value-vars ... value-var)
- (fold-init ... (fold-var init) ...)
- end-tests
- stuff ...))))
- ; A loop to produce a list of fresh variables. The new variables are tacked
- ; onto the end of the body.
- (define-syntax copy-vars
- (syntax-rules ()
- ((copy-vars () vars (cont stuff ...))
- (cont vars stuff ...))
- ((copy-vars (x y ...) (vars ...) cont)
- (copy-vars (y ...) (vars ... a) cont))))
- ; Here we build up the body of the loop. When all the sequences are done we
- ; are done.
- ;
- ; For each sequence we do (type step stuff ...) to build the body and
- ; (type init vars ...) to get the initial value of the fold variable for
- ; that sequence. Here `step' and `init' are keywords.
- ;
- ; The actual arguments to (type step stuff ...) are:
- ; vars ... ; variables bound to the sequence's arguments
- ; fold-var ; variable bound to the last state and to be bound to the
- ; ; next state
- ; value-var ; variable to be bound to the next element
- ; loop-body-exp ; this expression continues the loop
- ; final-exp ; this expression ends the loop
- (define-syntax folder-loop
- (syntax-rules ()
- ((folder-loop () ; no more sequences
- loop-body ; body so far
- (args ...) ; complete list of sequence arguments
- ((fold-var init) ...) ; fold variables and their initial values
- end-tests ; end test for first synchronized seq.
- (state-var ...) ; the user's state variables
- loop ; loop variable
- final) ; final argument variable
- (lambda (final args ... state-var ...)
- (let loop ((fold-var init) ... (state-var state-var) ...)
- loop-body)))
- ; Not synchronized
- ((folder-loop ((type #f synched? fold-vars value-var (vars ...)) more ...)
- loop-body
- args
- fold-var-inits end-tests state-vars
- loop final)
- (folder-loop (more ...)
- (type step (vars ...) fold-vars value-var
- loop-body (final . state-vars))
- (vars ... . args)
- fold-var-inits end-tests state-vars
- loop final))
- ; Synchronized, not first such
- ((folder-loop ((type #t #t fold-vars value-var (vars ...)) more ...)
- loop-body
- args
- fold-var-inits end-tests state-vars
- loop final)
- (folder-loop (more ...)
- (type step (vars ...) fold-vars value-var
- loop-body
- (begin (assertion-violation 'folder
- "synchronized sequence ended early")
- (values)))
- (vars ... . args)
- fold-var-inits end-tests state-vars
- loop final))
- ; First synchronized sequence
- ((folder-loop ((type #t #f fold-vars value-var (vars ...)) more ...)
- loop-body
- args
- fold-var-inits end-tests state-vars
- loop final)
- (folder-loop (more ...)
- (type step (vars ...) fold-vars value-var
- loop-body (if (and . end-tests)
- (final . state-vars)
- (begin (assertion-violation 'folder
- "synchronized sequence ended early")
- (values))))
- (vars ... . args)
- fold-var-inits end-stests state-vars
- loop final))))
-
- ; Iterators
- ; (list* var list)
- ; (list-spine* var list)
- ; (list-spine-cycle-safe* var list on-cycle-thunk)
- ; (vector* var vector)
- ; (string* var string)
- ; (count* var start [end [step]])
- ; (bits* var integer [step-size])
- ; (input* var input-port reader) ; (reader port) -> value or eof-object
- ; (stream* var function initial-state) ; (function state) -> [value new-state]
- ; A new-state of #F means that the previous value was the final one.
- (define-syntax list*
- (syntax-rules (sync state-vars step)
- ((list* sync (next more))
- (next #f more))
- ((list* state-vars (start-list) (next more))
- (next ((list-var start-list)) more))
- ((list* step (start-list) (list-var) value-var loop-body final-exp)
- (if (null? list-var)
- final-exp
- (let ((value-var (car list-var))
- (list-var (cdr list-var)))
- loop-body)))))
- (define-syntax list%
- (syntax-rules (sync done)
- ((list% sync (next more))
- (next #t more))
- ((list% done (start-list) (list-var))
- (null? list-var))
- ((list% stuff ...)
- (list* stuff ...))))
- (define-syntax list-spine*
- (syntax-rules (sync state-vars step)
- ((list-spine* sync (next more))
- (next #f more))
- ((list-spine* state-vars (start-list) (next more))
- (next ((list-var start-list)) more))
- ((list-spine* step (start-list) (list-var)
- value-var loop-body final-exp)
- (if (null? list-var)
- final-exp
- (let ((value-var list-var)
- (list-var (cdr list-var)))
- loop-body)))))
- (define-syntax list-spine%
- (syntax-rules (sync done)
- ((list-spine% sync (next more))
- (next #t more))
- ((list-spine% done (start-list) (list-var))
- (null? list-var))
- ((list-spine% stuff ...)
- (list-spine* stuff ...))))
- (define-syntax list-spine-cycle-safe*
- (syntax-rules (sync state-vars step)
- ((list-spine-cycle-safe* sync (next more))
- (next #f more))
- ((list-spine-cycle-safe* state-vars
- (start-list on-cycle-thunk)
- (next more))
- (next ((list-var start-list)
- (lag-var start-list)
- (move-lag? #f))
- more))
- ((list-spine-cycle-safe* step
- (start-list on-cycle-thunk)
- (list-var lag-var move-lag?)
- spine-var loop-body final-exp)
- (if (null? list-var)
- final-exp
- (let ((spine-var list-var)
- (list-var (cdr list-var))
- (lag-var (if move-lag?
- (cdr lag-var)
- lag-var))
- (move-lag? (not move-lag?)))
- (if (eq? list-var lag-var)
- (on-cycle-thunk)
- loop-body))))))
- (define-syntax list-spine-cycle-safe%
- (syntax-rules (sync done)
- ((list-spine-cycle-safe% sync (next more))
- (next #t more))
- ((list-spine-cycle-safe% done
- (start-list on-cycle-thunk)
- (list-var lag-var move-lag?))
- (null? list-var))
- ((list-spine-cycle-safe% stuff ...)
- (list-spine-cycle-safe* stuff ...))))
- (define-syntax vector*
- (syntax-rules (sync state-vars step)
- ((vector* sync (next more))
- (next #f more))
- ((vector* state-vars (vector) (next more))
- (next ((i 0)) more))
- ((vector* step (vector) (i) value-var loop-body final-exp)
- (if (= i (vector-length vector))
- final-exp
- (let ((value-var (vector-ref vector i))
- (i (+ i 1)))
- loop-body)))))
- (define-syntax vector%
- (syntax-rules (sync done)
- ((vector% sync (next more))
- (next #t more))
- ((vector% done (vector) (i))
- (= i (vector-length vector)))
- ((vector% stuff ...)
- (vector* stuff ...))))
- (define-syntax string*
- (syntax-rules (sync state-vars step)
- ((string* sync (next more))
- (next #f more))
- ((string* state-vars (string) (next more))
- (next ((i 0)) more))
- ((string* step (string) (i) value-var loop-body final-exp)
- (if (= i (string-length string))
- final-exp
- (let ((value-var (string-ref string i))
- (i (+ i 1)))
- loop-body)))))
- (define-syntax string%
- (syntax-rules (sync done)
- ((string% sync (next more))
- (next #t more))
- ((string% done (string) (i))
- (= i (string-length string)))
- ((string% stuff ...)
- (string* stuff ...))))
- (define-syntax count*
- (syntax-rules (sync state-vars step)
- ((count* sync (next more))
- (next #f more))
- ((count* state-vars (start args ...) (next more))
- (next ((i start)) more))
- ((count* step (start) (i) value-var loop-body final-exp)
- (let ((value-var i)
- (i (+ i 1)))
- loop-body))
- ((count* step (start end) (i) value-var loop-body final-exp)
- (count* step (start end 1) (i) value-var loop-body final-exp))
- ; This doesn't work because we don't see the original arguments, just variables
- ; bound to them.
- ; ((count* step (start #f increment) (i) value-var loop-body final-exp)
- ; (let ((value-var i)
- ; (i (+ i increment)))
- ; loop-body))
- ((count* step (start end increment) (i) value-var loop-body final-exp)
- (if (= i end)
- final-exp
- (let ((value-var i)
- (i (+ i increment)))
- loop-body)))))
- ; Synchronized, so we don't allow the unbounded version.
- (define-syntax count%
- (syntax-rules (sync done state-vars step)
- ((count% sync (next more))
- (next #t more))
- ((count% done (start end increment ...) (i))
- (= end i))
- ((count% state-vars (start args ...) (next more))
- (next ((i start)) more))
- ((count% step (start end) (i) value-var loop-body final-exp)
- (count% step (start end 1) (i) value-var loop-body final-exp))
- ((count% step (start end increment) (i) value-var loop-body final-exp)
- (if (= i end)
- final-exp
- (let ((value-var i)
- (i (+ i increment)))
- loop-body)))))
- ; I would really like to be able to lift the mask calculation out of the loop.
- ; There could be yet another clause in iterators that returned (VAR VAL) clauses
- ; to be added to a LET around the loop.
- (define-syntax bits*
- (syntax-rules (sync state-vars step)
- ((bits* sync (next more))
- (next #f more))
- ((bits* state-vars (bit-set args ...) (next more))
- (next ((i bit-set)) more))
- ((bits* step (bit-set) (i) value-var loop-body final-exp)
- (if (= i 0)
- final-exp
- (let ((value-var (odd? i))
- (i (arithmetic-shift i -1)))
- loop-body)))
- ((bits* step (bit-set size) (i) value-var loop-body final-exp)
- (if (= i 0)
- final-exp
- (let ((value-var (bitwise-and i (- (arithmetic-shift 1 size) 1)))
- (i (arithmetic-shift i (- size))))
- loop-body)))))
- ; This one is unlikely to be used much, because the termination test is
- ; so data dependent.
- (define-syntax bits%
- (syntax-rules (sync done state-vars step)
- ((bits% sync (next more))
- (next #t more))
- ((bits% done values (i))
- (= i 0))
- ((bits% more ...)
- (bits* more ...))))
- (define-syntax input*
- (syntax-rules (sync state-vars step)
- ((input* sync (next more))
- (next #f more))
- ((input* state-vars (port reader) (next more))
- (next () more))
- ((input* step (port reader) () value-var loop-body final-exp)
- (let ((value-var (reader port)))
- (if (eof-object? value-var)
- final-exp
- loop-body)))))
- (define-syntax input%
- (syntax-rules (sync done)
- ((input% sync (next more))
- (next #t more))
- ((input% done (port reader) ())
- (eof-object? (peek-char port)))
- ((input% more ...)
- (input* more ...))))
- (define-syntax stream*
- (syntax-rules (sync state-vars step)
- ((stream* sync (next more))
- (next #f more))
- ((stream* state-vars (function start-state) (next more))
- (next ((state start-state)) more))
- ((stream* step (function start-state) (state) value-var loop-body final-exp)
- (call-with-values
- (lambda ()
- (function state))
- (lambda (value-var state)
- (if state
- loop-body
- final-exp))))))
- (define-syntax stream%
- (syntax-rules (sync done)
- ((stream% sync (next more))
- (next #t more))
- ((stream% done (function start-state) (state))
- (call-with-values
- (lambda ()
- (function state))
- (lambda (value-var state)
- (not state))))
- ((stream% more ...)
- (stream* more ...))))
|