diff --git a/lib/srfi/38.scm b/lib/srfi/38.scm index d75a3006..14399cf2 100644 --- a/lib/srfi/38.scm +++ b/lib/srfi/38.scm @@ -259,147 +259,158 @@ (else (slot-set! type res i (car ls)) (lp (cdr ls) (+ i 1))))))) - (else (lp (cons (read-one) ls)))))))) - (define (read-one) - (skip-whitespace in) - (case (peek-char in) - ((#\#) + (else (lp (cons (read-one in) ls)))))))) + (define (read-hash in) + (if (eof-object? (peek-char in)) + (read-error "read error: incomplete # found at end of input")) + (case (char-downcase (peek-char in)) + ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) + (let* ((str (read-label '())) + (n (string->number str))) + (if (not n) (read-error "read error: invalid reference" str)) + (cond + ((eqv? #\= (peek-char in)) + (read-char in) + (let* ((cell (list #f)) + (thunk (lambda () (car cell)))) + (set! shared (cons (cons n thunk) shared)) + (let ((x (read-one in))) + (set-car! cell x) + x))) + ((eqv? #\# (peek-char in)) + (read-char in) + (cond + ((assv n shared) => cdr) + (else (read-error "read error: unknown reference" n)))) + (else + (read-error "read error: expected # after #n" + (read-char in)))))) + ((#\;) (read-char in) - (if (eof-object? (peek-char in)) - (read-error "read error: incomplete # found at end of input")) - (case (char-downcase (peek-char in)) - ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) - (let* ((str (read-label '())) - (n (string->number str))) - (if (not n) (read-error "read error: invalid reference" str)) - (cond - ((eqv? #\= (peek-char in)) - (read-char in) - (let* ((cell (list #f)) - (thunk (lambda () (car cell)))) - (set! shared (cons (cons n thunk) shared)) - (let ((x (read-one))) - (set-car! cell x) - x))) - ((eqv? #\# (peek-char in)) - (read-char in) - (cond - ((assv n shared) => cdr) - (else (read-error "read error: unknown reference" n)))) - (else - (read-error "read error: expected # after #n" - (read-char in)))))) - ((#\;) - (read-char in) - (read-one) ;; discard - (read-one)) - ((#\|) - (skip-comment in 0) - (read-one)) - ((#\!) - (read-char in) - (let ((c (peek-char in))) - (cond - ((or (char-whitespace? c) (eqv? c #\/)) - (skip-line in) - (read-one)) - (else - (let ((name (read-name #f in))) - (cond - ((string-ci=? name "fold-case") - (set-port-fold-case! in #t)) - ((string-ci=? name "no-fold-case") - (set-port-fold-case! in #f)) - (else ;; assume a #!/bin/bash line - (read-error "unknown #! symbol" name))) - (read-one)))))) - ((#\() (list->vector (read-one))) - ((#\') (read-char in) (list 'syntax (read-one))) - ((#\`) (read-char in) (list 'quasisyntax (read-one))) - ((#\t) (let ((s (read-name #f in))) - (or (string-ci=? s "t") (string-ci=? s "true") - (read-error "bad # syntax" s)))) - ((#\f) (let ((s (read-name #f in))) - (if (or (string-ci=? s "f") (string-ci=? s "false")) - #f - (read-error "bad # syntax" s)))) - ((#\d) (read-char in) (read in)) - ((#\x) (read-char in) (read-number 16)) - ((#\o) (read-char in) (read-number 8)) - ((#\b) (read-char in) (read-number 2)) - ((#\i) (read-char in) (exact->inexact (read-one))) - ((#\e) (string->number (read-name #\# in))) - ((#\u #\v) - (if (eqv? #\v (peek-char in)) - (read-char in)) - (read-char in) - (if (not (eqv? #\8 (peek-char in))) - (read-error "invalid syntax #u" (peek-char in))) - (read-char in) - (let ((ls (read-one))) - (if (not (list? ls)) - (read-error "invalid bytevector syntax" ls)) - (let* ((len (length ls)) - (bv (make-bytevector len))) - (do ((i 0 (+ i 1)) (ls ls (cdr ls))) - ((null? ls) bv) - (bytevector-u8-set! bv i (car ls)))))) - ((#\\) - (read-char in) - (let* ((c1 (read-char in)) - (c2 (peek-char in))) - (if (or (eof-object? c2) (memv c2 delimiters)) - c1 - (read-named-char c1 in)))) - (else - (read-error "unknown # syntax: " (peek-char in))))) - ((#\() + (read-one in) ;; discard + (read-one in)) + ((#\|) + (skip-comment in 0) + (read-one in)) + ((#\!) (read-char in) - (let lp ((res '())) - (skip-whitespace in) - (let ((c (peek-char in))) - (case c - ((#\)) - (read-char in) - (reverse res)) - ((#\.) - (read-char in) - (cond - ((memv (peek-char in) delimiters) - (let ((tail (read-one))) - (cond - ((and (skip-whitespace-and-sexp-comments - in (lambda (in) (read-one))) - (eqv? #\) (peek-char in))) - (read-char in) - (append (reverse res) tail)) - ((eof-object? (peek-char in)) - (read-incomplete-error "unterminated dotted list")) - (else - (read-error "expected end of list after dot"))))) - ((char-numeric? (peek-char in)) - (lp (cons (read-float-tail in) res))) - (else - (lp (cons (string->symbol (read-name #\. in)) res))))) - (else - (if (eof-object? c) - (read-incomplete-error "unterminated list") - (lp (cons (read-one) res)))))))) - ((#\{) + (let ((c (peek-char in))) + (cond + ((or (char-whitespace? c) (eqv? c #\/)) + (skip-line in) + (read-one in)) + (else + (let ((name (read-name #f in))) + (cond + ((string-ci=? name "fold-case") + (set-port-fold-case! in #t)) + ((string-ci=? name "no-fold-case") + (set-port-fold-case! in #f)) + (else ;; assume a #!/bin/bash line + (read-error "unknown #! symbol" name))) + (read-one in)))))) + ((#\() (list->vector (read-one in))) + ((#\') (read-char in) (list 'syntax (read-one in))) + ((#\`) (read-char in) (list 'quasisyntax (read-one in))) + ((#\t) (let ((s (read-name #f in))) + (or (string-ci=? s "t") (string-ci=? s "true") + (read-error "bad # syntax" s)))) + ((#\f) (let ((s (read-name #f in))) + (if (or (string-ci=? s "f") (string-ci=? s "false")) + #f + (read-error "bad # syntax" s)))) + ((#\d) (read-char in) (read in)) + ((#\x) (read-char in) (read-number 16)) + ((#\o) (read-char in) (read-number 8)) + ((#\b) (read-char in) (read-number 2)) + ((#\i) (read-char in) (exact->inexact (read-one in))) + ((#\e) (string->number (read-name #\# in))) + ((#\u #\v) + (if (eqv? #\v (peek-char in)) + (read-char in)) (read-char in) - (read-object)) - ((#\') (read-char in) (list 'quote (read-one))) - ((#\`) (read-char in) (list 'quasiquote (read-one))) - ((#\,) + (if (not (eqv? #\8 (peek-char in))) + (read-error "invalid syntax #u" (peek-char in))) (read-char in) - (let ((sym (if (eqv? #\@ (peek-char in)) - (begin (read-char in) 'unquote-splicing) - 'unquote))) - (list sym (read-one)))) + (let ((ls (read-one in))) + (if (not (list? ls)) + (read-error "invalid bytevector syntax" ls)) + (let* ((len (length ls)) + (bv (make-bytevector len))) + (do ((i 0 (+ i 1)) (ls ls (cdr ls))) + ((null? ls) bv) + (bytevector-u8-set! bv i (car ls)))))) + ((#\\) + (read-char in) + (let* ((c1 (read-char in)) + (c2 (peek-char in))) + (if (or (eof-object? c2) (memv c2 delimiters)) + c1 + (read-named-char c1 in)))) (else - (read in)))) + (read-error "unknown # syntax: " (peek-char in))))) + (define (read-one in) + (cond + ((not (skip-whitespace-and-sexp-comments in read-one)) + (read-hash in)) + (else + (case (peek-char in) + ((#\#) + (read-char in) + (read-hash in)) + ((#\() + (read-char in) + (let lp ((res '())) + (cond + ((not (skip-whitespace-and-sexp-comments in read-one)) + (lp (cons (read-hash in) res))) + (else + (let ((c (peek-char in))) + (case c + ((#\)) + (read-char in) + (reverse res)) + ((#\.) + (read-char in) + (cond + ((memv (peek-char in) delimiters) + (let ((tail (read-one in))) + (cond + ((null? res) + (read-error "dot before any elements in list")) + ((and (skip-whitespace-and-sexp-comments + in read-one) + (eqv? #\) (peek-char in))) + (read-char in) + (append (reverse res) tail)) + ((eof-object? (peek-char in)) + (read-incomplete-error + "unterminated dotted list")) + (else + (read-error "expected end of list after dot"))))) + ((char-numeric? (peek-char in)) + (lp (cons (read-float-tail in) res))) + (else + (lp (cons (string->symbol (read-name #\. in)) res))))) + (else + (if (eof-object? c) + (read-incomplete-error "unterminated list") + (lp (cons (read-one in) res)))))))))) + ((#\{) + (read-char in) + (read-object)) + ((#\') (read-char in) (list 'quote (read-one in))) + ((#\`) (read-char in) (list 'quasiquote (read-one in))) + ((#\,) + (read-char in) + (let ((sym (if (eqv? #\@ (peek-char in)) + (begin (read-char in) 'unquote-splicing) + 'unquote))) + (list sym (read-one in)))) + (else + (read in)))))) ;; body - (let ((res (read-one))) + (let ((res (read-one in))) (if (pair? shared) (patch res)) res))))) diff --git a/tests/r7rs-tests.scm b/tests/r7rs-tests.scm index 75689243..86ed281a 100644 --- a/tests/r7rs-tests.scm +++ b/tests/r7rs-tests.scm @@ -2040,7 +2040,7 @@ (test '(a . b) (read (open-input-string "(a . b #;c)"))) (define (test-read-error str) - (test-assert + (test-assert str (guard (exn (else #t)) (read (open-input-string str)) #f)))