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)))))