Module
LinkJSONValue preserves exact number text and decoded JSON structure. Parse text with parse, encode values with stringify, and parse a requested type with parseAs. Decode an existing tree through the JSON protocol.
Why
LinkParsed JSON retains its value kinds before a caller chooses typed decoding.
Availability
LinkImport std.json in language mode 5.21. The current compiler selects std/json.tpz for this language mode. Availability in other released editions and inclusion in each installed distribution are Pending.
Exported types
Linkexport type JSON
Type members keep the compiler-owned type name shown in their declarations. Importing a module does not create a new type identity.
Public API
LinkPending contracts
LinkRead collection sizes, keys, and values as properties
LinkRead collection sizes, keys, and values as properties
Bytes.length and ByteBuffer.length are read-only int properties that report the number of bytes.
JSONValue.length is an Option<int> property. Arrays and objects return Some(count) for their element or member count. Other JSON kinds return None().
JSONValue.keys and JSONValue.values are properties returning Option<Array<string>> and Option<Array<JSON. Objects return Some(keys) or Some(values). Other JSON kinds return None().
Read these properties without parentheses, as with Array.length, Map.length, Map.keys, Map.values, and Set.length. Calling a property value is rejected as a non-callable value.
Why
The same collection observation should use the same syntax across core collections and library values. Keeping JSONValue results optional preserves its distinction between collections and scalar values.
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Read the same properties on core collections
Linkimport std.iolet array = [2, 3]let entries = map { "name": "Topaz" }let values = set { 2, 3 }io.writeLine("{array.length}:{entries.length}:{values.length}")io.writeLine(entries.keys[0])io.writeLine(entries.values[0])
2:1:2 name Topaz
Expected result
Expected result
Execution completes. Exit code 0.
2:1:2nameTopaz
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Read a byte sequence size
Linkimport std.bytes { Bytes }import std.iolet bytes = Bytes.empty()let size: int = bytes.lengthio.writeLine("{size}")
0
Expected result
Expected result
Execution completes. Exit code 0.
0
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Read a byte buffer size
Linkimport std.bytes { ByteBuffer }import std.iolet buffer = ByteBuffer.allocate(3)let size: int = buffer.lengthio.writeLine("{size}")
3
Expected result
Expected result
Execution completes. Exit code 0.
3
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Read JSON sizes and preserve optional results
Linkimport std.jsonimport std.testimport std.iolet array = test.assertOk(json.parse("[1,2]"))let object = test.assertOk(json.parse("\{\"name\":\"Topaz\"\}"))let scalar = test.assertOk(json.parse("42"))let arraySize: Option<int> = array.lengthlet objectSize: Option<int> = object.lengthlet scalarSize: Option<int> = scalar.lengthtest.assertEq(test.assertSome(arraySize), 2)test.assertEq(test.assertSome(objectSize), 1)test.assertNone(scalarSize)io.writeLine("JSON sizes read")
JSON sizes read
Expected result
Expected result
Execution completes. Exit code 0.
JSON sizes read
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Read JSON object keys
Linkimport std.jsonimport std.testimport std.iolet object = test.assertOk(json.parse("\{\"name\":\"Topaz\"\}"))let array = test.assertOk(json.parse("[]"))let scalar = test.assertOk(json.parse("42"))let names: Option<Array<string>> = object.keystest.assertEq(test.assertSome(names)[0], "name")test.assertNone(array.keys)test.assertNone(scalar.keys)io.writeLine("JSON keys read")
JSON keys read
Expected result
Expected result
Execution completes. Exit code 0.
JSON keys read
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Read JSON object values
Linkimport std.jsonimport std.testimport std.iolet object = test.assertOk(json.parse("\{\"name\":\"Topaz\"\}"))let array = test.assertOk(json.parse("[]"))let scalar = test.assertOk(json.parse("42"))let values = test.assertSome(object.values)test.assertEq(test.assertSome(values[0].asString()), "Topaz")test.assertNone(array.values)test.assertNone(scalar.values)io.writeLine("JSON values read")
JSON values read
Expected result
Expected result
Execution completes. Exit code 0.
JSON values read
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Reject calling Bytes.length
Linkimport std.bytes { Bytes }function inspect(value: Bytes) -> () {let result = value.length()return ()}
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5005stdlib-property-not-callable atmain.tpz:3:22
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Reject calling ByteBuffer.length
Linkimport std.bytes { ByteBuffer }function inspect(value: ByteBuffer) -> () {let result = value.length()return ()}
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5005stdlib-property-not-callable atmain.tpz:3:22
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Reject calling JSONValue.length
Linkimport std.json { JSONValue }function inspect(value: JSONValue) -> () {let result = value.length()return ()}
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5005stdlib-property-not-callable atmain.tpz:3:22
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Reject calling JSONValue.keys
Linkimport std.json { JSONValue }function inspect(value: JSONValue) -> () {let result = value.keys()return ()}
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5005stdlib-property-not-callable atmain.tpz:3:22
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Reject calling JSONValue.values
Linkimport std.json { JSONValue }function inspect(value: JSONValue) -> () {let result = value.values()return ()}
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5005stdlib-property-not-callable atmain.tpz:3:22
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 781 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 858 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 875 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 954 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
271329b482bc· 983 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 487 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 734 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 753 - compiler/crates/topaz_value/src/value/members.rs at
271329b482bc· 793 - compiler/crates/topaz_self_frontend/topaz/checker/call_complete.tpz at
271329b482bc· 1328 -
topaz.stdlib.contract.collection-propertiesatworking-tree - topaz.decision.collection-properties.1 at
topaz.decisi
Diagnostics
LinkInspect JSON kinds with kind
LinkInspect JSON kinds with kind
JSON returns exactly one of null, bool, number, string, array, or object. The name describes the JSON value's outermost kind. Both true and false have kind bool. Integer and fractional JSON numbers have kind number.
Test whether a JSON value is null with value.. This comparison is false for false, zero, the empty string, and empty arrays and objects. Reading the kind does not modify or decode the JSON value.
A present array element or object member containing JSON null is still present. at and get return Some(value) containing that JSONValue. An absent element or member returns None(). Inspect presence first, then compare the contained value's kind.
JSONValue does not expose an is member. Use the same kind comparison for null as for every other JSON kind.
Why
One kind query distinguishes every JSON value kind. Comparing that result uses the ordinary equality rule for null, booleans, numbers, strings, arrays, and objects. A separate null predicate would duplicate one case and give it a second spelling. Keeping presence separate also prevents a stored null from being mistaken for a missing entry.
Source evidence
- compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 659 - compiler/crates/topaz_value/src/value/json/parser.rs at
72a59a31125f· 4 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
72a59a31125f· 1156 - compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 698 -
topaz.stdlib.contract.json-kindatworking-tree - topaz.decision.json-kind-null.1 at
topaz.decisi
Distinguish null from every other JSON kind
Linkimport std.jsonimport std.testimport std.iofor source in (["null", "false", "0", "\"\"", "[]", "\{\}"]) {let value = test.assertOk(json.parse(source))let kind = value.kind()let nullKind = kind == "null"io.writeLine("{kind}:{nullKind}")}
null:true bool:false number:false string:false array:false object:false
Expected result
Expected result
Execution completes. Exit code 0.
null:truebool:falsenumber:falsestring:falsearray:falseobject:false
Source evidence
- compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 659 - compiler/crates/topaz_value/src/value/json/parser.rs at
72a59a31125f· 4 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
72a59a31125f· 1156 - compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 698 -
topaz.stdlib.contract.json-kindatworking-tree - topaz.decision.json-kind-null.1 at
topaz.decisi
Keep present null values distinct from missing entries
Linkimport std.jsonimport std.testimport std.iolet array = test.assertOk(json.parse("[null]"))let object = test.assertOk(json.parse("\{\"present\":null\}"))let arrayValue = test.assertSome(array.at(0))let objectValue = test.assertSome(object.get("present"))test.assertNone(array.at(1))test.assertNone(object.get("absent"))io.writeLine("{arrayValue.kind()}:{objectValue.kind()}")
null:null
Expected result
Expected result
Execution completes. Exit code 0.
null:null
Source evidence
- compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 659 - compiler/crates/topaz_value/src/value/json/parser.rs at
72a59a31125f· 4 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
72a59a31125f· 1156 - compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 698 -
topaz.stdlib.contract.json-kindatworking-tree - topaz.decision.json-kind-null.1 at
topaz.decisi
Reject the removed JSONValue.isNull member
Linkimport std.json { JSONValue }function inspect(value: JSONValue) -> () {let result = value.isNull()return ()}
No stdout.
Expected result
Source evidence
- compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 659 - compiler/crates/topaz_value/src/value/json/parser.rs at
72a59a31125f· 4 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
72a59a31125f· 1156 - compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 698 -
topaz.stdlib.contract.json-kindatworking-tree - topaz.decision.json-kind-null.1 at
topaz.decisi
Use kind to test a JSON value for null
Linkimport std.json { JSONValue }function inspect(value: JSONValue) -> () {let result = value.kind() == "null"return ()}
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 659 - compiler/crates/topaz_value/src/value/json/parser.rs at
72a59a31125f· 4 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
72a59a31125f· 1156 - compiler/crates/topaz_value/src/value/members.rs at
72a59a31125f· 698 -
topaz.stdlib.contract.json-kindatworking-tree - topaz.decision.json-kind-null.1 at
topaz.decisi
Diagnostics
LinkProject JSON values without coercion
LinkProject JSON values without coercion
JSON is an immutable JSON tree with the six JSON kinds. Reading a member preserves the tree.
as and as return Some for the matching kind and None() for every other kind. False and empty text are present values. Neither function parses text or converts a number.
number returns the exact accepted number lexeme for a number and None() for another kind. It preserves a negative zero, exponent spelling and fractional trailing zeroes.
as returns Some for a number spelled as an optional minus and decimal integer digits within the signed 64 bit range. Negative zero becomes zero. A decimal point, exponent, overflow or different kind returns None() without rounding.
as returns the elements of an array in source order. Another kind returns None(). The returned array is a separate collection. Changing that collection does not change the JSON tree.
at uses a zero based array index. A negative index, an index at or beyond the array length, or a receiver of another kind returns None(). get uses an exact decoded object key and returns None() for an absent key or another receiver kind. A present null child is Some containing JSON null.
length is a property containing the array element count or object member count. Scalar kinds yield None(). keys and values are object properties. They contain arrays in ascending Unicode scalar order of decoded keys, with corresponding positions. Array and scalar receivers yield None() for both properties.
The receiver and supplied arguments are evaluated once in ordinary call order. Inspection performs no I/O and invokes no user conversion. Incorrect argument types follow ordinary checking diagnostics rather than becoming absent values.
Why
Optional projection keeps a missing child distinct from a stored null. Number text preserves the original representation, while the integer projection has an explicit spelling and range. Sorted key and value positions support deterministic traversal.
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/members.rs at
912a5e86e1f9· 659 -
topaz.stdlib.contract.json-valueatworking-tree - topaz.decision.json-number-projection.1 at
topaz.decisi
Inspect present values and missing children
Linkimport std.jsonimport std.testimport std.iolet value = test.assertOk(json.parse("[false,\"\",null,7]"))let items = test.assertSome(value.asArray())test.assertEq(test.assertSome(items[0].asBool()), false)test.assertEq(test.assertSome(items[1].asString()), "")test.assertEq(items[2].kind(), "null")test.assertEq(test.assertSome(items[3].asInt()), 7)test.assertNone(value.at(-1))test.assertNone(value.at(4))test.assertNone(value.get("0"))test.assertNone(items[0].asString())test.assertNone(items[1].numberText())test.assertNone(items[2].asArray())let object = test.assertOk(json.parse("\{\"present\":null\}"))test.assertEq(test.assertSome(object.get("present")).kind(), "null")test.assertNone(object.get("missing"))test.assertNone(object.at(0))io.writeLine("present values remain distinct from missing children")
present values remain distinct from missing children
Expected result
Expected result
Execution completes. Exit code 0.
present values remain distinct from missing children
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/members.rs at
912a5e86e1f9· 659 -
topaz.stdlib.contract.json-valueatworking-tree - topaz.decision.json-number-projection.1 at
topaz.decisi
Keep integer projection within the declared spelling and range
Linkimport std.jsonimport std.testimport std.iofor text in (["-9223372036854775808", "9223372036854775807", "9223372036854775808", "-0", "1.0", "1e0", "1.5"]) {let value = test.assertOk(json.parse(text))match (value.asInt()) {case Some(number) => io.writeLine("{text} = {number}")case None() => io.writeLine("{text} = none")}}
-9223372036854775808 = -9223372036854775808 9223372036854775807 = 9223372036854775807 9223372036854775808 = none -0 = 0 1.0 = none 1e0 = none 1.5 = none
Expected result
Expected result
Execution completes. Exit code 0.
-9223372036854775808 = -92233720368547758089223372036854775807 = 92233720368547758079223372036854775808 = none-0 = 01.0 = none1e0 = none1.5 = none
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/members.rs at
912a5e86e1f9· 659 -
topaz.stdlib.contract.json-valueatworking-tree - topaz.decision.json-number-projection.1 at
topaz.decisi
Read matching keys and values in scalar order
Linkimport std.jsonimport std.testimport std.iolet object = test.assertOk(json.parse("\{\"z\":1,\"a\":null\}"))let names = test.assertSome(object.keys)let values = test.assertSome(object.values)test.assertEq(test.assertSome(object.length), 2)io.writeLine("{names[0]} = {values[0].kind()}")io.writeLine("{names[1]} = {test.assertSome(values[1].asInt())}")let array = test.assertOk(json.parse("[]"))test.assertEq(test.assertSome(array.length), 0)test.assertNone(array.keys)test.assertNone(array.values)let scalar = test.assertOk(json.parse("\"text\""))test.assertNone(scalar.length)
a = null z = 1
Expected result
Expected result
Execution completes. Exit code 0.
a = nullz = 1
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/members.rs at
912a5e86e1f9· 659 -
topaz.stdlib.contract.json-valueatworking-tree - topaz.decision.json-number-projection.1 at
topaz.decisi
Parse a complete JSON document
LinkParse a complete JSON document
parse accepts one complete JSON value with leading and trailing space, tab, CR or LF. An empty input, a byte order mark, comments, trailing commas and trailing nonwhitespace return Err. Scalars are valid roots.
JSON numbers follow the JSON decimal grammar. A leading plus, redundant leading zero, missing fraction or exponent digits, NaN and infinities are invalid. Every accepted lexeme is stored exactly without conversion to binary floating point. Its magnitude need not fit int or float.
Quoted strings decode the JSON escapes and valid UTF 16 surrogate pairs into Unicode scalar values. Unescaped controls, malformed escapes and unpaired surrogates return Err. No Unicode normalization is performed.
Object names are compared after escape decoding. A repeated name returns Err before its value is converted into the object. The second name does not overwrite the first. Arrays preserve source order and object traversal follows the decoded key order.
The root starts at depth zero. Descending into an array element or object value adds one. Depths through 128 are accepted and the first value at depth 129 returns Err with a nesting limit message.
A parse failure returns a record containing a nonempty cause message and one based line and column integers. Columns count Unicode scalar values. CRLF is one line break and a lone CR or LF also starts the next line. The first offending scalar is the location. An invalid escape points to its backslash. A repeated name points to its second opening quote. An incomplete input points immediately after the final scalar.
The text expression is evaluated once before parsing. The parser consumes through trailing whitespace before returning Ok. It performs no I/O, invokes no typed decoder and exposes no partial tree. Malformed data uses the Result error channel rather than a runtime diagnostic.
Why
Exact number storage avoids losing document data before a caller chooses a numeric type. Rejecting duplicate names prevents source order from silently selecting a value. A single scalar based location rule makes errors actionable across Unicode text and newline styles.
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 78 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 108 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 289 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parseatworking-tree - topaz.decision.json-parse-boundaries.1 at
topaz.decisi
Retain numbers beyond binary and integer precision
Linkimport std.jsonimport std.testimport std.iofor text in (["9007199254740993", "9223372036854775808", "-0", "1.2300e+03", "1e9999"]) {let value = test.assertOk(json.parse(text))io.writeLine(test.assertSome(value.numberText()))}
9007199254740993 9223372036854775808 -0 1.2300e+03 1e9999
Expected result
Expected result
Execution completes. Exit code 0.
90071992547409939223372036854775808-01.2300e+031e9999
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 78 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 108 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 289 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parseatworking-tree - topaz.decision.json-parse-boundaries.1 at
topaz.decisi
Locate the first invalid scalar and end of input
Linkimport std.jsonimport std.iofor text in (["", "true false", "[1,]", "[1 x]", "[\rtrue,\r?]"]) {match (json.parse(text)) {case Ok(_) => io.writeLine("accepted")case Err(error) => io.writeLine("{error.line},{error.column}")}}
1,1 1,6 1,4 1,4 3,1
Expected result
Expected result
Execution completes. Exit code 0.
1,11,61,41,43,1
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 78 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 108 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 289 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parseatworking-tree - topaz.decision.json-parse-boundaries.1 at
topaz.decisi
Reject a repeated decoded key at its opening quote
Linkimport std.jsonimport std.iomatch (json.parse("\{\"a\":1,\"\\u0061\":2\}")) {case Ok(_) => io.writeLine("accepted")case Err(error) => io.writeLine("{error.line},{error.column}")}
1,8
Expected result
Expected result
Execution completes. Exit code 0.
1,8
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 78 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 108 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 289 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parseatworking-tree - topaz.decision.json-parse-boundaries.1 at
topaz.decisi
Decode surrogate pairs and reject malformed JSON spellings
Linkimport std.jsonimport std.testimport std.iolet value = test.assertOk(json.parse("\"\\uD83D\\uDE00\""))test.assertEq(test.assertSome(value.asString()), "😀")for text in (["01", "+1", "1.", "1e", "NaN", "\"\\uD800\"", "\"\\uDC00\""]) {match (json.parse(text)) {case Ok(_) => io.writeLine("accepted")case Err(_) => io.writeLine("invalid")}}
invalid invalid invalid invalid invalid invalid invalid
Expected result
Expected result
Execution completes. Exit code 0.
invalidinvalidinvalidinvalidinvalidinvalidinvalid
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 78 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 108 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 289 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parseatworking-tree - topaz.decision.json-parse-boundaries.1 at
topaz.decisi
Accept depth 128 and reject the next child
Linkimport std.jsonimport std.iolet mut text = "0"for level in (0 ..< 128) {text = "[" + text + "]"}match (json.parse(text)) {case Ok(_) => io.writeLine("depth 128 accepted")case Err(_) => io.writeLine("depth 128 rejected")}match (json.parse("[" + text + "]")) {case Ok(_) => io.writeLine("depth 129 accepted")case Err(_) => io.writeLine("depth 129 rejected")}
depth 128 accepted depth 129 rejected
Expected result
Expected result
Execution completes. Exit code 0.
depth 128 accepteddepth 129 rejected
Source evidence
- compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 78 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 108 - compiler/crates/topaz_value/src/value/json/parser.rs at
912a5e86e1f9· 289 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parseatworking-tree - topaz.decision.json-parse-boundaries.1 at
topaz.decisi
Serialize JSON in a deterministic order
LinkSerialize JSON in a deterministic order
stringify requires the JSON conformance of its input type. It calls JSON. once and writes the returned JSON tree. A type without that conformance is rejected during checking with TPZ5533. The protocol representation rules define records, enums, arrays, maps, options, results and custom codecs.
Successful output contains one compact JSON value with no leading whitespace or terminal newline. Object names follow the decoded key order. Arrays retain their element order. Map insertion order and record declaration order do not choose serialization order.
The writer escapes quotation marks and backslashes. It uses the short escapes for LF, CR and tab. Other controls below U+0020 use four digit lowercase Unicode escapes. Other scalar values are emitted unchanged. It does not escape a slash or normalize Unicode.
An existing JSONValue retains every accepted number lexeme. An int uses decimal digits and an optional minus. Float encoding follows JSON numeric conversion, including its shortest binary64 roundtrip spelling and negative zero. NaN and infinities return Err.
The depth and active value cycle rules of JSON conversion apply. A depth above 128 or a value cycle returns an error beginning JSON_. Other value failures return the selected codec error. Built in conversion errors identify the first failing child with a path rooted at $.
The input expression is evaluated before conversion. Built in conversions visit arrays in index order and objects in sorted key order. A custom encoder retains its ordinary evaluation and side effects. An encoder error prevents writing. This function returns text and performs no filesystem or stream write.
Why
Stable JSON bytes support fixtures and reproducible document inputs. The existing JSON conformance supplies one conversion path, while a Result distinguishes invalid values from successful text.
Source evidence
- compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 71 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 204 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 221 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 151 -
topaz.stdlib.contract.json-stringifyatworking-tree - topaz.decision.json-write-order.1 at
topaz.decisi
Write sorted objects and preserve a parsed number lexeme
Linkimport std.jsonimport std.testimport std.ioio.writeLine(test.assertOk(json.stringify(map { "z": 1, "a": 2 })))io.writeLine(test.assertOk(json.stringify(["a,b", "x\"y", "\n", "é"])))let number = test.assertOk(json.parse("1.2300e+03"))io.writeLine(test.assertOk(json.stringify(number)))let empty: Array<int> = []io.writeLine(test.assertOk(json.stringify(empty)))
{"a":2,"z":1}
["a,b","x\"y","\n","é"]
1.2300e+03
[]
Expected result
Expected result
Execution completes. Exit code 0.
{"a":2,"z":1}["a,b","x\"y","\n","é"]1.2300e+03[]
Source evidence
- compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 71 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 204 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 221 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 151 -
topaz.stdlib.contract.json-stringifyatworking-tree - topaz.decision.json-write-order.1 at
topaz.decisi
Write finite float values and reject a nonfinite value
Linkimport std.jsonimport std.iofor value in ([1.5, -0.0]) {match (json.stringify(value)) {case Ok(text) => io.writeLine(text)case Err(_) => io.writeLine("rejected")}}match (json.stringify(0.0 / 0.0)) {case Ok(_) => io.writeLine("accepted")case Err(_) => io.writeLine("nonfinite rejected")}
1.5 -0 nonfinite rejected
Expected result
Expected result
Execution completes. Exit code 0.
1.5-0nonfinite rejected
Source evidence
- compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 20 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 71 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 204 - compiler/crates/topaz_value/src/value/json/codec.rs at
912a5e86e1f9· 221 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 151 -
topaz.stdlib.contract.json-stringifyatworking-tree - topaz.decision.json-write-order.1 at
topaz.decisi
Parse text before typed JSON decoding
LinkParse text before typed JSON decoding
parse requires an explicit JSON decodable result type. The ordinary JSON capability checks apply. Omitting a required result type or selecting a type without decoding support produces TPZ5534.
The function completes JSON parsing before calling JSON.. A malformed document returns an error string containing the parse cause, line and column. It never calls the decoder on a malformed or trailing input.
After parsing succeeds, the selected decoder is called once. Its Ok payload or Err message becomes the result. Custom decoder effects occur after parsing and follow ordinary function evaluation. Built in decoding performs no I/O.
The JSON protocol defines supported representations. Derived records ignore unknown fields and use declared defaults for missing fields. A missing required field, wrong kind, unknown enum tag, wrong payload count or value outside the target numeric range returns Err. No string to number or string to boolean coercion is performed.
Built in errors describe the expected shape and first failing path rooted at $. Arrays are checked in increasing index order and object fields in ascending Unicode scalar order. Built in int decoding requires an exactly integral value within signed 64 bit bounds. Float decoding follows the protocol rounding and overflow rules. Optional null and nested option normalization follow the same protocol rule as JSON.. Use numberText and asInt when the input must retain the integer spelling boundary.
Decode an already parsed tree with JSON.. There is no second JSONValue receiver decoding form. Parsing failure and decoding failure are recoverable Result errors and do not produce assertion diagnostics by themselves.
Why
Parsing and decoding are separate boundaries. A complete syntax check prevents a user decoder from acting on malformed input, and one protocol dispatch keeps text and tree conversion consistent.
Source evidence
- compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 716 - compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 828 - compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 930 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parse-asatworking-tree - topaz.decision.json-write-order.1 at
topaz.decisi
Decode a record after parsing and report invalid data
Linkimport std.jsonimport std.testimport std.iorecord Item derives JSON { name: string, count: int = 7 }let item = test.assertOk(json.parseAs<Item>("\{\"name\":\"ink\",\"extra\":true\}"))io.writeLine("{item.name},{item.count}")for text in (["\{\}", "17", "[", "\{\"name\":\"ink\",\"count\":9223372036854775808\}"]) {match (json.parseAs<Item>(text)) {case Ok(_) => io.writeLine("accepted")case Err(_) => io.writeLine("invalid data")}}
ink,7 invalid data invalid data invalid data invalid data
Expected result
Expected result
Execution completes. Exit code 0.
ink,7invalid datainvalid datainvalid datainvalid data
Source evidence
- compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 716 - compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 828 - compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 930 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parse-asatworking-tree - topaz.decision.json-write-order.1 at
topaz.decisi
Call a custom decoder once after complete parsing
Linkimport std.json { JSONValue, parseAs }import std.iorecord Token { text: string }impl JSON<Token> {function encode(value: Token) -> Result<JSONValue, string> {JSON.encode(value.text)}function decode(value: JSONValue) -> Result<Token, string> {io.writeLine("decode")match (value.asString()) {case Some(text) => Ok(Token { text: text })case None() => Err("expected token string")}}}match (parseAs<Token>("\"ink\"")) {case Ok(value) => io.writeLine(value.text)case Err(message) => io.writeLine(message)}match (parseAs<Token>("\"ink\" false")) {case Ok(_) => io.writeLine("accepted")case Err(_) => io.writeLine("parse failed before decode")}
decode ink parse failed before decode
Expected result
Expected result
Execution completes. Exit code 0.
decodeinkparse failed before decode
Source evidence
- compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 716 - compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 828 - compiler/crates/topaz_value/src/value/json/schema.rs at
912a5e86e1f9· 930 - compiler/crates/topaz_self_frontend/topaz/emitter/builtins.tpz at
912a5e86e1f9· 152 -
topaz.stdlib.contract.json-parse-asatworking-tree - topaz.decision.json-write-order.1 at
topaz.decisi