RFC 8259 Scope¶
This page defines the JSON accepted and rejected by cl-json-kit.
Conformance results¶
The vendored JSONTestSuite corpus runs in CI:
| Corpus class | Requirement | Cases | Result |
|---|---|---|---|
y_ |
every conforming parser must accept | 95 | 95 accepted |
n_ |
every conforming parser must reject | 176 + 12 | all rejected |
i_ |
implementation-defined | 22 + 13 | each choice pinned by a test |
No case crashes, hangs, or signals anything other than json-parse-error; the
two pathological cases the corpus ships as 100 KB and 250 KB files of repeated
punctuation are rejected by a depth bound rather than by exhausting the control
stack.
The counts split because 25 cases (the + 12 and + 13 above) carry input that
is not well-formed UTF-8 — lone continuation bytes, overlong sequences, UTF-16
with and without a BOM, ISO-8859-1. This library's API consumes Common Lisp
characters rather than octets (see Characters, not
octets below), so those inputs are rejected by the
external-format layer before the reader sees them, and the vendored tests
exclude them by name.
The implementation-defined cases are where parsers legitimately disagree —
deeply nested arrays, numbers outside double-float range, lone surrogates in
\uXXXX escapes. Each is listed in the test file together with this library's
choice.
What the reader accepts¶
The reader accepts one complete RFC 8259 JSON text:
- objects, arrays, strings, numbers,
true,false, andnull; - only JSON-defined whitespace;
- string escapes, including UTF-16 surrogate-pair combination for characters outside the Basic Multilingual Plane.
What the reader rejects¶
- unescaped control characters in strings;
- malformed escapes;
- lone (unpaired) surrogates;
- invalid number forms;
- a leading UTF-8 byte-order mark (
U+FEFF) — it is not JSON-defined whitespace, so it is rejected like any other unexpected character; strip it yourself first (see the FAQ and Recipes); - trailing data after the value (for
parse;parse-prefixandread-jsonintentionally stop at the value boundary).
Numbers¶
The built-in decoder maps ordinary non-integer numbers to double-float. When
float conversion overflows or underflows, it falls back to an exact integer or
ratio instead of rejecting an otherwise valid JSON number; for example, 1e400
remains an exact integer. max-exact-exponent bounds the absolute decimal
scale used by that fallback, preventing an untrusted exponent from requesting an
enormous expt computation.
Supply a number-decoder when the application
needs its own decimal type or a uniform number representation, and a
number-encoder to control formatting on output.
Characters, not octets¶
The API operates on Common Lisp characters, not octets. Encoding validity
and UTF-8 decoding errors therefore belong to the stream / external-format
layer — configure your stream before calling read-json or write-json.
The writer emits non-ASCII Lisp characters directly and escapes the required JSON characters; it does not promise ASCII-only output.
Non-goals¶
The following are explicitly out of scope:
- RFC 8785 canonicalization (canonical number formatting, byte-for-byte cross-implementation output);
- multiple-value stream framing beyond what
parse-prefix/read-jsonprovide; - comments;
- trailing commas;
- JSON5 and other extensions;
- arbitrary-precision decimal preservation without a custom
number-decoder/number-encoder; - an octet / UTF-8 API.
:sort-keys t therefore yields deterministic member ordering, not RFC 8785
canonical JSON. See Writing JSON.