Backup of Felix's reader added by mario-goulart on Fri Sep 2 14:31:29 2016
;;;; read.scm ; ; misc error syntax (define %case-sensitive (let ((f #t)) ; not R5RS compliant but simply the right thing to do (lambda arg (if (pair? arg) (set! f (car arg)) f)))) (define %read (let ((read-char read-char) (reverse reverse) (peek-char peek-char) (list->vector list->vector) (list->string list->string) (case-sensitive %case-sensitive) (string->number string->number)) (lambda port (let ((port (optional port %input-port)) (cs (case-sensitive)) (eol (lambda (c) (error "unexpected delimiter" c)))) (define (parse-token t) (or (string->number t) (string->symbol t))) (define (read1) (let ((c (read-char port))) (if (eof-object? c) c (case c ((#\#) (read-sharp)) ((#\() (read-list #\))) ((#\[) (read-list #\])) ((#\{) (read-list #\})) ((#\,) (cond ((eqv? (peek-char port) #\@) (read-char port) (list 'unquote-splicing (read1))) (else (list 'unquote (read1))))) ((#\`) (list 'quasiquote (read1))) ((#\') `',(read1)) ((#\;) (skip-line) (read1)) ((#\") (read-string)) ((#\|) (read-xsymbol)) ((#\) #\] #\}) (eol c)) (else (if (char-whitespace? c) (read1) (parse-token (read-token (list (docase c)) cs)))))))) (define (skip-line) (let ((c (read-char port))) (unless (or (eof-object? c) (char=? #\newline c)) (skip-line)))) (define (skip-whitespace) ; returns peeked char (let ((c (peek-char port))) (cond ((eof-object? c) c) ((char-whitespace? c) (read-char port) (skip-whitespace)) (else c)))) (define (read-sharp) (let ((c (read-char port))) (if (eof-object? c) (error "unexpected EOF after `#'") (case c ((#\f #\F) #f) ((#\t #\T) #t) ((#\x #\X) (string->number (read-token '() #f) 16)) ((#\o #\O) (string->number (read-token '() #f) 8)) ((#\b #\B) (string->number (read-token '() #f) 2)) ((#\i #\I) (let* ((tok (read-token '() #f)) (n (string->number tok))) (cond ((not (number? n)) (error "invalid number syntax" tok)) ((inexact? n) n) (else (exact->inexact n))))) ((#\e #\E) (let* ((tok (read-token '() #f)) (n (string->number tok))) (cond ((not (number? n)) (error "invalid number syntax" tok)) ((exact? n) n) (else (inexact->exact n))))) ((#\() (list->vector (read-list #\)))) ((#\;) (read1) (read1)) ((#\%) (string->symbol (read-token (list (docase c) #\#) cs))) ((#\!) (skip-line) (read1)) ((#\\) (let ((t (read-token '() #t))) (cond ((string-ci=? "newline" t) #\newline) ((string-ci=? "tab" t) #\tab) ((string-ci=? "space" t) #\space) ((string-ci=? "return" t) #\return) ((zero? (string-length t)) (read-char port)) (else (string-ref t 0))))) ((#\') `(syntax ,(read1))) ; for v-t-ex (else (error "invalid `#' syntax" c)))))) (define (read-list delim) (%call-with-exit-continuation (lambda (return) (let ((lst '()) (old eol)) (set! eol (lambda (c) (set! eol old) (if (eqv? c delim) (return (reverse lst)) (error "missing closing delimiter" delim)))) (let loop () (let ((c (skip-whitespace))) (cond ((eof-object? c) (error "unexpected EOF while reading list")) ((char=? c delim) (read-char port) (set! eol old) (return (reverse lst))) (else (if (eqv? #\. c) (let ((t (read-token '() cs))) (if (string=? "." t) (let ((rest (read1))) (skip-whitespace) (set! eol old) (if (eqv? (read-char port) delim) (return (append (reverse lst) rest)) (error "missing closing delimiter" delim))) (set! lst (cons (parse-token t) lst)))) (set! lst (cons (read1) lst))) (loop))))))))) (define (read-string) (let loop ((lst '())) (let ((c (read-char port))) (cond ((eof-object? c) (error "unexpected EOF while reading string")) ((char=? #\" c) (list->string (reverse lst))) ((char=? #\\ c) (let ((c (read-char port))) (if (eof-object? c) (error "unexpected EOF while reading string") (case c ((#\n) (loop (cons #\newline lst))) ((#\r) (loop (cons #\return lst))) ((#\t) (loop (cons #\tab lst))) (else (loop (cons c lst))))))) (else (loop (cons c lst))))))) (define (read-xsymbol) (let loop ((lst '())) (let ((c (read-char port))) (cond ((eof-object? c) (error "unexpected EOF while reading extended symbol")) ((char=? #\| c) (string->symbol (list->string (reverse lst)))) ((char=? #\\ c) (let ((c (read-char port))) (if (eof-object? c) (error "unexpected EOF while reading extended symbol") (loop (cons c lst))))) (else (loop (cons c lst))))))) (define (docase c) (if cs c (char-downcase c))) (define (read-token prefix cs) (let loop ((lst prefix)) ; prefix must be in reverse order (let ((c (peek-char port))) (if (or (eof-object? c) (memv c '(#\{ #\} #\( #\) #\[ #\] #\; #\")) (char-whitespace? c)) (list->string (reverse lst)) (loop (cons ((if cs id docase) (read-char port)) lst)))))) (read1)))))