Source

medea / grammar.scm

Full commit
(let ()

;; ws <- `[ \t\n\r]*

(define ws
  (zero-or-more (in (string->char-set " \t\n\r"))))

;; begin-array     <- #\[

(define begin-array
  (is #\[))

;; begin-object    <- #\{

(define begin-object
  (is #\{))

;; end-array       <- #\]

(define end-array
  (is #\]))

;; end-object      <- #\}

(define end-object
  (is #\}))

;; name-separator  <- #\:

(define name-separator
  (is #\:))

;; value-separator <- #\,

(define value-separator
  (is #\,))

;; false <- "false" 
;;       -> handle-false

(define false
  (bind (char-seq "false") handle-false))

;; true  <- "true"
;;       -> handle-true

(define true
  (bind (char-seq "true") handle-true))

;; null  <- "null"
;;       -> handle-null

(define null
  (bind (char-seq "null") handle-null))


;; escape  <- ["\\/bfnrt]
;;         -> handle-escape

(define escape
  (bind (in char-set:json-escape)
        handle-escape))

;; unicode <- #\u [[:xdigit:]]{4}
;;         -> handle-unicode

(define unicode
  (bind (as-string
         (preceded-by (is #\u)
                      (repeated (in char-set:hex-digit) 4)))
        handle-unicode))

;; char    <- #\\ ( escape / unicode ) / (![[:cntrl:]"\\] .)

(define char
  (any-of (preceded-by (is #\\) (any-of escape unicode fail))
          (none-of* (in char-set:json-char) item)))

;; raw-string <- #\" char* #\"
;;            -> handle-string/raw

(define raw-string
  (memoize
   (as-string
    (enclosed-by (is #\")
                 (zero-or-more char)
                 (is #\")))))

;; member <- ws raw-string ws name-separator value
;;        -> handle-member

(define member
  (recursive-parser
   (sequence* ((_ ws)
               (name raw-string)
               (_ (preceded-by ws name-separator))
               (value value))
     (handle-member name value))))


;; object <- begin-object ws ( member ( value-separator member )* )? end-object
;;        -> handle-object

(define object
  (bind (enclosed-by
         (preceded-by begin-object ws)
         (any-of
          (sequence*
              ((first-member (member))
               (more-members (zero-or-more (preceded-by value-separator (member)))))
            (result (cons first-member more-members)))
          (result '()))
         end-object)
        handle-object))

;; array  <- begin-array ws ( value ( value-separator value )* )? end-array
;;        -> handle-array


(define array
  (recursive-parser
   (bind (enclosed-by
          (preceded-by begin-array ws)
          (any-of
           (sequence*
               ((first-value value)
                (more-values (zero-or-more (preceded-by value-separator value))))
             (result (cons first-value more-values)))
           (result '()))
          end-array)
         handle-array)))

;; exp    <- [Ee] ([+-])? ([[:digit:]])+
;;        -> as-string

(define exp
  (as-string
   (sequence* ((e      (in #\E #\e))
               (sig    (maybe (in #\+ #\-)))
               (digits (one-or-more (in char-set:digit))))
     (result (cons* e sig digits)))))

;; frac   <- ,#\. ([[:digit:]])+
;;        -> as-string

(define frac
  (as-string
   (sequence* ((dec (is #\.))
               (digits (one-or-more (in char-set:digit))))
     (result (cons dec digits)))))

;; int    <- ,"0" / ( [123456789] ([[:digit:]])* )
;;        -> as-string

(define int
  (any-of (char-seq "0")
          (as-string
           (sequence*
               ((n  (in (string->char-set "123456789")))
                (ns (zero-or-more (in char-set:digit))))
             (result (cons n ns))))))

;; number <- ,"-"? int frac? exp?
;;        -> handle-number

(define number
  (bind (as-string
         (sequence (maybe (is #\-))
                   int
                   (maybe frac)
                   (maybe exp)))
        handle-number))

;; string  <- raw-string
;;         -> handle-string

(define string
  (bind raw-string handle-string))

;; value  <- ws ( null / false / true / object / array / number / string ) ws

(define value
  (enclosed-by ws (any-of null false true object (array) number string) ws))

(define (trailing-ws input)
  (if (consume-trailing-whitespace?)
      (ws input)
      (cons #f input)))

;; document <- ws ( object / array ) ws

(define document
  (enclosed-by ws (any-of object (array)) trailing-ws))

document)