2020open Js
2121open ! Import
2222
23+ (* ***)
24+
25+ (* The writing logic for basic types is copied from [lib/deriving_json]. *)
26+
27+ let write_string buffer s =
28+ Buffer. add_char buffer '"' ;
29+ for i = 0 to String. length s - 1 do
30+ match s.[i] with
31+ | '"' -> Buffer. add_string buffer {| \" |}
32+ | '\\ ' -> Buffer.add_string buffer {|\\ |}
33+ | '\b ' -> Buffer.add_string buffer {|\b |}
34+ | '\x0C ' -> Buffer.add_string buffer {|\f |}
35+ | '\n ' -> Buffer.add_string buffer {|\n |}
36+ | '\r ' -> Buffer.add_string buffer {|\r |}
37+ | '\t ' -> Buffer.add_string buffer {|\t |}
38+ | c when Poly.(c <= '\x1F ') ->
39+ (* Other control characters are escaped. *)
40+ Printf.bprintf buffer {|\u %04X|} (int_of_char c)
41+ | c when Poly.(c < '\x80 ') -> Buffer.add_char buffer s.[i]
42+ | _c (* >= '\x80 ' *) ->
43+ (* Bytes greater than 127 are embedded in a UTF-8 sequence. *)
44+ Buffer.add_char buffer (Char.chr (0xC2 lor (Char.code s.[i] lsr 6)));
45+ Buffer.add_char buffer (Char.chr (0x80 lor (Char.code s.[i] land 0x3F)))
46+ done;
47+ Buffer.add_char buffer '" '
48+
49+ let write_float buffer f =
50+ (* "%.15g" can be (much) shorter; "%.17g" is round-trippable *)
51+ let s = Printf. sprintf " %.15g" f in
52+ if Poly. (float_of_string s = f)
53+ then Buffer. add_string buffer s
54+ else Printf. bprintf buffer " %.17g" f
55+
56+ let write_int64 buffer i =
57+ let mask16 = Int64. of_int 0xffff in
58+ let mask24 = Int64. of_int 0xffffff in
59+ Printf. bprintf
60+ buffer
61+ " [255,%Ld,%Ld,%Ld]"
62+ (Int64. logand i mask24)
63+ (Int64. logand (Int64. shift_right i 24 ) mask24)
64+ (Int64. logand (Int64. shift_right i 48 ) mask16)
65+
66+ external custom_identifier : Obj .t -> string = " caml_custom_identifier"
67+
68+ let rec write b v =
69+ if Obj. is_int v
70+ then Printf. bprintf b " %d" (Obj. obj v : int )
71+ else
72+ let t = Obj. tag v in
73+ if t < = Obj. last_non_constant_constructor_tag
74+ then (
75+ Printf. bprintf b " [%d" t;
76+ for i = 0 to Obj. size v - 1 do
77+ Buffer. add_char b ',' ;
78+ write b (Obj. field v i)
79+ done ;
80+ Buffer. add_char b ']' )
81+ else if t = Obj. string_tag
82+ then write_string b (Obj. obj v : string )
83+ else if t = Obj. double_tag
84+ then write_float b (Obj. obj v : float )
85+ else if t = Obj. double_array_tag
86+ then (
87+ Printf. bprintf b " [%d" t;
88+ for i = 0 to Obj. size v - 1 do
89+ Buffer. add_char b ',' ;
90+ write_float b (Obj. double_field v i)
91+ done ;
92+ Buffer. add_char b ']' )
93+ else if t = Obj. custom_tag
94+ then
95+ match custom_identifier v with
96+ | "_i" -> Printf. bprintf b " %ld" (Obj. obj v : int32 )
97+ | "_j" ->
98+ let i : int64 = Obj. obj v in
99+ write_int64 b i
100+ | id -> failwith (Printf. sprintf " Json.output: unsupported custom value %s " id)
101+ else failwith (Printf. sprintf " Json.output: unsupported tag %d " t)
102+
103+ let to_json v =
104+ let buf = Buffer. create 50 in
105+ write buf v;
106+ Buffer. contents buf
107+
108+ (* ***)
109+
23110class type json = object
24111 method parse : 'a. js_string t -> 'a meth
25112
@@ -51,13 +138,22 @@ let input_reviver =
51138 in
52139 wrap_meth_callback reviver
53140
54- let unsafe_input s = json##parse_ s input_reviver
141+ let unsafe_input s =
142+ match Sys. backend_type with
143+ | Other "wasm_of_ocaml" ->
144+ (* https://github.com/ocsigen/js_of_ocaml/pull/1660#discussion_r1731099372
145+ The encoding of OCaml values is ambiguous since both integers and floats
146+ are mapped to numbers *)
147+ failwith " Json.unsafe_input: not implemented in the Wasm backend"
148+ | _ -> json##parse_ s input_reviver
55149
56150class type obj = object
57151 method constructor : 'a. 'a constr Js. readonly_prop
58152end
59153
60154let mlInt64_constr =
155+ Js.Unsafe. pure_expr
156+ @@ fun () ->
61157 let dummy_int64 = 1L in
62158 let dummy_obj : obj t = Obj. magic dummy_int64 in
63159 dummy_obj##.constructor
@@ -71,4 +167,20 @@ let output_reviver _key (value : Unsafe.any) : Obj.t =
71167 Obj. repr (array [| 255 ; value##.lo; value##.mi; value##.hi |])
72168 else Obj. repr value
73169
74- let output obj = json##stringify_ obj (Js. wrap_callback output_reviver)
170+ let use_native_stringify_ =
171+ ref
172+ (match Sys. backend_type with
173+ | Other "js_of_ocaml" -> true
174+ | Native | Bytecode | Other _ -> false )
175+
176+ let use_native_stringify () = ! use_native_stringify_
177+
178+ let set_use_native_stringify b = use_native_stringify_ := b
179+
180+ let output_ x = to_json (Obj. repr x)
181+
182+ let output obj =
183+ match Sys. backend_type with
184+ | Other "js_of_ocaml" when use_native_stringify () ->
185+ json##stringify_ obj (Js. wrap_callback output_reviver)
186+ | _ -> Js. string (output_ obj)
0 commit comments