example/json.ss
#lang scheme/base
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PARSEQ.PLT
;; A Parser Combinator library.
;;
;; Bonzai Lab, LLC.  All rights reserved.
;;
;; Licensed under LGPL.
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; json.ss - a parser for the json format
;; yc 1/5/2010 - first version
;; yc 7/76/2010 - updated json-string to handle single quotes.
(require "../main.ss"
         )

(define hex-digit (seq d <- (choice digit #\a #\b #\c #\d #\e #\f
                                    #\A #\B #\C #\D #\E #\F)
                       (return (case d 
                                 ((#\0) 0)
                                 ((#\1) 1)
                                 ((#\2) 2) 
                                 ((#\3) 3)
                                 ((#\4) 4)
                                 ((#\5) 5)
                                 ((#\6) 6) 
                                 ((#\7) 7)
                                 ((#\8) 8)
                                 ((#\9) 9) 
                                 ((#\a #\A) 10)
                                 ((#\b #\B) 11)
                                 ((#\c #\C) 12)
                                 ((#\d #\D) 13)
                                 ((#\e #\E) 14)
                                 ((#\f #\F) 15)))))

(define (hex->char h) 
  (case h
    ((0) #\0)
    ((1) #\1)
    ((2) #\2)
    ((3) #\3) 
    ((4) #\4) 
    ((5) #\5) 
    ((6) #\6)
    ((7) #\7) 
    ((8) #\8)
    ((9) #\9) 
    ((10) #\a)
    ((11) #\b) 
    ((12) #\c)
    ((13) #\d) 
    ((14) #\e) 
    ((15) #\f)))


(define (hexes->char hexes) 
  (integer->char (hexes->integer hexes))) 

(define (char->hexes c) 
  (integer->hexes (char->integer c))) 

(define (char->hex-chars c)
  (map hex->char (char->hexes c))) 

(define (hexes->integer hexes)
  (define (helper rest acc) 
    (cond ((null? rest) acc) 
          (else
           (helper (cdr rest) (+ (* acc 16) (car rest))))))
  (helper hexes 0)) 

(define (integer->hexes i) 
  (define (helper q acc) 
    (if (= q 0) 
        acc 
        (let-values (((q r) 
                      (quotient/remainder q 16))) 
          (helper q (cons r acc)))))
  (helper i '()))

(define unicode-char
  (seq #\\ #\u 
       code <- (repeat hex-digit 4 4) 
       (return (hexes->char code)))) 

(define (json-string/inner quote)
  (zero-many (choice e-newline 
                     e-return 
                     e-tab 
                     e-backslash 
                     (escaped-char #\\ quote) 
                     (escaped-char #\\ #\/) 
                     (escaped-char #\\ #\\) 
                     (escaped-char #\\ #\b #\backspace) 
                     (escaped-char #\\ #\f #\page) 
                     unicode-char
                     (char-not-in  (list quote 
                                         #\newline 
                                         #\return 
                                         #\tab 
                                         #\\ 
                                         #\backspace 
                                         #\page))
                     )))

(define json-string
  (choice (seq #\' atoms <- (json-string/inner #\') #\'
               (return (list->string atoms)))
          (seq #\" atoms <- (json-string/inner #\") #\" 
               (return (list->string atoms)))))

(define json-array (tokens v <- (bracket/delimited #\[ json-value #\, #\])
                           (return (list->vector v))))

(define json-object (tokens v <- (bracket/delimited #\{ json-pair #\, #\}) 
                            (return (make-immutable-hash v))))

(define json-pair (tokens key <- (choice json-string 
                                         (seq c <- alpha 
                                              lst <- (zero-many alphanumeric)
                                              (return (list->string (cons c lst)))))
                          #\: 
                          value <- json-value 
                          (return (cons key value)))) 

(define json-literal (choice (tokens "true" (return #t)) 
                             (tokens "false" (return #f))
                             (tokens "null" (return '())) 
                             ))

(define json-value (choice json-literal json-array json-object real-number json-string)) 

(define read-json (make-reader json-value)) 

(provide read-json)