#lang scheme/base
(require parser-tools/lex
(prefix-in : parser-tools/lex-sre)
mzlib/string
scheme/contract
)
(define-lex-abbrevs
(array-begin #\{)
(array-end #\})
(array-delim (:: (:* #\space) #\, (:* #\space)))
(space #\space)
(naked-char (:& (:~ #\{ #\} #\,) any-char))
(naked-string (:* naked-char))
(newline (:: #\\ #\n))
(return (:: #\\ #\r))
(formfeed (:: #\\ #\f))
(alert (:: #\\ #\a))
(tab (:: #\\ #\t))
(backslash (:: #\\ #\\))
(quoted-char (:or newline
return
formfeed
alert
tab
backslash
any-char))
(quoted-string (:: #\" (:* quoted-char) #\")))
(define lex-array
(lexer ((eof) 'eof)
(array-begin 'begin)
(array-end 'end)
(array-delim 'delim)
(quoted-string (read-from-string lexeme))
(naked-string lexeme)
(space 'space)))
(define (read-array in)
(define (helper acc begin?)
(let ((token (lex-array in)))
(case token
((end eof) (reverse acc))
((begin) (if begin? (helper (cons (read-array in) acc) begin?)
(helper acc #t)))
((delim space) (helper acc begin?))
(else (helper (cons token acc) begin?)))))
(helper '() #f))
(define (parse-array str)
(cond ((string? str) (read-array (open-input-string str)))
((bytes? str) (read-array (open-input-bytes str)))
((null? str) str)))
(provide/contract (read-array (-> input-port? any)) (parse-array (-> (or/c string? bytes? null?) any)) )