(in-package #:json) (defparameter number-literal (let ((signed-digits (comp ((sign (optional (one-of (unit #\-) (unit #\+)))) (natural (if sign (crit (many (unit digit-char-p))) (many (unit digit-char-p))))) (cons sign natural)))) (comp ((base signed-digits) (dot (optional (unit #\.))) (fraction (if dot (crit (many (unit digit-char-p))) nothing)) (e (optional (one-of (unit #\e) (unit #\E)))) (exponent (if e (crit signed-digits) nothing))) (read-from-string (str:from-list (remove nil (append base (cons dot fraction) (cons (when e #\d) exponent)))))))) (defparameter string-literal (comp ((_ (unit #\")) (chars (optional (many (one-of (comp ((slash (unit #\\)) (escaped (unit)) (codepoints (if (char= escaped #\u) (comp ((cp0 (unit digit-char-p)) (cp1 (unit digit-char-p)) (cp2 (unit digit-char-p)) (cp3 (unit digit-char-p))) (let ((str (make-string 7))) (setf (char str 0) #\#) (setf (char str 1) #\\) (setf (char str 2) #\u) (setf (char str 3) cp0) (setf (char str 4) cp1) (setf (char str 5) cp2) (setf (char str 6) cp3) str)) nothing))) (case escaped (#\n #\Newline) (#\t #\Tab) (#\u (read-from-string codepoints)) (t escaped))) (unit (and (char/= it #\") (char/= it #\\))))))) (_ (crit (unit #\")))) (str:from-list chars))) (defparameter true-symbol (comp ((_ (unit #\t)) (_ (crit (literal "rue")))) 'true)) (defparameter false-symbol (comp ((_ (unit #\f)) (_ (crit (literal "alse")))) 'false)) (defparameter null-symbol (comp ((_ (unit #\n)) (_ (crit (literal "ull")))) 'null)) (defvar json-value) (defparameter json-array (comp ((_ (unit #\[)) (vn (optional (separated-list json-value (unit #\,)))) (_ (unit #\]))) (apply #'vector vn))) (defparameter json-object (let ((json-pair (comp ((_ whitespace) (k string-literal) (_ whitespace) (_ (crit (unit #\:))) (v (crit json-value))) (cons k v)))) (comp ((_ (unit #\{)) (vn (optional (separated-list json-pair (unit #\,)))) (_ (unit #\}))) (let* ((obj (make-hash-table :test #'equal :size (length vn)))) (dolist (v vn) (setf (gethash (car v) obj) (cdr v))) obj)))) (defparameter json-value (comp ((_ whitespace) (v (one-of number-literal string-literal json-object json-array true-symbol false-symbol null-symbol)) (_ whitespace)) v)) (defun from-string (str) (run json-value (input:from-string str))) (defun from-file (file) (run json-value (input:from-file file)))