json.bend source
json.bend on the hub · documented module
import Basedef q() -> String: SCon{Chr{34}, SNil{}}def bs() -> String: SCon{Chr{92}, SNil{}}def quoted(+k: String) -> String: q() ++ k ++ q()def escape(s: String) -> String: match s: case SNil{}: SNil{} case SCon{Chr{34}, t}: bs() ++ q() ++ escape(t) case SCon{Chr{92}, t}: bs() ++ bs() ++ escape(t) case SCon{h, t}: Char.show(h) ++ escape(t)def pair(+k: String, +v: String) -> String: quoted(k) ++ ":" ++ quoted(escape(v))def object1(+k: String, +v: String) -> String: "{" ++ pair(k, v) ++ "}"def object2(+k1: String, +v1: String, +k2: String, +v2: String) -> String: "{" ++ pair(k1, v1) ++ "," ++ pair(k2, v2) ++ "}"def object3( +k1: String, +v1: String, +k2: String, +v2: String, +k3: String, +v3: String) -> String: "{" ++ pair(k1, v1) ++ "," ++ pair(k2, v2) ++ "," ++ pair(k3, v3) ++ "}"def skip_ws(s: String) -> String: match s: case SNil{}: SNil{} case SCon{Chr{32}, t}: skip_ws(t) case SCon{Chr{9}, t}: skip_ws(t) case SCon{Chr{10}, t}: skip_ws(t) case SCon{Chr{13}, t}: skip_ws(t) case SCon{h, t}: SCon{h, t}def after_colon.on(s: String) -> Maybe<&2, String>: match s: case SNil{}: None{} case SCon{Chr{58}, t}: Some{skip_ws(t)} case SCon{h, t}: None{}def after_colon(s: String) -> Maybe<&2, String>: after_colon.on(skip_ws(s))def take_string.go(s: String, acc: String) -> Maybe<&2, String>: match s: case SNil{}: None{} case SCon{Chr{34}, t}: Some{String.reverse(acc)} case SCon{Chr{92}, t}: match t: case SNil{}: None{} case SCon{h, rest}: take_string.go(rest, SCon{h, acc}) case SCon{h, t}: take_string.go(t, SCon{h, acc})def take_string(s: String) -> Maybe<&2, String>: match s: case SNil{}: None{} case SCon{Chr{34}, t}: take_string.go(t, SNil{}) case SCon{h, t}: None{}def take_u32.go(s: String, +acc: U32) -> Maybe<&2, U32>: match s: case SNil{}: Some{acc} case SCon{Chr{48}, t}: take_u32.go(t, U32.mul(acc, 10)) case SCon{Chr{49}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 1)) case SCon{Chr{50}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 2)) case SCon{Chr{51}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 3)) case SCon{Chr{52}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 4)) case SCon{Chr{53}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 5)) case SCon{Chr{54}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 6)) case SCon{Chr{55}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 7)) case SCon{Chr{56}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 8)) case SCon{Chr{57}, t}: take_u32.go(t, U32.add(U32.mul(acc, 10), 9)) case SCon{h, t}: Some{acc}def take_u32.start(s: String) -> Maybe<&2, U32>: match s: case SNil{}: None{} case SCon{Chr{48}, t}: take_u32.go(t, 0) case SCon{Chr{49}, t}: take_u32.go(t, 1) case SCon{Chr{50}, t}: take_u32.go(t, 2) case SCon{Chr{51}, t}: take_u32.go(t, 3) case SCon{Chr{52}, t}: take_u32.go(t, 4) case SCon{Chr{53}, t}: take_u32.go(t, 5) case SCon{Chr{54}, t}: take_u32.go(t, 6) case SCon{Chr{55}, t}: take_u32.go(t, 7) case SCon{Chr{56}, t}: take_u32.go(t, 8) case SCon{Chr{57}, t}: take_u32.go(t, 9) case SCon{h, t}: None{}def take_u32(s: String) -> Maybe<&2, U32>: take_u32.start(skip_ws(s))def take_bool.f(+s: String, is_false: Bool) -> Maybe<&2, Bool>: match is_false: case True{}: Some{False{}} case False{}: None{}def take_bool.t(+s: String, is_true: Bool) -> Maybe<&2, Bool>: match is_true: case True{}: Some{True{}} case False{}: take_bool.f(s, String.starts_with(s, "false"))def take_bool.on(+s: String) -> Maybe<&2, Bool>: take_bool.t(s, String.starts_with(s, "true"))def take_bool(s: String) -> Maybe<&2, Bool>: take_bool.on(skip_ws(s))def after_key.go( n: Nat, sel: Nat, s: String, +key: String, here: Bool) -> Maybe<&2, String>: match n sel s here: case 0n _ _ _: None{} case 1n+p 0n SNil{} _: None{} case 1n+p 0n SCon{h, t} _: +s2 = {SCon{h, t} : String} after_key.go(p, 1n, s2, key, String.starts_with(s2, quoted(key))) case 1n+p 1n+z rest True{}: after_colon(String.drop(rest, String.length(quoted(key)))) case 1n+p 1n+z SNil{} False{}: None{} case 1n+p 1n+z SCon{h, t} False{}: after_key.go(p, 0n, t, key, False{})def after_key(+s: String, +key: String) -> Maybe<&2, String>: after_key.go( Nat.add(String.length(s), Nat.add(String.length(s), 2n)), 0n, s, key, False{} )def string_from(r: Maybe<&2, String>) -> Maybe<&2, String>: match r: case None{}: None{} case Some{rest}: take_string(rest)def bool_from(r: Maybe<&2, String>) -> Maybe<&2, Bool>: match r: case None{}: None{} case Some{rest}: take_bool(rest)def u32_from(r: Maybe<&2, String>) -> Maybe<&2, U32>: match r: case None{}: None{} case Some{rest}: take_u32(rest)def string_field(+json: String, +key: String) -> Maybe<&2, String>: string_from(after_key(json, key))def bool_field(+json: String, +key: String) -> Maybe<&2, Bool>: bool_from(after_key(json, key))def u32_field(+json: String, +key: String) -> Maybe<&2, U32>: u32_from(after_key(json, key))def need_string(r: Maybe<&2, String>, missing: String) -> Result<&2, &2, String, String>: match r: case None{}: Fail{missing} case Some{v}: Done{v}def or_empty(r: Maybe<&2, String>) -> String: match r: case None{}: "" case Some{v}: vdef or_false(r: Maybe<&2, Bool>) -> Bool: match r: case None{}: False{} case Some{v}: v