{"name":"json_basic.nu","source":"// json_basic.nu — exercises stdlib/ext/json.nu\n//\n// Expected output:\n//   parse null ok type=null\n//   parse true ok type=bool val=T\n//   parse false ok type=bool val=F\n//   parse 42 ok type=num as_i=42\n//   parse -3.5 ok type=num as_f=-3.5\n//   parse \"hi\\n\" ok type=str data=hi\n//   parse [1,2,3] ok type=arr len=3 first=1\n//   parse {\"a\":1,\"b\":[true,null]} ok type=obj a=1 b_len=2\n//   stringify roundtrip ok\n//   err empty: empty input\n//   err bad: bad format\n//   err trailing: trailing garbage\n\n$ `stdlib/ext/json.nu`\n\n@ show_err s label JsonError e → v {\n    ( nurl_print label )\n    ( nurl_print ( parse_err_msg # ParseErr . e kind ) )\n    ( nurl_print `\\n` )\n}\n\n@ main → i {\n    // 1. null\n    : !Json JsonError r1 ( json_parse `null` )\n    ?? r1 {\n        T j → {\n            ( nurl_print `parse null ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print `\\n` )\n            ( json_free j )\n        }\n        F e → ( show_err `parse null err: ` # JsonError e )\n    }\n\n    // 2. true\n    : !Json JsonError r2 ( json_parse `true` )\n    ?? r2 {\n        T j → {\n            ( nurl_print `parse true ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` val=` )\n            ( nurl_print ? ( json_bool_val j ) `T` `F` )\n            ( nurl_print `\\n` )\n            ( json_free j )\n        }\n        F e → ( show_err `parse true err: ` # JsonError e )\n    }\n\n    // 3. false\n    : !Json JsonError r3 ( json_parse `false` )\n    ?? r3 {\n        T j → {\n            ( nurl_print `parse false ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` val=` )\n            ( nurl_print ? ( json_bool_val j ) `T` `F` )\n            ( nurl_print `\\n` )\n            ( json_free j )\n        }\n        F e → ( show_err `parse false err: ` # JsonError e )\n    }\n\n    // 4. integer\n    : !Json JsonError r4 ( json_parse `42` )\n    ?? r4 {\n        T j → {\n            ( nurl_print `parse 42 ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` as_i=` )\n            : ?i ai ( json_num_as_i j )\n            ?? ai {\n                T n → ( nurl_print ( nurl_str_int n ) )\n                F → ( nurl_print `(none)` )\n            }\n            ( nurl_print `\\n` )\n            ( json_free j )\n        }\n        F e → ( show_err `parse 42 err: ` # JsonError e )\n    }\n\n    // 5. negative float\n    : !Json JsonError r5 ( json_parse `-3.5` )\n    ?? r5 {\n        T j → {\n            ( nurl_print `parse -3.5 ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` as_f=` )\n            : ?f af ( json_num_as_f j )\n            ?? af {\n                T x → ( nurl_print ( nurl_str_float x ) )\n                F → ( nurl_print `(none)` )\n            }\n            ( nurl_print `\\n` )\n            ( json_free j )\n        }\n        F e → ( show_err `parse -3.5 err: ` # JsonError e )\n    }\n\n    // 6. string with escape\n    : !Json JsonError r6 ( json_parse `\"hi\\n\"` )\n    ?? r6 {\n        T j → {\n            ( nurl_print `parse \"hi\\\\n\" ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` data=` )\n            ( nurl_print ( json_str_data j ) )\n            ( json_free j )\n        }\n        F e → ( show_err `parse string err: ` # JsonError e )\n    }\n\n    // 7. array of integers\n    : !Json JsonError r7 ( json_parse `[1, 2, 3]` )\n    ?? r7 {\n        T j → {\n            ( nurl_print `parse [1,2,3] ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` len=` )\n            ( nurl_print ( nurl_str_int ( json_arr_len j ) ) )\n            ( nurl_print ` first=` )\n            : ?Json fst ( json_arr_get j 0 )\n            ?? fst {\n                T v → {\n                    : ?i ai ( json_num_as_i v )\n                    ?? ai {\n                        T n → ( nurl_print ( nurl_str_int n ) )\n                        F → ( nurl_print `?` )\n                    }\n                }\n                F → ( nurl_print `none` )\n            }\n            ( nurl_print `\\n` )\n            ( json_free j )\n        }\n        F e → ( show_err `parse arr err: ` # JsonError e )\n    }\n\n    // 8. object with mixed values\n    : !Json JsonError r8 ( json_parse `{\"a\": 1, \"b\": [true, null]}` )\n    ?? r8 {\n        T j → {\n            ( nurl_print `parse obj ok type=` )\n            ( nurl_print ( json_type_name j ) )\n            ( nurl_print ` a=` )\n            : ?Json va ( json_obj_get j `a` )\n            ?? va {\n                T v → {\n                    : ?i ai ( json_num_as_i v )\n                    ?? ai {\n                        T n → ( nurl_print ( nurl_str_int n ) )\n                        F → ( nurl_print `?` )\n                    }\n                }\n                F → ( nurl_print `(missing)` )\n            }\n            ( nurl_print ` b_len=` )\n            : ?Json vb ( json_obj_get j `b` )\n            ?? vb {\n                T v → ( nurl_print ( nurl_str_int ( json_arr_len v ) ) )\n                F → ( nurl_print `(missing)` )\n            }\n            ( nurl_print `\\n` )\n\n            // 9. roundtrip\n            : String out ( json_stringify j )\n            // Re-parse the serialized form and compare top-level keys.\n            : !Json JsonError r9 ( json_parse ( string_data out ) )\n            ?? r9 {\n                T j2 → {\n                    ? & ( json_is_obj j2 ) ( json_obj_has j2 `b` ) {\n                        ( nurl_print `stringify roundtrip ok\\n` )\n                    } {\n                        ( nurl_print `stringify roundtrip MISMATCH\\n` )\n                    }\n                    ( json_free j2 )\n                }\n                F e → ( show_err `roundtrip parse err: ` # JsonError e )\n            }\n            ( string_free out )\n            ( json_free j )\n        }\n        F e → ( show_err `parse obj err: ` # JsonError e )\n    }\n\n    // 10. error paths\n    : !Json JsonError re1 ( json_parse `` )\n    ?? re1 {\n        T j → { ( nurl_print `unexpected ok\\n` ) ( json_free j ) }\n        F e → ( show_err `err empty: ` # JsonError e )\n    }\n\n    : !Json JsonError re2 ( json_parse `xyz` )\n    ?? re2 {\n        T j → { ( nurl_print `unexpected ok\\n` ) ( json_free j ) }\n        F e → ( show_err `err bad: ` # JsonError e )\n    }\n\n    : !Json JsonError re3 ( json_parse `42 trailing` )\n    ?? re3 {\n        T j → { ( nurl_print `unexpected ok\\n` ) ( json_free j ) }\n        F e → ( show_err `err trailing: ` # JsonError e )\n    }\n\n    // 11. json_pretty + json_obj_keys + json_arr_each + json_obj_each\n    : !Json JsonError rp ( json_parse `{\"x\":1,\"y\":[true,null],\"z\":\"q\"}` )\n    ?? rp {\n        T j → {\n            // pretty roundtrips through compact parser back into the same value\n            : String pp ( json_pretty j )\n            ( nurl_print `pretty:\\n` )\n            ( nurl_print ( string_data pp ) )\n            ( nurl_print `\\n` )\n\n            // obj_keys yields the key list in declaration order\n            : ( Vec String ) keys ( json_obj_keys j )\n            ( nurl_print `keys=` )\n            : i kn ( vec_len [String] keys )\n            : ~ i ki 0\n            ~ < ki kn {\n                : ?String e ( vec_get [String] keys ki )\n                ?? e {\n                    T s → {\n                        ? > ki 0 { ( nurl_print `,` ) } {}\n                        ( nurl_print ( string_data s ) )\n                    }\n                    F → {}\n                }\n                = ki + ki 1\n            }\n            ( nurl_print `\\n` )\n            : ( @ v String ) drop_s \\ String s → v { ( string_free s ) }\n            ( vec_free_with [String] keys drop_s )\n\n            // arr_each on the inner array (json_obj_get → JArr)\n            : ?Json y ( json_obj_get j `y` )\n            ?? y {\n                T jy → {\n                    ( nurl_print `y_each=` )\n                    : ( @ v Json ) p \\ Json e → v {\n                        ( nurl_print ( json_type_name e ) )\n                        ( nurl_print `,` )\n                    }\n                    ( json_arr_each jy p )\n                    ( nurl_print `\\n` )\n                }\n                F → ( nurl_print `y missing\\n` )\n            }\n\n            // obj_each on the outer object — prints \"key=type;\" per pair\n            ( nurl_print `obj_each=` )\n            : ( @ v s Json ) print_pair \\ s k Json v → v {\n                ( nurl_print k )\n                ( nurl_print `=` )\n                ( nurl_print ( json_type_name v ) )\n                ( nurl_print `;` )\n            }\n            ( json_obj_each j print_pair )\n            ( nurl_print `\\n` )\n\n            ( string_free pp )\n            ( json_free j )\n        }\n        F e → ( show_err `pretty parse err: ` # JsonError e )\n    }\n\n    // 12. pretty edge: empty array + empty object collapse\n    : !Json JsonError rp2 ( json_parse `{\"a\":[],\"b\":{}}` )\n    ?? rp2 {\n        T j → {\n            : String p ( json_pretty j )\n            ( nurl_print `empty_pretty:\\n` )\n            ( nurl_print ( string_data p ) )\n            ( nurl_print `\\n` )\n            ( string_free p )\n            ( json_free j )\n        }\n        F e → ( show_err `empty pretty err: ` # JsonError e )\n    }\n\n    // 13. Programmatic build via constructors + mutators\n    : Json built ( json_obj_new )\n    ( json_obj_set built `id` ( json_int 7 ) )\n    ( json_obj_set built `score` ( json_float 0.95 ) )\n    ( json_obj_set built `tag` ( json_str_lit `alpha` ) )\n    : Json items ( json_arr_new )\n    ( json_arr_push items ( json_int 10 ) )\n    ( json_arr_push items ( json_int 20 ) )\n    ( json_arr_push items ( json_int 30 ) )\n    ( json_obj_set built `items` items )\n    : String built_s ( json_stringify built )\n    ( nurl_print `built=` )\n    ( nurl_print ( string_data built_s ) )\n    ( nurl_print `\\n` )\n\n    // 14. json_get path access\n    : ?Json id ( json_get built `id` )\n    ?? id {\n        T jv → {\n            : ?i ai ( json_num_as_i jv )\n            ?? ai { T n → { ( nurl_print `id=` )\n                    ( nurl_print ( nurl_str_int n ) )\n                    ( nurl_print `\\n` ) }\n                F → ( nurl_print `id missing\\n` ) }\n        }\n        F → ( nurl_print `id missing\\n` )\n    }\n\n    : ?Json second ( json_get built `items.1` )\n    ?? second {\n        T jv → {\n            : ?i ai ( json_num_as_i jv )\n            ?? ai { T n → { ( nurl_print `items.1=` )\n                    ( nurl_print ( nurl_str_int n ) )\n                    ( nurl_print `\\n` ) }\n                F → ( nurl_print `items.1 missing\\n` ) }\n        }\n        F → ( nurl_print `items.1 missing\\n` )\n    }\n\n    : ?Json miss ( json_get built `items.99` )\n    ?? miss {\n        T _ → ( nurl_print `oob unexpected\\n` )\n        F → ( nurl_print `items.99=none\\n` )\n    }\n\n    // 15. json_obj_set replaces existing key (frees old value)\n    ( json_obj_set built `id` ( json_int 999 ) )\n    : ?Json id2 ( json_get built `id` )\n    ?? id2 {\n        T jv → {\n            : ?i ai ( json_num_as_i jv )\n            ?? ai { T n → { ( nurl_print `id_after=` )\n                    ( nurl_print ( nurl_str_int n ) )\n                    ( nurl_print `\\n` ) }\n                F → {} }\n        }\n        F → {}\n    }\n\n    // 16. json_clone produces an independent tree (mutation of clone\n    //     doesn't affect original)\n    : Json dup ( json_clone built )\n    ( json_obj_set dup `id` ( json_int -1 ) )\n    ( nurl_print `eq_after_clone=` )\n    ( nurl_print ? ( json_eq built dup ) `T` `F` )\n    ( nurl_print `\\n` )\n\n    : ?Json orig_id ( json_get built `id` )\n    ?? orig_id {\n        T jv → {\n            : ?i ai ( json_num_as_i jv )\n            ?? ai { T n → { ( nurl_print `orig_id=` )\n                    ( nurl_print ( nurl_str_int n ) )\n                    ( nurl_print `\\n` ) }\n                F → {} }\n        }\n        F → {}\n    }\n\n    // 17. json_eq round-trip on a parsed object\n    : !Json JsonError e1 ( json_parse `{\"x\":1,\"y\":2}` )\n    : !Json JsonError e2 ( json_parse `{\"x\":1,\"y\":2}` )\n    : !Json JsonError e3 ( json_parse `{\"x\":1,\"y\":3}` )\n    ?? e1 { T j1 → {\n            ?? e2 { T j2 → {\n                    ?? e3 { T j3 → {\n                            ( nurl_print `eq_same=` )\n                            ( nurl_print ? ( json_eq j1 j2 ) `T` `F` )\n                            ( nurl_print ` eq_diff=` )\n                            ( nurl_print ? ( json_eq j1 j3 ) `T` `F` )\n                            ( nurl_print `\\n` )\n                            ( json_free j3 )\n                        } F _ → {} }\n                    ( json_free j2 )\n                } F _ → {} }\n            ( json_free j1 )\n        } F _ → {} }\n\n    ( json_free dup )\n    ( string_free built_s )\n    ( json_free built )\n\n    ^ 0\n}\n","bytes":12815}