JSON


Quick Start

(module demo
  (import std.json std.io)
  (begin
    ;; Parse from a string
    (let ((cfg (json:read-string
                "{\"name\":\"eta\",\"n\":7,\"flags\":[true,false]}"
                'keep-integers-exact? #t)))
      (println (hash-map-ref cfg "name"))           ;; "eta"
      (println (hash-map-ref cfg "n"))              ;; 7
      (println (vector-ref (hash-map-ref cfg "flags") 0))) ;; #t

    ;; Serialise back
    (println (json:write-string
              (hash-map "ok" #t "xs" #(1 2 3))))
    ;; => {"ok":true,"xs":[1,2,3]}

    ;; Stream from a port
    (let ((p (open-input-string "{\"msg\":\"ok\"}")))
      (println (hash-map-ref (json:read p) "msg")))))

std.json is a thin Eta layer over the native JSON codec implemented in eta/core/src/eta/util/json.h — a hand-written, RFC 8259 compliant parser and serialiser with no third-party dependency. It is auto-imported by std.prelude; direct import works when you want a smaller surface:

(import std.json)

API

FunctionSignatureNotes
json:read(port [opts ...]) -> valueReads a single JSON document from any input port.
json:read-string(string [opts ...]) -> valueConvenience for in-memory text.
json:write(value [port]) -> '()Writes JSON to port (defaults to (current-output-port)).
json:write-string(value) -> stringReturns the serialised form as a string.

Options

Reader options are alternating keyword/value pairs at the end of the argument list. Both symbol ('keep-integers-exact?) and keyword (:keep-integers-exact?) spellings are accepted.

OptionTypeDefaultEffect
keep-integers-exact?bool#fWhen #t, integer-typed JSON numbers decode to fixnums; floats stay flonum. The default decodes all numbers to flonums for predictable arithmetic.

Type Mapping

JSONEta
objecthash map (string keys)
arrayvector
stringstring
number (int)flonum (or fixnum with keep-integers-exact?)
number (float)flonum
true / false#t / #f
null'() (empty list)

The same mapping is used in reverse by json:write / json:write-string, with these additional conventions:


Patterns

Loading config from disk

(import std.json std.io)
(defun load-config (path)
  (let ((p (open-input-file path)))
    (let ((cfg (json:read p 'keep-integers-exact? #t)))
      (close-port p)
      cfg)))

Round-tripping a hash map

(let* ((src  (hash-map "name" "eta" "count" 2))
       (text (json:write-string src))
       (dst  (json:read-string text 'keep-integers-exact? #t)))
  (assert-equal "eta" (hash-map-ref dst "name"))
  (assert-equal 2     (hash-map-ref dst "count")))

Pretty-printed output

json:write writes the compact RFC 8259 form. Wrap the value in your own formatter, or pass through a re-decode + manual rendering loop, if human-readable indentation is required.


Notes