std.json
RFC-8259 JSON parse and stringify, implemented in pure Bop.
Performance is reasonable for scripting workloads (config files, API payloads up to a few MB). A C-backed parser would be faster but would pull bop-std out of its zero-Rust-dep contract.
Import
use std.json // glob
use std.json.{parse, stringify} // selective
use std.json as j // aliased
stringify(value)
Emit value as JSON text. Bop values that have no JSON analogue (fn, struct, enum) raise a runtime error — strip them out before calling.
use std.json.{stringify}
print(stringify(42)) // "42"
print(stringify("hello")) // "\"hello\""
print(stringify([1, 2, 3])) // "[1,2,3]"
print(stringify({"name": "Alice", "age": 30})) // '{"name":"Alice","age":30}'
print(stringify(true)) // "true"
print(stringify(none)) // "null"
Strings are escaped for the five characters JSON requires (", \, \n, \r, \t). Other control characters under 0x20 are not currently escaped — fine for the common cases, but a known gap if you’re stringifying raw binary.
parse(text)
Parse JSON text into a Bop value. Parse errors raise a runtime error with a position marker.
use std.json.{parse}
print(parse("42")) // 42
print(parse("\"hello\"")) // "hello"
print(parse("[1, 2, 3]")) // [1, 2, 3]
print(parse("{\"name\": \"Alice\"}")) // {"name": "Alice"}
print(parse("null")) // none
Mapping
| JSON type | Bop type |
|---|---|
| number (integer) | int |
| number (decimal / exponent) | number |
| string | string |
| boolean | bool |
| null | none |
| array | array |
| object | dict (keys must be strings, which JSON already requires) |
Catching parse errors
parse raises on malformed input. Wrap in try_call if you want a Result-shaped outcome:
use std.json.{parse}
let r = try_call(fn() { return parse("\{broken") })
match r {
Result::Ok(v) => print("parsed: " + v.to_str()),
Result::Err(e) => print("parse failed: " + e.message),
}
// parse failed: ...
(The leading \{ escapes the { so Bop doesn’t mistake it for a string-interpolation marker.)
Known gaps
\b/\fescapes are rejected. Rare in real payloads.\uXXXXescapes are rejected — they’d need 4-hex parsing plus code-point-to-UTF-8 conversion, which is nontrivial in pure Bop.
Both raise a clear “unsupported escape” error so you know what happened.