(define-library (zambyte meta json) ;; portable (export json define-json-record-type json-ref json-value? json-key-not-found) ;; non-portable (export json-object json-list json-null json-object? json-list? json-null? json-object-contains-key? string->json json->string json-object-ref json-list-ref json-list-length json-object->alist json-list->list) (import (scheme base)) ;; portable (begin (define-syntax json (syntax-rules (object list null true false) ((_ (object (key . value) ...)) (json-object `(key . ,(json value)) ...)) ((_ (list vs ...)) (json-list (json vs) ...)) ((_ null) json-null) ((_ true) #t) ((_ false) #f) ((_ value) (if (json-value? value) value (error "json: not a json value" value))))) ;; TODO: implement this (define (json-object-set! . args) #f) (define-syntax handle-field-declarations (syntax-rules () ((_ (field accessor)) (define (accessor obj) (json-object-ref obj 'field))) ((_ (field accessor mutator)) (begin (define (accessor obj) (json-object-ref obj 'field)) (define (mutator obj value) (json-object-set! obj 'field value)))))) (define-syntax define-json-record-type (syntax-rules () ((_ type (constructor fields ...) from-json-string predicate field-declarations ...) (begin (define (constructor fields ...) (make-json-record 'type (json-object `(fields . ,fields) ...) from-json-string)) (define (predicate obj) (and (json-record? obj) (eq? (json-record->name obj) 'type))) (define (from-json-string str) (let ((json (string->json str))) (parameterize ((json-key-not-found (lambda () (error "key not found in json string when converting to a record" 'from-json-string)))) (constructor (json-ref json 'fields) ...)))) (handle-field-declarations field-declarations) ...)))) (define-record-type (make-json-record name fields from-json-string) json-record? (name json-record->name) (fields json-record->fields) (from-json-string json-record->from-json-string)) (define (json-ref json key . keys) (let ((ref (cond ((json-object? json) json-object-ref) ((json-list? json) json-list-ref) (else (error "json-ref: cannot get reference on json value" json))))) (if (null? keys) (ref json key) (apply json-ref (ref json key) keys)))) (define (json-value? obj) (or (boolean? obj) (number? obj) (string? obj) (json-null? obj) (json-list? obj) (json-object? obj))) (define json-key-not-found (make-parameter (lambda () (values))))) ;; non-portable (cond-expand ((and (library (macduffie json)) (srfi 69)) (include-library-declarations "macduffie.scm")) ((and guile (library (json))) (include-library-declarations "guile.scm")) (gauche (include-library-declarations "gauche.scm")) (gerbil (include-library-declarations "gerbil.scm")) (sagittarius (include-library-declarations "sagittarius.scm")) ((library (chibi json)) (include-library-declarations "chibi.scm")) ((library (srfi 180)) (include-library-declarations "180.scm")) (else (error "No implementation of JSON library available."))))