wingo pushed a commit to branch master
in repository guile.

commit b6df67fe065edfd2eae296d6873754d3d42db345
Author: Andy Wingo <wi...@pobox.com>
AuthorDate: Wed Feb 17 11:55:53 2021 +0100

    Re-use string output port within read
    
    * module/ice-9/read.scm (read): Just have one string output port during
      the read.
---
 module/ice-9/read.scm | 133 ++++++++++++++++++++++++++------------------------
 1 file changed, 69 insertions(+), 64 deletions(-)

diff --git a/module/ice-9/read.scm b/module/ice-9/read.scm
index e0aecfe..98261e2 100644
--- a/module/ice-9/read.scm
+++ b/module/ice-9/read.scm
@@ -134,6 +134,14 @@
   (define (peek) (lookahead-char port))
   (define filename (port-filename port))
   (define (get-pos) (cons (port-line port) (port-column port)))
+  (define accumulator (open-output-string))
+  (define-syntax-rule (accumulate proc)
+    (begin
+      (proc (lambda (ch) (put-char accumulator ch)))
+      (let ((str (get-output-string accumulator)))
+        (seek accumulator 0 SEEK_SET)
+        (truncate-file accumulator 0)
+        str)))
 
   (define (annotate line column datum)
     ;; FIXME: Return a syntax object instead, so we can avoid the
@@ -161,18 +169,15 @@
        (else (read-semicolon-comment)))))
 
   (define-syntax-rule (take-until first pred)
-    (let ((acc (open-output-string)))
-      (put-char acc first)
-      (let lp ()
-        (let ((ch (peek)))
-          (cond
-           ((or (eof-object? ch)
-                (pred ch))
-            (get-output-string acc))
-           (else
-            (put-char acc ch)
-            (next)
-            (lp)))))))
+    (accumulate
+     (lambda (put)
+       (put first)
+       (let lp ()
+         (let ((ch (peek)))
+           (unless (or (eof-object? ch) (pred ch))
+             (put ch)
+             (next)
+             (lp)))))))
   (define-syntax-rule (take-while first pred)
     (take-until first (lambda (ch) (not (pred ch)))))
 
@@ -288,58 +293,58 @@
               (input-error "invalid character in escape sequence: ~S" ch)))))))
 
   (define (read-string rdelim)
-    (let ((acc (open-output-string)))
-      (let lp ()
-        (let ((ch (next)))
-          (cond
-           ((eof-object? ch)
-            (input-error "unexpected end of input while reading string"))
-           ((eqv? ch rdelim)
-            (get-output-string acc))
-           ((eqv? ch #\\)
-            (let ((ch (next)))
-              (when (eof-object? ch)
-                (input-error "unexpected end of input while reading string"))
-              (case ch
-                ((#\newline)
-                 (when (hungry-eol-escapes?)
-                   ;; Skip intraline whitespace before continuing.
-                   (let lp ()
-                     (let ((ch (peek)))
-                       (unless (or (eof-object? ch)
-                                   (eqv? ch #\tab)
-                                   (eq? (char-general-category ch) 'Zs))
-                         (next)
-                         (lp))))))
-                ;; Accept "\(" for use at the beginning of
-                ;; lines in multiline strings to avoid
-                ;; confusing emacs lisp modes.
-                ((#\| #\\ #\() (put-char acc ch))
-                ((#\0)         (put-char acc #\nul))
-                ((#\f)         (put-char acc #\ff))
-                ((#\n)         (put-char acc #\newline))
-                ((#\r)         (put-char acc #\return))
-                ((#\t)         (put-char acc #\tab))
-                ((#\a)         (put-char acc #\alarm))
-                ((#\v)         (put-char acc #\vtab))
-                ((#\b)         (put-char acc #\backspace))
-                ((#\x)
-                 (let ((ch (if (or (r6rs-escapes?) (eqv? rdelim #\|))
-                               (read-r6rs-hex-escape)
-                               (read-fixed-hex-escape 2))))
-                   (put-char acc ch)))
-                ((#\u)
-                 (put-char acc (read-fixed-hex-escape 4)))
-                ((#\U)
-                 (put-char acc (read-fixed-hex-escape 8)))
-                (else
-                 (unless (eqv? ch rdelim)
-                   (input-error "invalid character in escape sequence: ~S" ch))
-                 (put-char acc ch)))
-              (lp)))
-           (else
-            (put-char acc ch)
-            (lp)))))))
+    (accumulate
+     (lambda (put)
+       (let lp ()
+         (let ((ch (next)))
+           (unless (eqv? ch rdelim)
+             (cond
+              ((eof-object? ch)
+               (input-error "unexpected end of input while reading string"))
+              ((eqv? ch #\\)
+               (let ((ch (next)))
+                 (when (eof-object? ch)
+                   (input-error "unexpected end of input while reading 
string"))
+                 (case ch
+                   ((#\newline)
+                    (when (hungry-eol-escapes?)
+                      ;; Skip intraline whitespace before continuing.
+                      (let lp ()
+                        (let ((ch (peek)))
+                          (unless (or (eof-object? ch)
+                                      (eqv? ch #\tab)
+                                      (eq? (char-general-category ch) 'Zs))
+                            (next)
+                            (lp))))))
+                   ;; Accept "\(" for use at the beginning of
+                   ;; lines in multiline strings to avoid
+                   ;; confusing emacs lisp modes.
+                   ((#\| #\\ #\() (put ch))
+                   ((#\0)         (put #\nul))
+                   ((#\f)         (put #\ff))
+                   ((#\n)         (put #\newline))
+                   ((#\r)         (put #\return))
+                   ((#\t)         (put #\tab))
+                   ((#\a)         (put #\alarm))
+                   ((#\v)         (put #\vtab))
+                   ((#\b)         (put #\backspace))
+                   ((#\x)
+                    (let ((ch (if (or (r6rs-escapes?) (eqv? rdelim #\|))
+                                  (read-r6rs-hex-escape)
+                                  (read-fixed-hex-escape 2))))
+                      (put ch)))
+                   ((#\u)
+                    (put (read-fixed-hex-escape 4)))
+                   ((#\U)
+                    (put (read-fixed-hex-escape 8)))
+                   (else
+                    (unless (eqv? ch rdelim)
+                      (input-error "invalid character in escape sequence: ~S" 
ch))
+                    (put ch)))
+                 (lp)))
+              (else
+               (put ch)
+               (lp)))))))))
 
   (define (read-character)
     (let ((ch (next)))

Reply via email to