Skip to content

Commit 2df9e99

Browse files
vouillonOlivierNicole
authored andcommitted
Runtime: implement Json.output
1 parent 3204c33 commit 2df9e99

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

lib/js_of_ocaml/js_of_ocaml_stubs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ void caml_bytes_of_array () {
44
caml_fatal_error("Unimplemented Javascript primitive caml_bytes_of_array!");
55
}
66

7+
void caml_custom_identifier () {
8+
caml_fatal_error("Unimplemented Javascript primitive caml_custom_identifier!");
9+
}
10+
711
void caml_js_error_of_exception () {
812
caml_fatal_error("Unimplemented Javascript primitive caml_js_error_of_exception!");
913
}

lib/js_of_ocaml/json.ml

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,88 @@
2020
open Js
2121
open! Import
2222

23+
(****)
24+
25+
let write_string buffer s =
26+
Buffer.add_char buffer '\"';
27+
for i = 0 to String.length s - 1 do
28+
match s.[i] with
29+
| '\"' -> Buffer.add_string buffer "\\\""
30+
| '\\' -> Buffer.add_string buffer "\\\\"
31+
| '\b' -> Buffer.add_string buffer "\\b"
32+
| '\x0C' -> Buffer.add_string buffer "\\f"
33+
| '\n' -> Buffer.add_string buffer "\\n"
34+
| '\r' -> Buffer.add_string buffer "\\r"
35+
| '\t' -> Buffer.add_string buffer "\\t"
36+
| c when Poly.(c <= '\x1F') ->
37+
(* Other control characters are escaped. *)
38+
Printf.bprintf buffer "\\u%04X" (int_of_char c)
39+
| c when Poly.(c < '\x80') -> Buffer.add_char buffer s.[i]
40+
| _c (* >= '\x80' *) ->
41+
(* Bytes greater than 127 are embedded in a UTF-8 sequence. *)
42+
Buffer.add_char buffer (Char.chr (0xC2 lor (Char.code s.[i] lsr 6)));
43+
Buffer.add_char buffer (Char.chr (0x80 lor (Char.code s.[i] land 0x3F)))
44+
done;
45+
Buffer.add_char buffer '\"'
46+
47+
let write_float buffer f =
48+
(* "%.15g" can be (much) shorter; "%.17g" is round-trippable *)
49+
let s = Printf.sprintf "%.15g" f in
50+
if Poly.(float_of_string s = f)
51+
then Buffer.add_string buffer s
52+
else Printf.bprintf buffer "%.17g" f
53+
54+
external custom_identifier : Obj.t -> string = "caml_custom_identifier"
55+
56+
let rec write b v =
57+
if Obj.is_int v
58+
then Printf.bprintf b "%d" (Obj.obj v : int)
59+
else
60+
let t = Obj.tag v in
61+
if t <= Obj.last_non_constant_constructor_tag
62+
then (
63+
Printf.bprintf b "[%d" t;
64+
for i = 0 to Obj.size v - 1 do
65+
Buffer.add_char b ',';
66+
write b (Obj.field v i)
67+
done;
68+
Buffer.add_char b ']')
69+
else if t = Obj.string_tag
70+
then write_string b (Obj.obj v : string)
71+
else if t = Obj.double_tag
72+
then write_float b (Obj.obj v : float)
73+
else if t = Obj.double_array_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_float b (Obj.double_field v i)
79+
done;
80+
Buffer.add_char b ']')
81+
else if t = Obj.custom_tag
82+
then
83+
match custom_identifier v with
84+
| "_i" -> Printf.bprintf b "%ld" (Obj.obj v : int32)
85+
| "_j" ->
86+
let i : int64 = Obj.obj v in
87+
let mask16 = Int64.of_int 0xffff in
88+
let mask24 = Int64.of_int 0xffffff in
89+
Printf.bprintf
90+
b
91+
"[255,%Ld,%Ld,%Ld]"
92+
(Int64.logand i mask24)
93+
(Int64.logand (Int64.shift_right i 24) mask24)
94+
(Int64.logand (Int64.shift_right i 48) mask16)
95+
| id -> failwith (Printf.sprintf "Json.output: unsupported custom value %s " id)
96+
else failwith (Printf.sprintf "Json.output: unsupported tag %d " t)
97+
98+
let to_json v =
99+
let buf = Buffer.create 50 in
100+
write buf v;
101+
Buffer.contents buf
102+
103+
(****)
104+
23105
class type json = object
24106
method parse : 'a. js_string t -> 'a meth
25107

@@ -51,13 +133,18 @@ let input_reviver =
51133
in
52134
wrap_meth_callback reviver
53135

54-
let unsafe_input s = json##parse_ s input_reviver
136+
let unsafe_input s =
137+
match Sys.backend_type with
138+
| Other "wasm_of_ocaml" -> failwith "Json.unsafe_input: not implemented"
139+
| _ -> json##parse_ s input_reviver
55140

56141
class type obj = object
57142
method constructor : 'a. 'a constr Js.readonly_prop
58143
end
59144

60145
let mlInt64_constr =
146+
Js.Unsafe.pure_expr
147+
@@ fun () ->
61148
let dummy_int64 = 1L in
62149
let dummy_obj : obj t = Obj.magic dummy_int64 in
63150
dummy_obj##.constructor
@@ -71,4 +158,7 @@ let output_reviver _key (value : Unsafe.any) : Obj.t =
71158
Obj.repr (array [| 255; value##.lo; value##.mi; value##.hi |])
72159
else Obj.repr value
73160

74-
let output obj = json##stringify_ obj (Js.wrap_callback output_reviver)
161+
let output obj =
162+
match Sys.backend_type with
163+
| Other "wasm_of_ocaml" -> Js.string (to_json (Obj.repr obj))
164+
| _ -> json##stringify_ obj (Js.wrap_callback output_reviver)

runtime/obj.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,9 @@ function caml_is_continuation_tag(t) {
214214
function caml_is_continuation_tag(t) {
215215
return (t == 245) ? 1 : 0;
216216
}
217+
218+
//Provides: caml_custom_identifier
219+
//Requires: caml_string_of_jsstring
220+
function caml_custom_identifier (o) {
221+
return caml_string_of_jsstring(o.custom_tag);
222+
}

0 commit comments

Comments
 (0)