Skip to content

Commit f91e558

Browse files
committed
Merge pull request #390 from bloomberg/obj_literal
[feature] extensible record with readable output
2 parents 9aa565f + 1a26292 commit f91e558

File tree

9 files changed

+207
-56
lines changed

9 files changed

+207
-56
lines changed

docs/book.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
3+
"plugins": ["[email protected]"],
4+
"pluginsConfig": {
5+
"edit-link": {
6+
"base": "https://github.com/bloomberg/bucklescript/tree/master/docs",
7+
"label": "Edit This Page"
8+
}
9+
}
10+
}

docs/build-doc.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/bin/sh
22
set -e
3-
node process.js
4-
cp -r dist/* $BUCKLESCRIPT_DOC
3+
# node process.js
4+
# gitbook build
5+
cp -r _book/* $BUCKLESCRIPT_DOC

jscomp/ppx_entry.ml

Lines changed: 101 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,89 @@ let discard_js_value loc e : Parsetree.expression =
9797
}
9898

9999

100+
let create_local_external loc
101+
~pval_prim
102+
~pval_type ~pval_attributes
103+
local_module_name
104+
local_fun_name
105+
args
106+
: Parsetree.expression_desc =
107+
Pexp_letmodule
108+
({txt = local_module_name; loc},
109+
{pmod_desc =
110+
Pmod_structure
111+
[{pstr_desc =
112+
Pstr_primitive
113+
{pval_name = {txt = local_fun_name; loc};
114+
pval_type ;
115+
pval_loc = loc;
116+
pval_prim = [pval_prim];
117+
pval_attributes };
118+
pstr_loc = loc;
119+
}];
120+
pmod_loc = loc;
121+
pmod_attributes = []},
122+
{
123+
pexp_desc =
124+
Pexp_apply
125+
(({pexp_desc = Pexp_ident {txt = Ldot (Lident local_module_name, local_fun_name);
126+
loc};
127+
pexp_attributes = [] ;
128+
pexp_loc = loc} : Parsetree.expression),
129+
args);
130+
pexp_attributes = [];
131+
pexp_loc = loc
132+
})
133+
134+
let handle_record_as_js_object
135+
loc
136+
attr
137+
(label_exprs : (Longident.t Asttypes.loc * Parsetree.expression) list)
138+
(mapper : Ast_mapper.mapper) : Parsetree.expression_desc =
139+
let labels, args =
140+
Ext_list.split_map (fun ({Location.txt ; loc}, e) ->
141+
match txt with
142+
| Longident.Lident x -> (x, (x, mapper.expr mapper e))
143+
| Ldot _ | Lapply _ ->
144+
Location.raise_errorf ~loc "invalid js label "
145+
) label_exprs in
146+
let pval_prim = "" in
147+
let pval_attributes = [attr] in
148+
let local_module_name = "Tmp" in
149+
let local_fun_name = "run" in
150+
let arrow label a b =
151+
{Parsetree.ptyp_desc = Ptyp_arrow (label, a, b);
152+
ptyp_attributes = [];
153+
ptyp_loc = loc} in
154+
155+
let pval_type =
156+
let arity = List.length labels in
157+
let tyvars = (Ext_list.init arity (fun i ->
158+
{Parsetree.ptyp_desc = Ptyp_var ("a" ^ string_of_int i);
159+
ptyp_attributes = [] ;
160+
ptyp_loc = loc})) in
161+
162+
let result_type =
163+
{Parsetree.ptyp_desc =
164+
Ptyp_constr ({txt = Ldot(Lident "Js", "t"); loc},
165+
[{ Parsetree.ptyp_desc =
166+
Ptyp_object (List.map2 (fun x y -> x ,[], y) labels tyvars, Closed);
167+
ptyp_attributes = [];
168+
ptyp_loc = loc
169+
}]);
170+
ptyp_loc = loc;
171+
ptyp_attributes = []
172+
} in
173+
List.fold_right2
174+
(fun label tyvar acc -> arrow label tyvar acc) labels tyvars result_type
175+
in
176+
create_local_external loc
177+
~pval_prim
178+
~pval_type ~pval_attributes
179+
local_module_name
180+
local_fun_name
181+
args
182+
100183
let gen_fn_run loc arity args : Parsetree.expression_desc =
101184
let open Parsetree in
102185
let ptyp_attributes = [] in
@@ -131,32 +214,8 @@ let gen_fn_run loc arity args : Parsetree.expression_desc =
131214
(** could be optimized *)
132215
let pval_type =
133216
Ext_list.reduce_from_right arrow (uncurry_fn :: tyvars) in
134-
Pexp_letmodule
135-
({txt = local_module_name; loc},
136-
{pmod_desc =
137-
Pmod_structure
138-
[{pstr_desc =
139-
Pstr_primitive
140-
{pval_name = {txt = local_fun_name; loc};
141-
pval_type ;
142-
pval_loc = loc;
143-
pval_prim = [pval_prim];
144-
pval_attributes = []};
145-
pstr_loc = loc;
146-
}];
147-
pmod_loc = loc;
148-
pmod_attributes = []},
149-
{
150-
pexp_desc =
151-
Pexp_apply
152-
(({pexp_desc = Pexp_ident {txt = Ldot (Lident local_module_name, local_fun_name);
153-
loc};
154-
pexp_attributes = [] ;
155-
pexp_loc = loc} : Parsetree.expression),
156-
args);
157-
pexp_attributes = [];
158-
pexp_loc = loc
159-
})
217+
create_local_external loc ~pval_prim ~pval_type ~pval_attributes:[]
218+
local_module_name local_fun_name args
160219

161220
let gen_fn_mk loc arity args : Parsetree.expression_desc =
162221
let open Parsetree in
@@ -195,33 +254,8 @@ let gen_fn_mk loc arity args : Parsetree.expression_desc =
195254
arrow (arrow predef_unit_type (List.hd tyvars) ) uncurry_fn
196255
else
197256
arrow (Ext_list.reduce_from_right arrow tyvars) uncurry_fn in
198-
199-
Pexp_letmodule
200-
({txt = local_module_name; loc},
201-
{pmod_desc =
202-
Pmod_structure
203-
[{pstr_desc =
204-
Pstr_primitive
205-
{pval_name = {txt = local_fun_name; loc};
206-
pval_type ;
207-
pval_loc = loc;
208-
pval_prim = [pval_prim];
209-
pval_attributes = []};
210-
pstr_loc = loc;
211-
}];
212-
pmod_loc = loc;
213-
pmod_attributes = []},
214-
{
215-
pexp_desc =
216-
Pexp_apply
217-
(({pexp_desc = Pexp_ident {txt = Ldot (Lident local_module_name, local_fun_name);
218-
loc};
219-
pexp_attributes = [] ;
220-
pexp_loc = loc} : Parsetree.expression),
221-
args);
222-
pexp_attributes = [];
223-
pexp_loc = loc
224-
})
257+
create_local_external loc ~pval_prim ~pval_type ~pval_attributes:[]
258+
local_module_name local_fun_name args
225259

226260

227261

@@ -623,7 +657,20 @@ let rec unsafe_mapper : Ast_mapper.mapper =
623657
) )
624658
])
625659
-> handle_obj_property loc obj name e mapper
626-
660+
| Pexp_record (label_exprs, None) ->
661+
begin match (* exclude {[ u with ..]} syntax currently *)
662+
Ext_list.exclude_with_fact
663+
(function({Location.txt = "bs.obj"}, _) -> true | _ -> false)
664+
e.pexp_attributes
665+
with
666+
| Some attr, pexp_attributes ->
667+
{ e with
668+
pexp_desc = handle_record_as_js_object e.pexp_loc attr label_exprs mapper;
669+
pexp_attributes
670+
}
671+
| None , _ ->
672+
Ast_mapper.default_mapper.expr mapper e
673+
end
627674
| _ -> Ast_mapper.default_mapper.expr mapper e
628675
);
629676
typ = (fun self typ -> handle_typ Ast_mapper.default_mapper self typ);

jscomp/test/.depend

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ mt_global.cmj : mt.cmi mt_global.cmi
330330
mt_global.cmx : mt.cmx mt_global.cmi
331331
number_lexer.cmj : ../stdlib/sys.cmi ../stdlib/lexing.cmi
332332
number_lexer.cmx : ../stdlib/sys.cmx ../stdlib/lexing.cmx
333+
obj_literal_ppx.cmj : ../stdlib/array.cmi
334+
obj_literal_ppx.cmx : ../stdlib/array.cmx
335+
obj_literal_ppx_test.cmj : ../runtime/js.cmj
336+
obj_literal_ppx_test.cmx : ../runtime/js.cmx
333337
obj_magic_test.cmj : ../stdlib/obj.cmi mt.cmi
334338
obj_magic_test.cmx : ../stdlib/obj.cmx mt.cmx
335339
obj_test.cmj : mt.cmi
@@ -974,6 +978,10 @@ mt_global.cmo : mt.cmi mt_global.cmi
974978
mt_global.cmj : mt.cmj mt_global.cmi
975979
number_lexer.cmo : ../stdlib/sys.cmi ../stdlib/lexing.cmi
976980
number_lexer.cmj : ../stdlib/sys.cmj ../stdlib/lexing.cmj
981+
obj_literal_ppx.cmo : ../stdlib/array.cmi
982+
obj_literal_ppx.cmj : ../stdlib/array.cmj
983+
obj_literal_ppx_test.cmo : ../runtime/js.cmo
984+
obj_literal_ppx_test.cmj : ../runtime/js.cmj
977985
obj_magic_test.cmo : ../stdlib/obj.cmi mt.cmi
978986
obj_magic_test.cmj : ../stdlib/obj.cmj mt.cmj
979987
obj_test.cmo : mt.cmi

jscomp/test/obj_literal_ppx.ml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
3+
let a = { x = 3 ; y = [| 1|]} [@bs.obj]
4+
5+
let b = { x = 3 ; y = [| 1 |]; z = 3; u = fun %uncurry (x,y) -> x + y } [@bs.obj]
6+
7+
let f obj =
8+
obj ## x + Array.length (obj ## y)
9+
10+
let h obj = obj##u (1,2)
11+
12+
let u = f a
13+
14+
let v = f b
15+
16+
let vv = h b
17+

jscomp/test/obj_literal_ppx_test.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
let a =
3+
let module N = struct
4+
external create : x : 'a0 -> y : 'a1 -> < x : 'a0 ; y : 'a1 > Js.t = ""[@@bs.obj]
5+
end in
6+
N.create ~x:3 ~y:[1;2;3]

jscomp/test/test.mllib

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,5 @@ ignore_test
304304

305305
test_index
306306

307+
obj_literal_ppx_test
308+
obj_literal_ppx

lib/js/test/obj_literal_ppx.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// GENERATED CODE BY BUCKLESCRIPT VERSION 0.4.2 , PLEASE EDIT WITH CARE
2+
'use strict';
3+
4+
5+
var a = {
6+
"x": 3,
7+
"y": /* int array */[1]
8+
};
9+
10+
var b = {
11+
"x": 3,
12+
"y": /* int array */[1],
13+
"z": 3,
14+
"u": function (x, y) {
15+
return x + y | 0;
16+
}
17+
};
18+
19+
function f(obj) {
20+
return obj.x + obj.y.length | 0;
21+
}
22+
23+
function h(obj) {
24+
return obj.u(1, 2);
25+
}
26+
27+
var u = f(a);
28+
29+
var v = f(b);
30+
31+
var vv = h(b);
32+
33+
exports.a = a;
34+
exports.b = b;
35+
exports.f = f;
36+
exports.h = h;
37+
exports.u = u;
38+
exports.v = v;
39+
exports.vv = vv;
40+
/* a Not a pure module */

lib/js/test/obj_literal_ppx_test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// GENERATED CODE BY BUCKLESCRIPT VERSION 0.4.2 , PLEASE EDIT WITH CARE
2+
'use strict';
3+
4+
5+
var a = {
6+
"x": 3,
7+
"y": /* :: */[
8+
1,
9+
/* :: */[
10+
2,
11+
/* :: */[
12+
3,
13+
/* [] */0
14+
]
15+
]
16+
]
17+
};
18+
19+
exports.a = a;
20+
/* a Not a pure module */

0 commit comments

Comments
 (0)