JSON value type, tag constants, conversion helpers, parser-result types, and serialization helpers.
Tag constants
Each constant is a static Int32 tag used by JSON.
JSONNull |
(-- tag) |
Provides the null tag, value 0. |
JSONInt |
(-- tag) |
Provides the signed-integer tag, value 1. |
JSONReal |
(-- tag) |
Provides the real-number tag, value 2. |
JSONCond |
(-- tag) |
Provides the boolean tag, value 3. |
JSONString |
(-- tag) |
Provides the string tag, value 4. |
JSONArray |
(-- tag) |
Provides the array tag, value 5. |
JSONObject |
(-- tag) |
Provides the object tag, value 6. |
JSON
JSON stores one tag and one payload. Its payload is an Int64, Real64, Cond, String, JSON Array, or String JSON HashTable.
JSON
(-- json) Constructs an owning JSONNull value.Fields
SCHEMA_NAME: static Text schema-name field with value"Json".mem0: reservedNat64implementation storage.mem1: reservedNat64implementation storage.mem2: reservedNatximplementation storage.mem3: reservedNatximplementation storage.impl: public internal implementation field; use tag and payload methods for ordinary access.
Initialization sets the active payload to JSONNull. Assignment copies the active payload, and destruction destroys it. Parsed strings, arrays, and objects therefore belong to the containing JSON value.
Methods
For every payload getter, a runtime tag mismatch reports Wrong tag in Tagged Union! and exits with status 2 when DEBUG is enabled. With DEBUG disabled, the runtime check is omitted; do not use a wrong-payload reference.
Payload getters return borrowed views, mutable through a mutable JSON and immutable through an immutable JSON. Reacquire them after relevant tag changes or storage-moving mutations of the containing arrays or objects; do not outlive the owner.
- Supported tags are
JSONNullthroughJSONObject; an unsupported stored tag is returned unchanged.
- When the tag differs, the old payload is destroyed and the new payload is initialized; references into the old payload are no longer valid.
- Repeating the current tag leaves the payload unchanged. Use the supported tags
JSONNullthroughJSONObject. The range is not checked: an unsupported tag is retained, and serialization reportsUnknown JSON tag!.
- The active tag must be
JSONInt.
- The active tag must be
JSONReal.
- The active tag must be
JSONCond.
- The active tag must be
JSONString.
- The active tag must be
JSONArray.
- The active tag must be
JSONObject.
Value conversions
Each conversion requires the payload schema itself: Int64, Real64, Cond, String, JSON Array, or String JSON HashTable, respectively. No implicit conversion is performed. Convert inputs first; for example, use "abc" toString stringAsJSON. Each result is a new owning JSON object. Immutable managed inputs are copied and mutable managed inputs may be moved from. intAsJSON accepts every Int64 value.
- Uses the conversion contract.
- Uses the conversion contract.
- Uses the conversion contract.
- Uses the conversion contract.
- Uses the conversion contract.
- Uses the conversion contract.
Payload and ownership rules
- A parsed JSON array is a
JSON Arrayof JSON values; a parsed object is aString JSON HashTablewhose keys are strings and whose values are JSON values. - The parse result owns its JSON tree and diagnostic message, but
errorInfo.position.currentSymbolborrows the original source bytes. Keep those bytes alive and unmoved while using that view. A copied position still refers to the same source bytes. - Check
successbefore using a parsed value, and also requirefinishedfor a complete-input parse. On failure,jsonmay contain a partial value; on clean completion,errorInfo.positionremains the default position. - Copying a
JSONcopies its active payload. A copied parsed tree can be changed without changing the original tree. - Changing the active tag or destroying a
JSONinvalidates references into its previous payload.
JSONParserResult
JSONParserResult
(-- result) Constructs success TRUE, finished TRUE, default errorInfo, and an owning JSONNull value.Fields
success:TRUEwhen lexical processing and node parsing succeed;FALSEon a JSON failure or when splitting reports an encoding failure.finished: startsTRUE.parseStringToJSONsets it toFALSEwhen trailing source characters remain;parseJSONNodedoes not derive it from remaining input.errorInfo:JSONParserErrorInfocontaining the diagnostic and position.json: the first parsedJSONnode when parsing reaches a node. With trailing input, it still contains that node.
Remarks
finishedis not a success flag: a failure at end of input can leave itTRUE. A clean, fully consumed parse leaveserrorInfo.positionat its default position.
JSONParserPosition
JSONParserPosition
(-- position) Constructs offset 0, line 1, column 1, currentCode 0, and an empty currentSymbol view.Fields
column:Int32one-based column in the split character views.line:Int32one-based line in the split character views.offset:Int32zero-based index into the split character views.currentSymbol: the current source-byte view from the split source, or an empty view at end of input.currentCode: the first byte ofcurrentSymbolconverted toNat32, not a decoded Unicode code point; it is zero at end of input.
Remarks
- Line and column are one-based; LF advances line and resets column to 1. A multibyte UTF-8 character advances one offset and one column.
- If splitting reports an encoding failure,
successisFALSE, the message isWrong encoding, can not recognize line and column, offset in bytes, offset and column contain the byte offset, and line is zero.
JSONParserErrorInfo
JSONParserErrorInfo
(-- errorInfo) Constructs an empty owned message and default position.Fields
message: parser diagnostic as aString.position:JSONParserPositionat the failure or first unparsed position.
Parser model and low-level helpers
Parsing runs at run time, including when source is known Text; inspect success, finished, payload, and position at run time.
- One source value is parsed as one JSON node. Leading and trailing whitespace is ignored; non-space trailing input makes
finishedFALSE. - Arrays preserve source order. Object keys must be unique; duplicate keys fail with
duplicate key. - Numbers without a fractional or exponent part produce
JSONInt; numbers with either produceJSONReal. - Leading zeros after the first digit fail with
not allowed digits after leading zero. Integer overflow normally fails withinteger constant overflow. - The accepted JSONInt range is
-9223372036854775807through9223372036854775807.9223372036854775808,-9223372036854775808, and-9223372036854775809fail withinteger constant overflow, foundinerrorInfo.messageat end of input. - Fractional or exponent notation produces JSONReal, including
9223372036854775808.0and9223372036854775808e0; an oversized integer without either notation fails rather than becoming JSONReal. - String escapes include
\",\\,\/,\b,\f,\t,\n,\r, and\uXXXX. - A high and low UTF-16 surrogate escape pair is combined into one code point. A high surrogate without
\ufollowed by a low surrogate, or a lone low surrogate, fails. Saving writes supplementary code points as paired\uXXXXescapes.
Current parser limitations
- Supply valid UTF-8; the parser is not a UTF-8 validator: malformed bytes inside a quoted string can be accepted and retained in the payload. Saving such a payload can replace malformed sequences with
\ufffdrather than report an error. - If splitting reports an encoding failure, success is
FALSEand message isWrong encoding, can not recognize line and column, offset in bytes. In that case offset and column contain the byte offset, and line is zero. - Large whole-number parts have a further limitation: after the integer accumulator wraps to zero, a following digit can cause
not allowed digits after leading zero. For example,184467440737095516160.0and184467440737095516160e0both fail at offset 20 withnot allowed digits after leading zero, 0 found. Fractional or exponent notation does not avoid this case. - The parser is not a strict JSON validator. It accepts trailing commas in arrays and objects, skips non-NUL control bytes up to 0x20 outside strings, and accepts malformed number spellings such as a single minus sign,
--1,1.,1e, and1e++2. - For an accepted number, digits in the fractional or exponent part select
JSONReal; otherwise the result isJSONInt. Thus the accepted spellings1.and1eyieldJSONInt, while1.0eyieldsJSONReal. Validate syntax separately when strict JSON input is required.
Failure messages
- Node diagnostics are
MESSAGE + ', ' + currentSymbol + ' found', with emptycurrentSymbolat end. - Malformed strings use
unterminated string,wrong code after \, orerror in unicodebefore the current symbol is appended. - An unquoted object key reports
quote expected. Malformed number syntax can reportwrong number constant. Surrogate failures use\u expected after high surrogate in \u escape,low surrogate expected after high surrogate in \u escape, orunexpected low surrogate in \u escape. - Malformed literals use
failed to read "true",failed to read "false",failed to read "null", orunexpected symbol. - Malformed containers use
: expected here,, or } expected here, or, or ] expected here.
Remarks
- Detected string-encoding failures use
Wrong encoding in JSON string!andWrong encoding in splitted array!when DEBUG is enabled. They do not make the current implementation a UTF-8 validator.
Low-level helpers
- The caller supplies storage satisfying JSON layout, alignment, extent, and lifetime. This helper neither initializes nor owns the storage.
JSONInit
(destinationAddress --) Initializes JSON storage to JSONNull.destinationAddressis aNatxaddress of suitable uninitialized storage. The caller supplies JSON layout, alignment, extent, and lifetime; do not overwrite a live owned payload without destroying it.
JSONSet
(sourceAddress destinationAddress --) Copies the source JSON into initialized destination storage.- Both arguments are
Natxaddresses of live JSON storage. The caller supplies suitable layout, alignment, extent, and lifetime for both objects.
JSONDestroy
(destinationAddress --) Destroys the payload in initialized JSON storage.destinationAddressis aNatxaddress of valid initialized storage. The call does not free containing storage; do not destroy the payload again without reinitializing it.
JSONImplArray
(-- array) Constructs an empty owning JSON Array.JSONImplObject
(-- object) Constructs an empty owning String JSON HashTable.JSONImpl
(-- impl) Constructs the internal tagged storage required by JSON.JSONImplRef
(-- ref) Supplies a static NIL reference descriptor for JSONImpl.makeJSONParserPosition
(code symbol offset line column -- position) Constructs a parser position from its five fields.jsonInternalFillPositionChars
(source position --) Refreshes currentSymbol and currentCode from offset.position.offsetmust be nonnegative. At or beyond the source end, the helper stores an empty view and zero; otherwise it stores the source view and its first byte.
parseJSONNodeImpl
(json result source position --) Parses one node with the low-level parser contract.- Use the same caller contract as
parseJSONNode: mutable JSON and JSONParserResult references, aStringView Array Crefsource, and a mutable JSONParserPosition reference. Initialize success and synchronize the position characters before the call; the helper does not derive finished from remaining input.
catJSONNodeWithPaddingImpl
(result padding json --) Appends one value with the serializer contract.- Use the same caller contract as
catJSONNodeWithPadding: a mutable String reference, a nonnegativeInt32padding, and an immutable JSON view. The first token has no leading padding; nested lines use padding + 2 spaces and the closing line uses padding spaces.
impl
(-- ref) Returns a borrowed JSONImpl view of the receiver storage.- The view preserves receiver constness; prefer tag and payload methods for ordinary access.
parseJSONNode
(json result source position --) Parses one node from an already split source into caller-supplied JSON and JSONParserResult values.jsonandresultare mutable JSON and JSONParserResult references.sourceis aStringView Array Cref;positionis aJSONParserPosition Ref.- Initialize
result.successto TRUE and synchronizecurrentSymbolandcurrentCodewith source and offset, usingjsonInternalFillPositionChars. - The call writes
json, updates position, and records failures in result. It does not derivefinishedfrom remaining input. The caller owns all destinations and source bytes.
resultis aString Ref,paddingis a nonnegativeInt32, andjsonis an immutable JSON view.- The first token has no leading padding. Nested lines use padding + 2 spaces and the closing line uses padding spaces. The call appends and returns no new String.
parseStringToJSON
See the parser runtime contract.
- The result reports lexical or JSON failure through
successanderrorInfo; trailing non-space input reportsfinished = FALSEwhile retaining the first node. - Check
successbefore using the parsed value, and requirefinishedfor a complete-input parse. The returned result owns the parsed JSON tree.
saveJSONToString
saveJSONToString
(json -- string) Serializes the stored value using the formatting rules below.- Arrays preserve item order. Objects follow
HashTableiteration order; that order is not a JSON key-order guarantee. - Objects and arrays use newlines and two spaces per nested level. Empty containers still use the container's multiline form.
- Booleans and null are written as
true,false, andnull. - Quotes, backslashes, slashes, and the JSON control escapes are emitted with their JSON escape forms. Other code points outside printable ASCII are written as
\uXXXX; supplementary code points use a high/low surrogate pair. - An invalid JSON tag fails with
Unknown JSON tag!.
Remarks
- Real formatting is lossy and does not preserve every
Real64value on a parse/save round trip. For example,0.1234567890123456789is saved as0.123457. Integer payloads are written in decimal without this real-number rounding. - A non-finite JSONReal is written as
inf,-inf, ornan; those spellings are not valid JSON. Require finite real payloads when valid JSON output is needed. A large parsed exponent such as1e400can produce infinity without a parse error.
Examples
Runtime parser results
"Json" use
"String" use
"control" use
{} () {} [
result: "{\"x\":1}" parseStringToJSON;
("success=" result.success
",finished=" result.finished
",tag=" result.json.getTag
",size=" result.json.getObject.size LF) printList
trailing: "{} x" parseStringToJSON;
duplicate: "{\"x\":1,\"x\":2}" parseStringToJSON;
("trailing-success=" trailing.success
",finished=" trailing.finished
",offset=" trailing.errorInfo.position.offset LF
"duplicate-success=" duplicate.success LF) printList
] "main" exportFunction
Expected Output
success=TRUE,finished=TRUE,tag=6,size=1
trailing-success=TRUE,finished=FALSE,offset=3
duplicate-success=FALSE
Parse and serialize array
"Json" use
"String" use
"control" use
{} Int32 {} [
result: "[1,true]" parseStringToJSON;
result.success ~ [
1
] [
result.json saveJSONToString print
0
] if
] "main" exportFunction
Expected Output
[
1,
true
]