Skip to content

Commit a8937cc

Browse files
committed
Merge pull request #415 from bloomberg/continue_ppx_obj
2 parents 3758f13 + 90ca7b7 commit a8937cc

File tree

8 files changed

+159
-76
lines changed

8 files changed

+159
-76
lines changed

jscomp/ppx_entry.ml

Lines changed: 80 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ let curry_type_id () =
8686

8787
let ignore_id = Longident.Ldot (Lident "Pervasives", "ignore")
8888

89-
89+
let arrow = Ast_helper.Typ.arrow
9090

9191
(* note we first declare its type is [unit],
9292
then [ignore] it, [ignore] is necessary since
@@ -150,6 +150,8 @@ let create_local_external loc
150150
pexp_loc = loc
151151
})
152152

153+
let record_as_js_object = ref None (* otherwise has an attribute *)
154+
let obj_type_as_js_obj_type = ref false
153155
let handle_record_as_js_object
154156
loc
155157
attr
@@ -166,11 +168,6 @@ let handle_record_as_js_object
166168
let pval_attributes = [attr] in
167169
let local_module_name = "Tmp" in
168170
let local_fun_name = "run" in
169-
let arrow label a b =
170-
{Parsetree.ptyp_desc = Ptyp_arrow (label, a, b);
171-
ptyp_attributes = [];
172-
ptyp_loc = loc} in
173-
174171
let pval_type =
175172
let arity = List.length labels in
176173
let tyvars = (Ext_list.init arity (fun i ->
@@ -190,7 +187,7 @@ let handle_record_as_js_object
190187
ptyp_attributes = []
191188
} in
192189
List.fold_right2
193-
(fun label tyvar acc -> arrow label tyvar acc) labels tyvars result_type
190+
(fun label tyvar acc -> arrow ~loc label tyvar acc) labels tyvars result_type
194191
in
195192
create_local_external loc
196193
~pval_prim
@@ -225,14 +222,9 @@ let gen_fn_run loc arity args : Parsetree.expression_desc =
225222
ptyp_loc = loc }]);
226223
ptyp_attributes;
227224
ptyp_loc = loc} in
228-
let arrow a b =
229-
{ptyp_desc =
230-
Ptyp_arrow ("", a, b);
231-
ptyp_attributes ;
232-
ptyp_loc = loc} in
233225
(** could be optimized *)
234226
let pval_type =
235-
Ext_list.reduce_from_right arrow (uncurry_fn :: tyvars) in
227+
Ext_list.reduce_from_right (fun a b -> arrow ~loc "" a b) (uncurry_fn :: tyvars) in
236228
create_local_external loc ~pval_prim ~pval_type ~pval_attributes:[]
237229
local_module_name local_fun_name args
238230

@@ -262,15 +254,11 @@ let gen_fn_mk loc arity args : Parsetree.expression_desc =
262254
ptyp_loc = loc }]);
263255
ptyp_attributes;
264256
ptyp_loc = loc} in
265-
let arrow a b =
266-
{ptyp_desc =
267-
Ptyp_arrow ("", a, b);
268-
ptyp_attributes ;
269-
ptyp_loc = loc} in
257+
let arrow = arrow ~loc "" in
270258
(** could be optimized *)
271259
let pval_type =
272260
if arity = 0 then
273-
arrow (arrow predef_unit_type (List.hd tyvars) ) uncurry_fn
261+
arrow (arrow predef_unit_type (List.hd tyvars) ) uncurry_fn
274262
else
275263
arrow (Ext_list.reduce_from_right arrow tyvars) uncurry_fn in
276264
create_local_external loc ~pval_prim ~pval_type ~pval_attributes:[]
@@ -280,16 +268,13 @@ let gen_fn_mk loc arity args : Parsetree.expression_desc =
280268

281269

282270
let handle_raw loc e =
283-
Ast_helper.Exp.letmodule
284-
{txt = tmp_module_name; loc }
285-
(Ast_helper.Mod.structure [
286-
Ast_helper.Str.primitive
287-
(Ast_helper.Val.mk {loc ; txt = tmp_fn}
288-
~prim:[prim]
289-
(Ast_helper.Typ.arrow "" predef_string_type predef_any_type))])
290-
(Ast_helper.Exp.apply
291-
(Ast_helper.Exp.ident {txt= Ldot(Lident tmp_module_name, tmp_fn) ; loc})
292-
[("",e)])
271+
create_local_external loc
272+
~pval_prim:prim
273+
~pval_type:(arrow "" predef_string_type predef_any_type)
274+
~pval_attributes:[]
275+
tmp_module_name
276+
tmp_fn
277+
[("",e)]
293278

294279

295280

@@ -369,25 +354,48 @@ let handle_typ
369354
ptyp_attributes ;
370355
ptyp_loc = loc
371356
} ->
372-
let methods = List.map (fun (label, ptyp_attrs, core_type ) ->
373-
match find_uncurry_attrs_and_remove ptyp_attrs with
374-
| None, _ -> label, ptyp_attrs , self.typ self core_type
375-
| Some v, ptyp_attrs ->
376-
label , ptyp_attrs, self.typ self
377-
{ core_type with ptyp_attributes = v :: core_type.ptyp_attributes}
378-
) methods in
379357
begin match Ext_list.exclude_with_fact (function
380358
| {Location.txt = "bs.obj" ; _}, _ -> true
381359
| _ -> false ) ptyp_attributes with
382-
| None, _ ->
383-
{ty with ptyp_desc = Ptyp_object (methods, closed_flag)}
384360
| Some _, ptyp_attributes ->
361+
let methods =
362+
Ext_ref.protect obj_type_as_js_obj_type true begin fun _ ->
363+
List.map (fun (label, ptyp_attrs, core_type ) ->
364+
match find_uncurry_attrs_and_remove ptyp_attrs with
365+
| None, _ -> label, ptyp_attrs , self.typ self core_type
366+
| Some v, ptyp_attrs ->
367+
label , ptyp_attrs, self.typ self
368+
{ core_type with ptyp_attributes = v :: core_type.ptyp_attributes}
369+
) methods
370+
end
371+
in
372+
385373
{ptyp_desc =
386374
Ptyp_constr ({ txt = js_obj_type_id () ; loc},
387375
[{ ty with ptyp_desc = Ptyp_object(methods, closed_flag);
388376
ptyp_attributes }]);
389377
ptyp_attributes = [];
390378
ptyp_loc = loc }
379+
| None, _ ->
380+
let methods =
381+
List.map (fun (label, ptyp_attrs, core_type ) ->
382+
match find_uncurry_attrs_and_remove ptyp_attrs with
383+
| None, _ -> label, ptyp_attrs , self.typ self core_type
384+
| Some v, ptyp_attrs ->
385+
label , ptyp_attrs, self.typ self
386+
{ core_type with ptyp_attributes = v :: core_type.ptyp_attributes}
387+
) methods
388+
in
389+
if !obj_type_as_js_obj_type then
390+
{ptyp_desc =
391+
Ptyp_constr ({ txt = js_obj_type_id () ; loc},
392+
[{ ty with ptyp_desc = Ptyp_object(methods, closed_flag);
393+
ptyp_attributes }]);
394+
ptyp_attributes = [];
395+
ptyp_loc = loc }
396+
else
397+
{ty with ptyp_desc = Ptyp_object (methods, closed_flag)}
398+
391399
end
392400
| _ -> super.typ self ty
393401

@@ -413,18 +421,13 @@ let handle_debugger loc payload =
413421
match payload with
414422
| Parsetree.PStr ( [])
415423
->
416-
Ast_helper.Exp.letmodule
417-
{txt = tmp_module_name; loc }
418-
(Ast_helper.Mod.structure [
419-
Ast_helper.Str.primitive
420-
(Ast_helper.Val.mk {loc ; txt = tmp_fn}
421-
~prim:[prim_debugger]
422-
(Ast_helper.Typ.arrow "" predef_unit_type predef_unit_type)
423-
)])
424-
(Ast_helper.Exp.apply
425-
(Ast_helper.Exp.ident
426-
{txt= Ldot(Lident tmp_module_name, tmp_fn) ; loc})
427-
[("", predef_val_unit)])
424+
create_local_external loc
425+
~pval_prim:prim_debugger
426+
~pval_type:(arrow "" predef_unit_type predef_unit_type)
427+
~pval_attributes:[]
428+
tmp_module_name
429+
tmp_fn
430+
[("", predef_val_unit)]
428431
| Parsetree.PTyp _
429432
| Parsetree.PPat (_,_)
430433
| Parsetree.PStr _
@@ -644,7 +647,7 @@ let rec unsafe_mapper : Ast_mapper.mapper =
644647
} as e ,
645648
_); pstr_loc = _ }]))
646649
->
647-
handle_raw loc e
650+
{e with pexp_desc = handle_raw loc e }
648651
| Pexp_extension({txt = "bs.raw"; loc}, (PTyp _ | PPat _ | PStr _))
649652
->
650653
Location.raise_errorf ~loc "bs.raw can only be applied to a string"
@@ -653,7 +656,7 @@ let rec unsafe_mapper : Ast_mapper.mapper =
653656

654657
(** Begin rewriting [bs.debugger], its output should not be rewritten any more*)
655658
| Pexp_extension ({txt = "bs.debugger"; loc} , payload)
656-
-> handle_debugger loc payload
659+
-> {e with pexp_desc = handle_debugger loc payload}
657660
(** End rewriting *)
658661
| Pexp_fun ("", None, pat , body)
659662
->
@@ -730,12 +733,22 @@ let rec unsafe_mapper : Ast_mapper.mapper =
730733
e.pexp_attributes
731734
with
732735
| Some attr, pexp_attributes ->
733-
{ e with
734-
pexp_desc = handle_record_as_js_object e.pexp_loc attr label_exprs mapper;
735-
pexp_attributes
736-
}
736+
Ext_ref.protect record_as_js_object (Some attr) begin fun () ->
737+
{ e with
738+
pexp_desc = handle_record_as_js_object e.pexp_loc attr label_exprs mapper;
739+
pexp_attributes
740+
}
741+
end
737742
| None , _ ->
738-
Ast_mapper.default_mapper.expr mapper e
743+
begin match !record_as_js_object with
744+
| Some attr
745+
->
746+
{ e with
747+
pexp_desc = handle_record_as_js_object e.pexp_loc attr label_exprs mapper;
748+
}
749+
| None ->
750+
Ast_mapper.default_mapper.expr mapper e
751+
end
739752
end
740753
| _ -> Ast_mapper.default_mapper.expr mapper e
741754
);
@@ -751,19 +764,16 @@ let rec unsafe_mapper : Ast_mapper.mapper =
751764
pexp_desc = Pexp_constant (Const_string (cont, opt_label)) ;
752765
pexp_loc; pexp_attributes } as e ,_); pstr_loc }])
753766
->
754-
Ast_helper.Str.eval @@
755-
Ast_helper.Exp.letmodule
756-
{txt = tmp_module_name; loc }
757-
(Ast_helper.Mod.structure [
758-
Ast_helper.Str.primitive
759-
(Ast_helper.Val.mk {loc ; txt = tmp_fn}
760-
~prim:[prim_stmt]
761-
(Ast_helper.Typ.arrow ""
762-
predef_string_type predef_any_type))])
763-
(Ast_helper.Exp.apply
764-
(Ast_helper.Exp.ident
765-
{txt= Ldot(Lident tmp_module_name, tmp_fn) ; loc})
766-
[("",e)])
767+
Ast_helper.Str.eval
768+
{ e with pexp_desc =
769+
create_local_external loc
770+
~pval_prim:prim_stmt
771+
~pval_type:(arrow ""
772+
predef_string_type predef_any_type)
773+
~pval_attributes:[]
774+
tmp_module_name
775+
tmp_fn
776+
[("",e)]}
767777
| Parsetree.PTyp _
768778
| Parsetree.PPat (_,_)
769779
| Parsetree.PStr _

jscomp/test/.depend

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,10 @@ mt.cmj : ../stdlib/list.cmi mt.cmi
333333
mt.cmx : ../stdlib/list.cmx mt.cmi
334334
mt_global.cmj : mt.cmi mt_global.cmi
335335
mt_global.cmx : mt.cmx mt_global.cmi
336+
nested_obj_literal.cmj :
337+
nested_obj_literal.cmx :
338+
nested_obj_test.cmj :
339+
nested_obj_test.cmx :
336340
number_lexer.cmj : ../stdlib/sys.cmi ../stdlib/lexing.cmi
337341
number_lexer.cmx : ../stdlib/sys.cmx ../stdlib/lexing.cmx
338342
obj_literal_ppx.cmj : ../stdlib/array.cmi
@@ -987,6 +991,10 @@ mt.cmo : ../stdlib/list.cmi mt.cmi
987991
mt.cmj : ../stdlib/list.cmj mt.cmi
988992
mt_global.cmo : mt.cmi mt_global.cmi
989993
mt_global.cmj : mt.cmj mt_global.cmi
994+
nested_obj_literal.cmo :
995+
nested_obj_literal.cmj :
996+
nested_obj_test.cmo :
997+
nested_obj_test.cmj :
990998
number_lexer.cmo : ../stdlib/sys.cmi ../stdlib/lexing.cmi
991999
number_lexer.cmj : ../stdlib/sys.cmj ../stdlib/lexing.cmj
9921000
obj_literal_ppx.cmo : ../stdlib/array.cmi

jscomp/test/demo.ml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ class type grid =
8484
object [@uncurry]
8585
inherit widget
8686
inherit measure
87-
method columns__set : <width : int; .. > Js.t array -> unit
87+
method columns__set : (<width : int; .. > [@bs.obj]) array -> unit
8888
method titleRows__set :
89-
<label : <text : string; .. > Js.t ; ..> Js.t array -> unit
89+
(<label : <text : string; .. > ; ..> [@bs.obj]) array -> unit
9090
method dataSource__set :
91-
<label : <text : string; .. > Js.t ; ..> Js.t array array -> unit
91+
(<label : <text : string; .. > ; ..> [@bs.obj]) array array -> unit
9292
end
9393

9494
external set_interval : (unit -> unit [@uncurry]) -> float -> unit = "setInterval"
@@ -186,8 +186,10 @@ let ui_layout
186186
stackPanel##addChild grid;
187187
stackPanel##addChild inputCode;
188188
stackPanel##addChild button;
189-
190-
let mk_titleRow text = {label = {text } [@bs.obj] }[@bs.obj] in
189+
(* {label = {text } [@bs.obj] }[@bs.obj]
190+
should also work
191+
*)
192+
let mk_titleRow text = {label = {text } }[@bs.obj] in
191193
let u = {width = 200} [@bs.obj] in
192194
grid##minHeight__set 300;
193195
grid##titleRows__set

jscomp/test/nested_obj_literal.ml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
3+
let structural_obj = { x = { y = { z = 3 }}} [@bs.obj]
4+
(* compiler inferred type :
5+
val structural_obj : < x : < y : < z : int > > > [@bs.obj] *)
6+
7+
type 'a x = {x : 'a }
8+
type 'a y = {y : 'a}
9+
type 'a z = { z : 'a}
10+
let f_record = { x = { y = { z = 3 }}}
11+
(* compiler inferred type :
12+
val f_record : int z y x *)
13+

jscomp/test/nested_obj_test.ml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
3+
type f_obj = < x : < y : < z : int > > > [@bs.obj]
4+
let f : f_obj = { x = { y = { z = 3 }}} [@bs.obj]
5+
6+
type 'a x = {x : 'a }
7+
type 'a y = {y : 'a}
8+
type 'a z = { z : 'a}
9+
let f_record = { x = { y = { z = 3 }}}
10+
11+
12+
let f : f_obj = { x = { y = ({ z = 3 }[@bs.obj]) }} [@bs.obj]
13+

jscomp/test/test.mllib

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,7 @@ gpr_405_test
310310

311311
attr_test
312312

313-
uncurry_glob_test
313+
uncurry_glob_test
314+
315+
nested_obj_test
316+
nested_obj_literal

lib/js/test/nested_obj_literal.js

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

lib/js/test/nested_obj_test.js

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

0 commit comments

Comments
 (0)