Implement read-syntax
authorAndy Wingo <wingo@pobox.com>
Sun, 21 Feb 2021 19:48:15 +0000 (20:48 +0100)
committerAndy Wingo <wingo@pobox.com>
Sun, 21 Feb 2021 21:09:41 +0000 (22:09 +0100)
* doc/ref/api-macros.texi (Syntax Case): Update documentation for
  datum->syntax.
* module/ice-9/psyntax.scm (datum->syntax): Use #:source keyword for
  source location info instead of an optional, and allow an alist.
* module/ice-9/psyntax-pp.scm: Regenerate.
* module/ice-9/read.scm (%read, read): Refactor to allow read and
  read-syntax to share an implementation.
  (read-syntax): New function.

doc/ref/api-macros.texi
module/ice-9/psyntax-pp.scm
module/ice-9/psyntax.scm
module/ice-9/read.scm

index 7bcca7a2bb5950e520776b1e69c3497b27a05b32..90cba24d2a54182d1c4ab37a53657cecd09ae084 100644 (file)
@@ -638,18 +638,18 @@ won't have access to the binding of @code{it}.
 
 But they can, if we explicitly introduce a binding via @code{datum->syntax}.
 
-@deffn {Scheme Procedure} datum->syntax template-id datum [srcloc]
+@deffn {Scheme Procedure} datum->syntax template-id datum [#:source=#f]
 Create a syntax object that wraps @var{datum}, within the lexical
 context corresponding to the identifier @var{template-id}.  If
 @var{template-id} is false, the datum will have no lexical context
 information.
 
 Syntax objects have an associated source location.  @xref{Source
-Properties}.  If a syntax object is passed as @var{srcloc}, the
-resulting syntax object will have the source properties of @var{srcloc}.
-Otherwise if @var{srcloc} is a source properties alist, those will be
+Properties}.  If a syntax object is passed as @var{source}, the
+resulting syntax object will have the source properties of @var{source}.
+Otherwise if @var{source} is a source properties alist, those will be
 the source properties of the resulting syntax object.  Otherwise if
-@var{srcloc} is false, the source properties are computed as
+@var{source} is false, the source properties are computed as
 @code{(source-properties @var{datum})}.
 @end deffn
 
index da14453b10fe6e78ba31a2b6c8dc202864f9e380..f0ee5eb403176fbb4ee4755ec7f6e7397845715b 100644 (file)
           (cons 'hygiene (module-name (current-module))))))
     (set! identifier? (lambda (x) (nonsymbol-id? x)))
     (set! datum->syntax
-      (lambda* (id datum #:optional (srcloc #f))
+      (lambda* (id datum #:key (source #f #:source))
         (make-syntax
           datum
           (if id (syntax-wrap id) '((top)))
           (if id
             (syntax-module id)
             (cons 'hygiene (module-name (current-module))))
-          (cond ((not srcloc) (source-properties datum))
-                ((and (list? srcloc) (and-map pair? srcloc)) srcloc)
-                (else (syntax-source srcloc))))))
+          (cond ((not source) (source-properties datum))
+                ((and (list? source) (and-map pair? source)) source)
+                (else (syntax-source source))))))
     (set! syntax->datum (lambda (x) (strip x '(()))))
     (set! generate-temporaries
       (lambda (ls)
index c5c85fde50cbf96ced63452d125730c82356d109..061beb9cd8a4aed41c8b62d4eff6c5f4282e6a3f 100644 (file)
             (nonsymbol-id? x)))
 
     (set! datum->syntax
-          (lambda* (id datum #:optional srcloc)
+          (lambda* (id datum #:key source)
             (make-syntax datum
                          (if id
                              (syntax-wrap id)
                              (syntax-module id)
                              (cons 'hygiene (module-name (current-module))))
                          (cond
-                          ((not srcloc) (source-properties datum))
-                          ((and (list? srcloc) (and-map pair? srcloc)) srcloc)
-                          (else (syntax-source srcloc))))))
+                          ((not source) (source-properties datum))
+                          ((and (list? source) (and-map pair? source)) source)
+                          (else (syntax-source source))))))
 
     (set! syntax->datum
           ;; accepts any object, since syntax objects may consist partially
index 9683744e4ca48873bfeafd25e1ebe866dc839cb2..5b375e19348c6fd50283518085fd608c991b504b 100644 (file)
@@ -43,7 +43,8 @@
   #:use-module (srfi srfi-11)
   #:use-module (ice-9 textual-ports)
   #:use-module (rnrs bytevectors)
-  #:replace (read))
+  #:replace (read)
+  #:export (read-syntax))
 
 (define read-hash-procedures
   (fluid->parameter %read-hash-procedures))
                                        read-options-inherit-all)
                                    field value)))
 
-(define* (read #:optional (port (current-input-port)))
+(define (%read port annotate strip-annotation)
   ;; init read options
   (define opts (compute-reader-options port))
   (define (enabled? field)
   (define (set-reader-option! field value)
     (set! opts (set-option opts field value))
     (set-port-read-option! port field value))
-  (define (record-positions?) (enabled? bitfield:record-positions?))
   (define (case-insensitive?) (enabled? bitfield:case-insensitive?))
   (define (keyword-style) (logand read-option-mask
                                   (ash opts (- bitfield:keyword-style))))
   (define (get-pos) (cons (port-line port) (port-column port)))
   ;; We are only ever interested in whether an object is a char or not.
   (define (eof-object? x) (not (char? x)))
-  (define (annotate line column datum)
-    ;; FIXME: Return a syntax object instead, so we can avoid the
-    ;; srcprops side table.
-    (when (and (record-positions?)
-               (supports-source-properties? datum)
-               ;; Line or column can be invalid via set-port-column! or
-               ;; ungetting chars beyond start of line.
-               (<= 0 line)
-               (<= 1 column))
-      ;; We always capture the column after one char of lookahead;
-      ;; subtract off that lookahead value.
-      (set-source-properties! datum `((filename . ,filename)
-                                      (line . ,line)
-                                      (column . ,(1- column)))))
-    datum)
 
   (define (input-error msg args)
     (scm-error 'read-error #f
            ;; Note that it is possible for scm_read_expression to
            ;; return `.', but not as part of a dotted pair: as in
            ;; #{.}#.  Indeed an example is here!
-           (if (and (eqv? ch #\.) (eq? expr '#{.}#))
+           (if (and (eqv? ch #\.) (eq? (strip-annotation expr) '#{.}#))
                (let* ((tail (read-expr (next-non-whitespace)))
                       (close (next-non-whitespace)))
                  (unless (eqv? close rdelim)
     (let ((ch (next-non-whitespace)))
       (when (eof-object? ch)
         (error "end of input while reading keyword"))
-      (let ((expr (read-expr ch)))
+      (let ((expr (strip-annotation (read-expr ch))))
         (unless (symbol? expr)
           (error "keyword prefix #: not followed by a symbol: ~a" expr))
         (symbol->keyword expr))))
            (let ((ch (next-non-whitespace)))
              (when (eof-object? ch)
                (error "unexpected end of input while reading :keyword"))
-             (symbol->keyword (read-expr ch)))
+             (symbol->keyword (strip-annotation (read-expr ch))))
            (read-mixed-case-symbol ch)))
       ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\+ #\- #\.)
        (read-number ch))
   (define (read-expr ch)
     (let ((line (port-line port))
           (column (port-column port)))
-      (annotate
-       line
-       column
-       (if (zero? neoteric)
-           (read-expr* ch)
-           (read-neoteric ch)))))
+      (annotate line
+                column
+                (if (zero? neoteric)
+                    (read-expr* ch)
+                    (read-neoteric ch)))))
 
   (define (read-directive)
     (let ((ch (next)))
     (if (eof-object? ch)
         ch
         (read-expr ch))))
+
+(define* (read #:optional (port (current-input-port)))
+  (define filename (port-filename port))
+  (define annotate
+    (if (memq 'positions (read-options))
+        (lambda (line column datum)
+          (when (and (supports-source-properties? datum)
+                     ;; Line or column can be invalid via
+                     ;; set-port-column! or ungetting chars beyond start
+                     ;; of line.
+                     (<= 0 line)
+                     (<= 1 column))
+            ;; We always capture the column after one char of lookahead;
+            ;; subtract off that lookahead value.
+            (set-source-properties! datum
+                                    `((filename . ,filename)
+                                      (line . ,line)
+                                      (column . ,(1- column)))))
+          datum)
+        identity))
+  (%read port annotate identity))
+
+(define* (read-syntax #:optional (port (current-input-port)))
+  (define filename (port-filename port))
+  (define (annotate line column datum)
+    (datum->syntax #f ; No lexical context.
+                   datum
+                   #:source `((filename . ,filename)
+                              (line . ,line)
+                              (column . ,(1- column)))))
+  (%read port annotate syntax->datum))