unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Kevin Ryde <user42@zip.com.au>
Subject: Re: while break and continue
Date: Thu, 14 Aug 2003 07:49:30 +1000	[thread overview]
Message-ID: <87znid1b4l.fsf@zip.com.au> (raw)
In-Reply-To: 8765lmkwpb.fsf@zip.com.au

[-- Attachment #1: Type: text/plain, Size: 1594 bytes --]

I applied this

        * boot-9.scm (while): Rewrite, continue as a proper escape, break
        doesn't take a return value, break and continue procs new for each
        while form allowing use in nested whiles, don't depend on bindings in
        expansion environment.

        * tests/syntax.test (while): New tests.

        * scheme-control.texi (while do): Update `while' for code rewrite, in
        particular describe break and continue.


 - syntax: while cond body ...
     Run a loop executing the BODY forms while COND is true.  COND is
     tested at the start of each iteration, so if it's `#f' the first
     time then BODY is not executed at all.  The return value is
     unspecified.

     Within `while', two extra bindings are provided, they can be used
     from both COND and BODY.

      - Scheme Procedure: break
          Break out of the `while' form.

      - Scheme Procedure: continue
          Abandon the current iteration, go back to the start and test
          COND again, etc.

     Each `while' form gets its own `break' and `continue' procedures,
     operating on that `while'.  This means when loops are nested the
     outer `break' can be used to escape all the way out.  For example,

          (while (test1)
            (let ((outer-break break))
              (while (test2)
                (if (something)
                  (outer-break #f))
                ...)))

     Note that each `break' and `continue' procedure can only be used
     within the dynamic extent of its `while'.  Outside the `while'
     their behaviour is unspecified.




[-- Attachment #2: boot-9.scm.while.diff --]
[-- Type: text/plain, Size: 1252 bytes --]

--- boot-9.scm.~1.316.~	2003-05-30 08:40:07.000000000 +1000
+++ boot-9.scm	2003-08-14 07:38:41.000000000 +1000
@@ -2491,18 +2491,6 @@
         (loop (1- count) (cons count result)))))
 
 \f
-;;; {While}
-;;;
-;;; with `continue' and `break'.
-;;;
-
-(defmacro while (cond . body)
-  `(letrec ((continue (lambda () (or (not ,cond) (begin (begin ,@ body) (continue)))))
-	    (break (lambda val (apply throw 'break val))))
-     (catch 'break
-	    (lambda () (continue))
-	    (lambda v (cadr v)))))
-
 ;;; {collect}
 ;;;
 ;;; Similar to `begin' but returns a list of the results of all constituent
@@ -2560,6 +2548,26 @@
       (else
        (error "define-syntax-macro can only be used at the top level")))))
 
+;;; {While}
+;;;
+;;; with `continue' and `break'.
+;;;
+
+;; The inner `do' loop avoids re-establishing a catch every iteration,
+;; that's only necessary if continue is actually used.
+;;
+(define-macro (while cond . body)
+  (let ((key (make-symbol "while-key")))
+    `(,do ((break    ,(lambda () (throw key #t)))
+	   (continue ,(lambda () (throw key #f))))
+	 ((,catch (,quote ,key)
+		  (,lambda ()
+		    (,do ()
+			((,not ,cond))
+		      ,@body)
+		    #t)
+		  ,(lambda (key arg) arg))))))
+
 \f
 ;;; {Module System Macros}
 ;;;

[-- Attachment #3: syntax.test.while.diff --]
[-- Type: text/plain, Size: 3788 bytes --]

--- syntax.test.~1.10.~	2003-04-28 07:51:30.000000000 +1000
+++ syntax.test	2003-08-12 22:30:55.000000000 +1000
@@ -550,3 +550,171 @@
       exception:missing/extra-expr
       (eval '(quote a b)
 	    (interaction-environment)))))
+
+(with-test-prefix "while"
+  
+  (define (unreachable)
+    (error "unreachable code has been reached!"))
+  
+  ;; an environment with no bindings at all
+  (define empty-environment
+    (make-module 1))
+  
+  ;; Return a new procedure COND which when called (COND) will return #t the
+  ;; first N times, then #f, then any further call is an error.  N=0 is
+  ;; allowed, in which case #f is returned by the first call.
+  (define (make-iterations-cond n)
+    (lambda ()
+      (cond ((not n)
+	     (error "oops, condition re-tested after giving false"))
+	    ((= 0 n)
+	     (set! n #f)
+	     #f)
+	    (else
+	     (set! n (1- n))
+	     #t))))
+  
+
+  (pass-if-exception "too few args" exception:wrong-num-args
+    (while))
+  
+  (with-test-prefix "empty body"
+    (do ((n 0 (1+ n)))
+	((> n 5))
+      (pass-if n
+	(let ((cond (make-iterations-cond n)))
+	  (while (cond)))
+	#t)))
+  
+  (pass-if "initially false"
+    (while #f
+      (unreachable))
+    #t)
+  
+  (with-test-prefix "in empty environment"
+    
+    (pass-if "empty body"
+      (eval `(,while #f)
+	    empty-environment)
+      #t)
+    
+    (pass-if "initially false"
+      (eval `(,while #f
+	       #f)
+	    empty-environment)
+      #t)
+    
+    (pass-if "iterating"
+      (let ((cond (make-iterations-cond 3)))
+	(eval `(,while (,cond)
+		 123 456)
+	      empty-environment))
+      #t))
+  
+  (with-test-prefix "iterations"
+    (do ((n 0 (1+ n)))
+	((> n 5))
+      (pass-if n
+	(let ((cond (make-iterations-cond n))
+	      (i    0))
+	  (while (cond)
+	    (set! i (1+ i)))
+	  (= i n)))))
+  
+  (with-test-prefix "break"
+    
+    (pass-if-exception "too many args" exception:wrong-num-args
+      (while #t
+	(break 1)))
+    
+    (with-test-prefix "from cond"
+      (pass-if "first"
+	(while (begin
+		 (break)
+		 (unreachable))
+	  (unreachable))
+	#t)
+      
+      (do ((n 0 (1+ n)))
+	  ((> n 5))
+	(pass-if n
+	  (let ((cond (make-iterations-cond n))
+		(i    0))
+	    (while (if (cond)
+		       #t
+		       (begin
+			 (break)
+			 (unreachable)))
+	      (set! i (1+ i)))
+	    (= i n)))))
+    
+    (with-test-prefix "from body"
+      (pass-if "first"
+	(while #t
+	  (break)
+	  (unreachable))
+	#t)
+      
+      (do ((n 0 (1+ n)))
+	  ((> n 5))
+	(pass-if n
+	  (let ((cond (make-iterations-cond n))
+		(i    0))
+	    (while #t
+	      (if (not (cond))
+		  (begin
+		    (break)
+		    (unreachable)))
+	      (set! i (1+ i)))
+	    (= i n)))))
+    
+    (pass-if "from nested"
+      (while #t
+	(let ((outer-break break))
+	  (while #t
+	    (outer-break)
+	    (unreachable)))
+	(unreachable))
+      #t))
+  
+  (with-test-prefix "continue"
+    
+    (pass-if-exception "too many args" exception:wrong-num-args
+      (while #t
+	(continue 1)))
+    
+    (with-test-prefix "from cond"
+      (do ((n 0 (1+ n)))
+	  ((> n 5))
+	(pass-if n
+	  (let ((cond (make-iterations-cond n))
+		(i    0))
+	    (while (if (cond)
+		       (begin
+			 (set! i (1+ i))
+			 (continue)
+			 (unreachable))
+		       #f)
+	      (unreachable))
+	    (= i n)))))
+    
+    (with-test-prefix "from body"
+      (do ((n 0 (1+ n)))
+	  ((> n 5))
+	(pass-if n
+	  (let ((cond (make-iterations-cond n))
+		(i    0))
+	    (while (cond)
+	      (set! i (1+ i))
+	      (continue)
+	      (unreachable))
+	    (= i n)))))
+    
+    (pass-if "from nested"
+      (let ((cond (make-iterations-cond 3)))
+	(while (cond)
+	  (let ((outer-continue continue))
+	    (while #t
+	      (outer-continue)
+	      (unreachable)))))
+      #t)))

[-- Attachment #4: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel

  reply	other threads:[~2003-08-13 21:49 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-05-30  0:00 while break and continue Kevin Ryde
2003-06-01 23:58 ` Marius Vollmer
2003-06-05  1:42   ` Kevin Ryde
2003-06-18 22:56     ` Marius Vollmer
2003-06-21 23:28       ` Kevin Ryde
2003-07-27 14:48         ` Marius Vollmer
2003-07-29  0:23           ` Kevin Ryde
2003-08-13 21:49             ` Kevin Ryde [this message]
2003-08-13  9:27               ` Matthias Koeppe
2003-08-14 23:35                 ` Kevin Ryde
2003-08-15  1:43                 ` Kevin Ryde
2003-06-06 22:31   ` Kevin Ryde
2003-06-18 22:57     ` Marius Vollmer
2003-06-20 23:56       ` Kevin Ryde

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87znid1b4l.fsf@zip.com.au \
    --to=user42@zip.com.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).