(in-package #:json) (defparameter number-parser (let ((signed-digits (comp ((sign (zero-or-one (unit (lambda (x) (or (char= x #\-) (char= x #\+)))))) (natural (one-or-more (unit #'digit-char-p)))) (cons sign natural)))) (comp ((base (either signed-digits (fail "Malformed number."))) (dot (zero-or-one (unit (lambda (x) (char= x #\.))))) (fraction (if dot (either (one-or-more (unit #'digit-char-p)) (fail "Malformed fractional part.")) nothing)) (e (zero-or-one (unit (lambda (x) (or (char= x #\e) (char= x #\E)))))) (exponent (if e (either signed-digits (fail "Malformed exponent part.")) nothing))) (list 'number base fraction exponent)))) (defparameter string-parser (comp ((start (unit (lambda (x) (char= x #\")))) (chars (zero-or-more (either (comp ((slash (unit (lambda (x) (char= x #\\)))) (escaped (unit)) (codepoints (if (and escaped (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 4))) (setf (char str 0) cp0) (setf (char str 1) cp1) (setf (char str 2) cp2) (setf (char str 3) cp3) str)) nothing))) (case escaped (#\n #\Newline) (#\t #\Tab) (#\u codepoints) (t escaped))) (unit (lambda (x) (char/= x #\")))))) (end (unit (lambda (x) (char= x #\"))))) (list 'string chars))) (defparameter whitespace-parser (comp ((whitespace (zero-or-more (unit (lambda (x) (or (char= x #\Space) (char= x #\Newline) (char= x #\Tab))))))) nil))