std/text/json
std/json — JSON validation + string-builder helpers.
Two surfaces:
1. Validation — jsonValidate(text) is a recursive-descent
yes/no check, allocating no output tree — pure Axle over byte
indexing, no FFI.
2. Stringification helpers — escape / quote / primitive
converters so user code can emit JSON by concatenation without
reinventing the escape rules.
The escaping, validation and integer / bool / null converters are
pure Axle. jsonF64ToString stays native (exact IEEE-754 float
formatting, with NaN / ∞ mapped to null). Every structural ASCII
byte is named once, at module scope, in the const block below.
Free functions
| Type | Method and description |
|---|---|
| __jsonIsWs(byte : i32) : bool true for JSON's whitespace set (space, tab, LF, CR). |
| __jsonIsDigit(byte : i32) : bool true for an ASCII decimal digit. |
| __jsonSkipWs(src : string, pos : i64, len : i64) : i64 Position of the first non-whitespace byte at or after pos. |
| __jsonEat(src : string, pos : i64, len : i64, expected : i32) : i64 Consume one expected byte; returns pos + 1 or -1 if it doesn't match. |
| __jsonEatKeyword(src : string, pos : i64, len : i64, keyword : string) : i64 Consume the literal keyword byte-for-byte (no allocation); -1 on mismatch. |
| __jsonParseValue(src : string, pos : i64, len : i64) : i64 Any JSON value: object, array, string, keyword literal or number. |
| __jsonParseObject(src : string, pos : i64, len : i64) : i64 { (string ':' value (',' string ':' value)*)? }. |
| __jsonParseArray(src : string, pos : i64, len : i64) : i64 [ value (',' value)* ]?. |
| __jsonParseString(src : string, pos : i64, len : i64) : i64 A quoted string, its escapes checked but not decoded (validation only). \" \\ \/ \b \f \n \r \t are the short escapes;\uXXXX needs exactly 4 hex digits; any other byte after \ isinvalid, and raw control bytes ( < 0x20) are rejected unescaped. |
| __jsonParseNumber(src : string, pos : i64, len : i64) : i64 A JSON number: optional -, integer part, optional fraction, optional exponent. |
| jsonValidate(text : string) : bool Recursive-descent yes/no validity check, allocating no output tree — use it to gate untrusted input before further processing. |
| __escapeInto(buffer : ptr<i8>, offset : i64, src : string) : i64 Escape the bytes of src into buffer at offset using JSON rules:" \ \n \r \t \b \f get their short escapes, other control bytes( < 0x20) become \u00XX, and every other byte is copied verbatim(so valid UTF-8 round-trips). Returns the offset past the output. |
| jsonEscapeString(s : string) : string String escaping (the body without surrounding quotes — useful when concatenating into a larger structure). |
| jsonQuoteString(s : string) : string Full quoted form: "..." with inner escaping. |
| jsonI64ToString(v : i64) : string Decimal text of a signed 64-bit value (digits emitted least-significant-first then reversed; handles the minimum value without negating). |
| jsonF64ToString(v : f64) : string Float → JSON literal. Stays native: NaN / ±∞ map to null, finitevalues use the exact IEEE-754 shortest round-trip form. |
| jsonBoolToString(v : bool) : string The JSON literal true or false. |
| jsonNull() : string The JSON literal null. |
| __jsonKeyEquals(src : string, start : i64, end : i64, key : string) : bool Does the quoted key at start (its opening quote) and ending at end(past its closing quote) spell key?Compared as bytes when the span carries no escape, which is every key an API sends; a span holding one is decoded first, so "a\\u0062" stillmatches "ab". |
| __jsonDecodeString(src : string, start : i64, end : i64) : string The quoted string spanning [start, end) — start at its opening quote,end past its closing one — with its escapes decoded.A lone surrogate, or a high surrogate with no low one after it, encodes as U+FFFD: [ __txtPutUtf8] refuses to emit a surrogate, and a decoder thatdropped the byte instead would shorten the string a caller measured. |
| __jsonHex4(src : string, pos : i64, stop : i64) : i32 The scalar four hex digits at pos spell, or U+FFFD when they do not. |
| __jsonMember(src : string, pos : i64, len : i64, key : string) : i64 Byte position of the value bound to key in the object starting at pos,or -1 when there is no such member — or when pos does not start anobject at all, which is the same answer for the same reason: the caller asked for a field and there is none. The loop is the one in __jsonParseObject, written once more because thatone discards the two positions this needs. Validation already ran, so a malformed shape here is impossible rather than merely unhandled. |
| __jsonSpan(src : string, start : i64, end : i64) : string The raw bytes of src[start..end) as a string — no escape handling. |
Method detail
#__jsonIsWs
true for JSON's whitespace set (space, tab, LF, CR).
#__jsonIsDigit
true for an ASCII decimal digit.
#__jsonSkipWs
Position of the first non-whitespace byte at or after pos.
#__jsonEat
Consume one expected byte; returns pos + 1 or -1 if it doesn't match.
#__jsonEatKeyword
Consume the literal keyword byte-for-byte (no allocation); -1 on mismatch.
#__jsonParseValue
Any JSON value: object, array, string, keyword literal or number.
#__jsonParseObject
{ (string ':' value (',' string ':' value)*)? }.
#__jsonParseArray
[ value (',' value)* ]?.
#__jsonParseString
A quoted string, its escapes checked but not decoded (validation
only). \" \\ \/ \b \f \n \r \t are the short escapes;\uXXXX needs exactly 4 hex digits; any other byte after \ is
invalid, and raw control bytes (< 0x20) are rejected unescaped.
#__jsonParseNumber
A JSON number: optional -, integer part, optional fraction, optional exponent.
#jsonValidate
Recursive-descent yes/no validity check, allocating no output tree —
use it to gate untrusted input before further processing.
text candidate JSON document to validate#__escapeInto
Escape the bytes of src into buffer at offset using JSON rules:" \ \n \r \t \b \f get their short escapes, other control bytes
(< 0x20) become \u00XX, and every other byte is copied verbatim
(so valid UTF-8 round-trips). Returns the offset past the output.
buffer destination byte buffer (as a raw address)offset write position within the buffer to start atsrc source string whose bytes to JSON-escape#jsonEscapeString
String escaping (the body without surrounding quotes — useful when
concatenating into a larger structure).
s string to JSON-escape (no surrounding quotes added)#jsonQuoteString
Full quoted form: "..." with inner escaping.
s string to escape and wrap in JSON double quotes#jsonI64ToString
Decimal text of a signed 64-bit value (digits emitted
least-significant-first then reversed; handles the minimum value
without negating).
v signed integer to render as a JSON number#jsonF64ToString
Float → JSON literal. Stays native: NaN / ±∞ map to null, finite
values use the exact IEEE-754 shortest round-trip form.
v floating-point value to render as a JSON number#jsonBoolToString
The JSON literal true or false.
v bool to render as a JSON literal#jsonNull
The JSON literal null.
#__jsonKeyEquals
Does the quoted key at start (its opening quote) and ending at end
(past its closing quote) spell key?
Compared as bytes when the span carries no escape, which is every key an
API sends; a span holding one is decoded first, so "a\\u0062" still
matches "ab".
#__jsonDecodeString
The quoted string spanning [start, end) — start at its opening quote,end past its closing one — with its escapes decoded.
A lone surrogate, or a high surrogate with no low one after it, encodes as
U+FFFD: [__txtPutUtf8] refuses to emit a surrogate, and a decoder that
dropped the byte instead would shorten the string a caller measured.
#__jsonHex4
The scalar four hex digits at pos spell, or U+FFFD when they do not.
#__jsonMember
Byte position of the value bound to key in the object starting at pos,
or -1 when there is no such member — or when pos does not start an
object at all, which is the same answer for the same reason: the caller
asked for a field and there is none.
The loop is the one in __jsonParseObject, written once more because that
one discards the two positions this needs. Validation already ran, so a
malformed shape here is impossible rather than merely unhandled.
#__jsonSpan
The raw bytes of src[start..end) as a string — no escape handling.
C class Json
Constructors
| Type | Method and description |
|---|---|
| constructor(text : string) Take a cursor over text without validating it — parse isthe entry point, and this is what it calls once the document has been checked. Safe on a malformed document all the same: every accessor answers the neutral value on a shape it cannot read, so an unchecked cursor simply answers nothing rather than reading past anything. |
Method detail
#constructor
Take a cursor over text without validating it — parse is
the entry point, and this is what it calls once the document has been
checked.
Safe on a malformed document all the same: every accessor answers the
neutral value on a shape it cannot read, so an unchecked cursor simply
answers nothing rather than reading past anything.
Methods
| Type | Method and description |
|---|---|
| parse(text : string) : Json |
| has(self, key : string) : bool |
| text(self, key : string) : string |
| int(self, key : string) : i64 |
| num(self, key : string) : f64 |
| flag(self, key : string) : bool |