Racketifying goof-loop
I have racketified goof loops. No :for or :acc needed, and :when, :unless, and :break are no longer parethesised. :acc blah (in ...) and :for blah (in ...) has been changed to (blah (folding ...)) and (blah (in ...))
This commit is contained in:
		
							parent
							
								
									716c26c7ce
								
							
						
					
					
						commit
						2c182da570
					
				
					 3 changed files with 101 additions and 113 deletions
				
			
		
							
								
								
									
										87
									
								
								goof.scm
									
										
									
									
									
								
							
							
						
						
									
										87
									
								
								goof.scm
									
										
									
									
									
								
							|  | @ -31,30 +31,22 @@ | ||||||
| ;; foof-loop) by Alex Shinn. The name goof-loop is a play on that | ;; foof-loop) by Alex Shinn. The name goof-loop is a play on that | ||||||
| ;; name, and the fact that I goofed in the chibi issue tracker when | ;; name, and the fact that I goofed in the chibi issue tracker when | ||||||
| ;; trying to understand the iterator protocol. | ;; trying to understand the iterator protocol. | ||||||
| ;; | 
 | ||||||
| ;; It extends chibi loop in the following way: |  | ||||||
| ;;   * adds support for binding variables in the loop clauses. |  | ||||||
| ;;   * Adds :when, :unless, and :break clauses that controls when the loop |  | ||||||
| ;;     body executes and when values are collected by accumulating for clauses. |  | ||||||
| ;;     similar to how #:when, #:unless and #:break works in racket. |  | ||||||
| ;; |  | ||||||
| ;;   It restricts chibi loops in the following ways: |  | ||||||
| ;;    * with- and for-clauses  are no longer visible in the final expression, for that you |  | ||||||
| ;;      must use an accumulator clause. |  | ||||||
| ;;    * Positional update is not supported. It seems error-prone once you start |  | ||||||
| ;;      having a lot of loop variables, and because goof-loop does some re-ordering |  | ||||||
| ;;      that foof loop does not. For example: |  | ||||||
| ;;        (:for a (in 0 (+ a 1))) (:acc acc (in '() (cons a acc))) |  | ||||||
| ;;      are actually reordered in a loop, because accumulators and for loops are separated |  | ||||||
| ;;      due to having to propagate the accumulators through the loop. |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| (use-modules (helpers) | (use-modules (helpers) | ||||||
|              (srfi srfi-71)) |              (srfi srfi-71)) | ||||||
| 
 | 
 | ||||||
|  | (define-aux-syntaxes | ||||||
|  |   ;; Auxiliary syntax for the loop clauses | ||||||
|  |   :when :unless :break :final :let :let* :subloop | ||||||
|  |   ;; Auxiliary syntax for the iterators. | ||||||
|  |   :gen) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| (include "iterators.scm") | (include "iterators.scm") | ||||||
| 
 | 
 | ||||||
| (define-aux-syntaxes :for :when :unless :break :final :let :let* :acc :subloop) | 
 | ||||||
| 
 | 
 | ||||||
| (define-syntax loop | (define-syntax loop | ||||||
|   (syntax-rules () |   (syntax-rules () | ||||||
|  | @ -89,62 +81,44 @@ | ||||||
| 
 | 
 | ||||||
| ;; 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 (=> in :for :with :when :unless :break :final :let :acc) |   (syntax-rules (=> in :when :unless :break :final :let :let* :subloop) | ||||||
|     ((_ orig name l a v c r f ul uw ub () => expr . body) |     ((_ orig name l a v c r f ul uw ub () => expr . body) | ||||||
|      (emit orig name l a v c r f ul uw ub expr . body)) |      (emit orig name l a v c r f ul uw ub expr . body)) | ||||||
|     ((_ orig name l a v c r f ul uw ub () . body) |     ((_ orig name l a v c r f ul uw ub () . body) | ||||||
|      (emit orig name l a v c r f ul uw ub (if #f #f) . body)) |      (emit orig name l a v c r f ul uw ub (if #f #f) . body)) | ||||||
|     ;; :for-clauses |  | ||||||
|     ;; 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 ((:for for-rest ...) clauses ...) . body) |  | ||||||
|      (push-new-subloop orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub ((:for for-rest ...) clauses ...) . body)) |  | ||||||
| 
 |  | ||||||
|     ;; The four special :for var (in ...)-clauses where user specifies their own iteration |  | ||||||
|     ((_ orig name l a v c r f ul ((uw uw* ...) uw-rest ...) ub ((:with args ...) clauses ...) . body) |  | ||||||
|      (push-new-subloop name l a v c r f ul ((uw uw* ...) uw-rest ...) ub ((:with args ...) clauses ...) . body)) |  | ||||||
|      |  | ||||||
|     ((_ orig name l a ((v-cur ...) . v-rest)  ((c-cur ...) . c-rest) |  | ||||||
|         r f ul uw ub ((:for var (in init step guard-expr)) clauses ...) . body) |  | ||||||
|      (cl orig name l a ((v-cur ... (var init step)) . v-rest) ((c-cur ... guard-expr) . c-rest) |  | ||||||
|          r f ul uw ub (clauses ...) . body)) |  | ||||||
|     ((_ orig name l a ((v-cur ...) . v-rest) c r f ul uw ub ((:for var (in init step)) clauses ...) . body) |  | ||||||
|      (cl orig name l a ((v-cur ... (var init step)) . v-rest) c r f ul uw ub (clauses ...) . body)) |  | ||||||
|     ((_ orig name l a ((v-cur ...) . v-rest) c r f ul uw ub ((:for var (in init)) clauses ...) . body) |  | ||||||
|      (cl orig name l a ((v-cur ... (var init var)) . v-rest) c r f ul uw ub (clauses ...) . body)) |  | ||||||
|     ;; For clause with a sequence creator. |  | ||||||
|     ((_ orig name l a v c r f ul uw ub ((:for id ids ... (iterator source ...)) clauses ...) . body) |  | ||||||
|      (iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub (clauses ...) . body)) |  | ||||||
| 
 |  | ||||||
|     ;; Accumulating clauses |  | ||||||
|     ;; should I push a subloop on a when clause? |  | ||||||
|     ;; Currently these have no stop or if-clauses. Maybe add? |  | ||||||
|     ((_ orig name l a v c r f ul uw ub ((:acc var (in init update)) clauses ...) . body) |  | ||||||
|      (cl-next () ((var init update)) () () () ((var var)) orig name l a v c r f ul uw ub (clauses ...) . body)) |  | ||||||
|     ((_ orig name l a v c r f ul uw ub ((:acc var (in init)) clauses ...) . body) |  | ||||||
|      (cl-next () ((var init var)) () () () ((var var)) orig name l a v c r f ul uw ub (clauses ...) . body)) |  | ||||||
|     ;; Accumulator clause with a proper accumulator. |  | ||||||
|     ((_ orig name l a v c r f ul uw ub ((:acc id ids ... (iterator source ...)) clauses ...) . body) |  | ||||||
|      (iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub (clauses ...) . body)) |  | ||||||
| 
 | 
 | ||||||
|     ;; user-whens |     ;; user-whens | ||||||
|     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub ((:when test) clauses ...) . body) |     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (:when test clauses ...) . body) | ||||||
|      (cl orig name l a v c r f ul ((cur-uw ... test) . uw-rest) ub (clauses ...) . body)) |      (cl orig name l a v c r f ul ((cur-uw ... test) . uw-rest) ub (clauses ...) . body)) | ||||||
|     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub ((:unless test) clauses ...) . body) |     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (:unless test clauses ...) . body) | ||||||
|      (cl orig name l a v c r f ul ((cur-uw ... (not test)) . uw-rest) ub (clauses ...) . body)) |      (cl orig name l a v c r f ul ((cur-uw ... (not test)) . uw-rest) ub (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) ((:break expr) clauses ...) . body) |     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ((cur-ub ...) . ub-rest) (:break expr clauses ...) . body) | ||||||
|      (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ((cur-ub ... expr) . ub-rest) (clauses ...) . body)) |      (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ((cur-ub ... expr) . ub-rest) (clauses ...) . body)) | ||||||
|     ;; USER LETS |     ;; USER LETS | ||||||
|     ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub ((:let id id* ... expr) clauses ...) . body) |     ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub (: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 (clauses ...) . body)) |      (cl orig name l a v c r f ((cur-ul ... (:let id id* ... expr)) . ul-rest) uw ub (clauses ...) . body)) | ||||||
|     ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub ((:let* id id* ... expr) clauses ...) . body) |     ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub (:let* (id id* ... expr) clauses ...) . body) | ||||||
|      (cl orig name l a v c r f ((cur-ul ... (:let* id id* ... expr)) . ul-rest) (clauses ...) . body)) |      (cl orig name l a v c r f ((cur-ul ... (:let* id id* ... expr)) . ul-rest) (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 (:subloop clauses ...) . body) |     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (:subloop clauses ...) . body) | ||||||
|      (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub (clauses ...) . body)) |      (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub (clauses ...) . body)) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |      | ||||||
|  |     ;; :for-clauses | ||||||
|  |     ;; 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 ((for-rest ...) clauses ...) . body) | ||||||
|  |      (push-new-subloop orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub ((for-rest ...) clauses ...) . body)) | ||||||
|  | 
 | ||||||
|  |     ;; For clause with a sequence creator. | ||||||
|  |     ((_ orig name l a v c r f ul uw ub ((id ids ... (iterator source ...)) clauses ...) . body) | ||||||
|  |      (iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub (clauses ...) . body)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |      | ||||||
|     ;; ERROR HANDLING? |     ;; ERROR HANDLING? | ||||||
|     ((_ orig name l a v c r f ul uw ub (clause . rest) . body) |     ((_ orig name l a v c r f ul uw ub (clause . rest) . body) | ||||||
|      (syntax-error "Invalid clause in loop" clause orig)) |      (syntax-error "Invalid clause in loop" clause orig)) | ||||||
|  | @ -208,9 +182,8 @@ | ||||||
|           ((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 clauses . body)))) |           ul uw ub clauses . body)) | ||||||
|          |     )) | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| (define-syntax user-let | (define-syntax user-let | ||||||
|   (syntax-rules (:let :let*) |   (syntax-rules (:let :let*) | ||||||
|  |  | ||||||
|  | @ -37,6 +37,15 @@ | ||||||
| ;; hashqing | ;; hashqing | ||||||
| ;; hashving | ;; hashving | ||||||
| 
 | 
 | ||||||
|  | (define-syntax in | ||||||
|  |   (syntax-rules ()  | ||||||
|  |   ((_ ((var) (init)) n . rest) | ||||||
|  |    (n () () ((var init var)) () () () . rest)) | ||||||
|  |   ((_ ((var) (init step)) n . rest) | ||||||
|  |    (n () () ((var init step)) () () () . rest)) | ||||||
|  |   ((_ ((var) (init step stop)) n . rest) | ||||||
|  |    (n () () ((var init step)) (stop) () () . rest)))) | ||||||
|  | 
 | ||||||
| (define-syntax in-list | (define-syntax in-list | ||||||
|   (syntax-rules () |   (syntax-rules () | ||||||
|     ((_ ((var) source) next . rest) |     ((_ ((var) source) next . rest) | ||||||
|  | @ -150,24 +159,26 @@ | ||||||
|            () |            () | ||||||
|            . rest)))) |            . rest)))) | ||||||
| 
 | 
 | ||||||
| ;;> \macro{(for ch (in-file [input-port [reader [eof?]]]))} | ;; ;;> \macro{(for ch (in-file [input-port [reader [eof?]]]))} | ||||||
|  | 
 | ||||||
|  | ;; (define-syntax in-file | ||||||
|  | ;;   (syntax-rules () | ||||||
|  | ;;     ((in-file ((var) source) next . rest) | ||||||
|  | ;;      (in-file ((var p) source) next . rest)) | ||||||
|  | ;;     ((in-file ((var p) (file)) 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 eof-object?)) next . rest)) | ||||||
|  | ;;     ((in-file ((var p) (file reader eof?)) next . rest) | ||||||
|  | ;;      (next ((p (open-input-file file)) (r reader) (e? eof?)) | ||||||
|  | ;;            () | ||||||
|  | ;;            ((var (r p) (r p))) | ||||||
|  | ;;            ((e? var)) | ||||||
|  | ;;            () | ||||||
|  | ;;            ((dummy (clo | ||||||
|  |            ;;          se-input-port p))) | ||||||
|  |            ;; . rest)))) | ||||||
| 
 | 
 | ||||||
| (define-syntax in-file |  | ||||||
|   (syntax-rules () |  | ||||||
|     ((in-file ((var) source) next . rest) |  | ||||||
|      (in-file ((var p) source) next . rest)) |  | ||||||
|     ((in-file ((var p) (file)) 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 eof-object?)) next . rest)) |  | ||||||
|     ((in-file ((var p) (file reader eof?)) next . rest) |  | ||||||
|      (next ((p (open-input-file file)) (r reader) (e? eof?)) |  | ||||||
|            () |  | ||||||
|            ((var (r p) (r p))) |  | ||||||
|            ((e? var)) |  | ||||||
|            () |  | ||||||
|            ((dummy (close-input-port p))) |  | ||||||
|            . rest)))) |  | ||||||
| 
 | 
 | ||||||
| (define-syntax in-generator | (define-syntax in-generator | ||||||
|   (syntax-rules () |   (syntax-rules () | ||||||
|  | @ -187,29 +198,15 @@ | ||||||
|     ((up-from (() . args) next . rest) |     ((up-from (() . args) next . rest) | ||||||
|      (up-from ((var) . args) next . rest)) |      (up-from ((var) . args) next . rest)) | ||||||
|     ((up-from ((var) (start (to limit) (by step))) next . rest) |     ((up-from ((var) (start (to limit) (by step))) next . rest) | ||||||
|      (next ((s start) (l limit) (e step)) |      (next ((s start) (l limit) (e step)) () | ||||||
|            () |            ((var s (+ var e))) ((>= var l)) () () . rest)) | ||||||
|            ((var s (+ var e))) |  | ||||||
|            ((>= var l)) |  | ||||||
|            () |  | ||||||
|            () |  | ||||||
|            . rest)) |  | ||||||
|     ((up-from ((var) (start (to limit))) next . rest) |     ((up-from ((var) (start (to limit))) next . rest) | ||||||
|      (next ((s start) (l limit)) |      (next ((s start) (l limit))() | ||||||
|            () |  | ||||||
|            ((var s (+ var 1))) |            ((var s (+ var 1))) | ||||||
|            ((>= var l)) |            ((>= var l)) () () . rest)) | ||||||
|            () |  | ||||||
|            () |  | ||||||
|            . rest)) |  | ||||||
|     ((up-from ((var) (start (by step))) next . rest) |     ((up-from ((var) (start (by step))) next . rest) | ||||||
|      (next ((s start) (e step)) |      (next ((s start) (e step))() | ||||||
|            () |            ((var s (+ var e))) () () () . rest)) | ||||||
|            ((var s (+ var e))) |  | ||||||
|            () |  | ||||||
|            () |  | ||||||
|            () |  | ||||||
|            . rest)) |  | ||||||
|     ((up-from ((var) (start)) next . rest) |     ((up-from ((var) (start)) next . rest) | ||||||
|      (next ((s start)) |      (next ((s start)) | ||||||
|            () |            () | ||||||
|  | @ -218,7 +215,11 @@ | ||||||
|            () |            () | ||||||
|            () |            () | ||||||
|            . rest)) |            . rest)) | ||||||
|     )) |     ;; Extra convenience, make it act like (in-range ...) from racket, but only for positive numbers. | ||||||
|  |     ((up-from ((var) (start limit step)) next . rest) | ||||||
|  |      (next ((s start) (l limit) (e step)) () ((var s (+ var e))) ((>= var l)) () () . rest)) | ||||||
|  |     ((up-from ((var) (start limit)) next . rest) | ||||||
|  |      (up-from ((var) (start limit 1)) next . rest)))) | ||||||
| 
 | 
 | ||||||
| ;;> \macro{(for x (down-from [start] [(to limit)] [(by step)]))} | ;;> \macro{(for x (down-from [start] [(to limit)] [(by step)]))} | ||||||
| 
 | 
 | ||||||
|  | @ -283,6 +284,20 @@ | ||||||
|         ((var (final cursor))) |         ((var (final cursor))) | ||||||
|         . rest)))) |         . rest)))) | ||||||
| 
 | 
 | ||||||
|  | (define-syntax folding | ||||||
|  |   (syntax-rules (if) | ||||||
|  |     ((_ ((var) (init update (if guard))) n . rest) | ||||||
|  |      (n () | ||||||
|  |         ((var init (if guard update var))) | ||||||
|  |         () () () | ||||||
|  |         ((var var)) | ||||||
|  |         . rest)) | ||||||
|  |     ((_ ((var) (init update)) n . rest) | ||||||
|  |      (folding ((var) (init update (if #t))) n . rest)) | ||||||
|  |     ((_ ((var) (init)) n . rest) | ||||||
|  |      (folding ((var) (init var (if #t))) n . rest)))) | ||||||
|  |      | ||||||
|  | 
 | ||||||
| ;;> \macro{(for x [pair] (listing expr))} | ;;> \macro{(for x [pair] (listing expr))} | ||||||
| 
 | 
 | ||||||
| (define-syntax listing | (define-syntax listing | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								tests.scm
									
										
									
									
									
								
							
							
						
						
									
										42
									
								
								tests.scm
									
										
									
									
									
								
							|  | @ -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 ((:for a (in-list '(((1) (2)) ((3) (4)) ((5) (6 7))))) | (loop ((a (in-list '(((1) (2)) ((3) (4)) ((5) (6 7))))) | ||||||
|        (:when #t) |        :when #t | ||||||
|        (:for b (in-list a)) |        (b (in-list a)) | ||||||
|        (:when #t)   |  | ||||||
|        (:for c (in-list b)) |  | ||||||
|        (:for acc (listing c))) |  | ||||||
|   => acc) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| (loop ((:for a (in-list '((1 2) (3 4) (5 6)))) |  | ||||||
|        (:when #t) |  | ||||||
|        (:for b (in-list a)) |  | ||||||
|        (:for acc (listing b))) |  | ||||||
|   => acc) |  | ||||||
| 
 |  | ||||||
| (loop ((:for a (in-list '(1 2 3))) |  | ||||||
|        (:acc oa (summing a)) |  | ||||||
|        :subloop   |        :subloop   | ||||||
|        (:for b (up-from a (to (+ a 2)))) |        (c (in-list b)) | ||||||
|        (:acc ob (listing b))) |        (acc (listing c))) | ||||||
|   => (values oa ob)) |   => acc) | ||||||
| ;; Should return 6 and (1 2 2 3 3 4 | 
 | ||||||
|  | 
 | ||||||
|  | (loop ((a (in-list '((1 2) (3 4) (5 6)))) | ||||||
|  |        :subloop | ||||||
|  |        (b (in-list a)) | ||||||
|  |        (acc (listing b))) | ||||||
|  |   => acc) | ||||||
|  | 
 | ||||||
|  | (loop ((a (in-list '(1 2 3))) | ||||||
|  |        (oa (summing a)) | ||||||
|  |        :subloop | ||||||
|  |        (b (up-from a (to (+ a 2)))) | ||||||
|  |        (ob (listing b))) | ||||||
|  |   => (values oa ob)) | ||||||
|  | ;; Should return 6 and (1 2 2 3 3 4) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus
						Linus