///|
/// Required typed lookup. Text values remain text; numeric-looking strings are not coerced.
pub fn get_string(config : Value, key : String) -> String raise ParseError {
match peek_document_path(config, key) {
Some(Text(s) | Bare(s)) => s
None => raise Invalid("missing key " + key)
_ => raise Invalid("expected string " + key)
}
}
///|
pub fn get_int(config : Value, key : String) -> Int raise ParseError {
match peek_document_path(config, key) {
Some(Number(s)) =>
@string.parse_int(s) catch {
_ => raise Invalid("expected 32-bit integer " + key)
}
None => raise Invalid("missing key " + key)
_ => raise Invalid("expected number " + key)
}
}
///|
pub fn get_bool(config : Value, key : String) -> Bool raise ParseError {
match peek_document_path(config, key) {
Some(Boolean(b)) => b
None => raise Invalid("missing key " + key)
_ => raise Invalid("expected boolean " + key)
}
}
///|
pub fn get_list(config : Value, key : String) -> Array[Value] raise ParseError {
match peek_document_path(config, key) {
Some(List(items)) => items.copy()
None => raise Invalid("missing key " + key)
_ => raise Invalid("expected list " + key)
}
}
///|
/// Stable JSON rendering of a resolved value; number spelling is retained.
pub fn Value::to_json_string(self : Value) -> String raise ParseError {
render(self, 0, Work::{ remaining: 1000000, next_id: 0, })
}
///|
fn render(v : Value, depth : Int, work : Work) -> String raise ParseError {
if depth > 64 {
raise Invalid("JSON nesting limit")
}
let result = match v {
Text(s) | Bare(s) => s.to_json().stringify()
Number(s) => {
let checked = @json.parse(s) catch {
_ => {
if !numeric_text(s) {
raise Invalid("invalid numeric value")
}
let value = @string.parse_double(s) catch {
_ => raise Invalid("invalid numeric value")
}
return value.to_string()
}
}
match checked {
Number(_) => s
_ => raise Invalid("invalid numeric value")
}
}
Boolean(b) => if b { "true" } else { "false" }
Null => "null"
List(items) =>
"[" + items.map(x => render(x, depth + 1, work)).join(",") + "]"
Object(m) | SealedObject(m) => {
let keys = m.keys().collect()
keys.sort()
"{" +
keys
.map(k => k.to_json().stringify() + ":" + render(m[k], depth + 1, work))
.join(",") +
"}"
}
_ => raise Invalid("unresolved value cannot be rendered")
}
work.spend(result.length())
result
}