; Author: Juergen Lorenz ; ju (at) jugilo (dot) de ; ; Copyright (c) 2013-2022, Juergen Lorenz ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are ; met: ; ; Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; ; Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; ; Neither the name of the author nor the names of its contributors may be ; used to endorse or promote products derived from this software without ; specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ; IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ; HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; (module simple-loops ( simple-loops do-for do-forever do-list do-times do-until do-while) (import scheme (chicken base)) (define-syntax do-times (syntax-rules () ((_ (k upto) xpr0 xpr1 ...) (let ((n upto)) (let loop ((k 0)) (unless (>= k n) xpr0 xpr1 ... (loop (+ k 1)))))) ;; deprecated ((_ k upto xpr . xprs) (do-times (k upto) xpr . xprs)) )) (define-syntax do-list (syntax-rules () ((_ (var lst) xpr xpr1 ...) (let loop ((sublst lst)) (if (not (null? sublst)) (let ((var (car sublst))) xpr xpr1 ... (loop (cdr sublst)))))) ;; deprecated ((_ var lst xpr . xprs) (do-list (var lst) xpr . xprs)) )) (define-syntax do-for (ir-macro-transformer (lambda (form inject compare?) ;; deprecated syntax (if (symbol? (cadr form)) (let ((args (caddr form)) (xpr (cadddr form)) (xprs (cddddr form))) (let ((var (cadr form)) (start (car args)) (stop (cadr args))) (let ((step (if (null? (cddr args)) 1 (caddr args)))) `(let ((stop ,stop)) (let loop ((,var ,start)) (unless (>= ,var stop) (begin ,xpr ,@xprs (loop (+ ,step ,var))))))))) ;; right syntax (let ((args (cadr form)) (xpr (caddr form)) (xprs (cdddr form))) (let ((var (car args)) (start (cadr args)) (stop (caddr args))) (let ((step (if (null? (cdddr args)) 1 (cadddr args)))) `(let ((stop ,stop)) (let loop ((,var ,start)) (unless (>= ,var stop) (begin ,xpr ,@xprs (loop (+ ,step ,var))))))))))))) ;(define-syntax do-for ; (syntax-rules () ; ((_ var (start stop step) xpr xpr1 ...) ; (let ((%stop stop)) ; (let loop ((var start)) ; (unless (>= var %stop) ; xpr xpr1 ... ; (loop (+ step var)))))) ; ((_ var (start stop) xpr . xprs) ; (do-for var (start stop 1) xpr . xprs)) ;; ;; deprecated ;; ((_ var (start stop step) xpr xpr1 ...) ;; (do-for (var (start stop step)) xpr . xprs)) ;; ((_ var (start stop) xpr . xprs) ;; (do-for (var (start stop 1)) xpr . xprs)) ; )) (define-syntax do-while (syntax-rules () ((_ test? xpr xpr1 ...) (let loop () (if test? (begin xpr xpr1 ... (loop))))))) (define-syntax do-until (syntax-rules () ((_ test? xpr xpr1 ...) (let loop () (if (not test?) (begin xpr xpr1 ... (loop))))))) ;;; the following macro is unhygienic on purpose, ;;; it exports the exit symbol behind the scene. ;;; So it can not be defined with syntax-rules (define-syntax do-forever (ir-macro-transformer (lambda (form inject compare?) (let ((xpr (cadr form)) (xprs (cddr form))) `(call-with-current-continuation (lambda (,(inject 'exit)) (let loop () ,xpr ,@xprs (loop)))))))) ;;; documentation (define simple-loops (let ( (alist '( (do-forever "endless loop" (do-forever xpr . xprs) "executes body xpr . xprs until exit is called") (do-times "loops a fixed number of times" (do-times (k upto) xpr . xprs) "execute xpr . xprs for k in [0 upto[") (do-list "loop along a list" (do-list (var lst) xpr . xprs) "execute xpr . xprs for var in lst") (do-for "for-loop" (do-for (var start stop step) xpr . xprs) "do xpr . xprs for var in [start stop[ with steps (default 1)") (do-while "while-loop" (do-while test? xpr . xprs) "execute xpr . xprs while test? is true") (do-until "until-loop" (do-until test? xpr . xprs) "execute xpr . xprs while test? is false") )) ) (case-lambda (() (map car alist)) ((sym) (let ((pair (assq sym alist))) (if pair (cdr pair) (print "Choose one of " (map car alist)))))))) ) ; module loops