Skip to content

Commit 24188e5

Browse files
committed
Merge pull request #432 from bloomberg/ppx_global_config
[feature] prepare global default configuration
2 parents 9e1714c + 4592a6a commit 24188e5

File tree

11 files changed

+239
-46
lines changed

11 files changed

+239
-46
lines changed

jscomp/syntax/ast_payload.ml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ let as_empty_structure (x : t ) =
5353
| PStr ([]) -> true
5454
| PTyp _ | PPat _ | PStr (_ :: _ ) -> false
5555

56+
57+
let as_record_and_process
58+
loc
59+
( x : t ) (action : Longident.t Asttypes.loc * Parsetree.expression -> unit ): unit=
60+
match x with
61+
| PStr [ {pstr_desc = Pstr_eval
62+
({pexp_desc = Pexp_record (label_exprs, with_obj) ; pexp_loc = loc}, _);
63+
_
64+
}]
65+
->
66+
begin match with_obj with
67+
| None ->
68+
List.iter action label_exprs
69+
| Some _ ->
70+
Location.raise_errorf ~loc "with is not supported"
71+
end
72+
| _ ->
73+
Location.raise_errorf ~loc "this is not a valid record config"
74+
5675
let is_string_or_strings (x : t) :
5776
[ `None | `Single of string | `Some of string list ] =
5877
let module M = struct exception Not_str end in
@@ -83,3 +102,12 @@ let is_string_or_strings (x : t) :
83102
_},_);
84103
_}] -> `Single name
85104
| _ -> `None
105+
106+
let assert_bool_lit (e : Parsetree.expression) =
107+
match e.pexp_desc with
108+
| Pexp_construct ({txt = Lident "true" }, None)
109+
-> true
110+
| Pexp_construct ({txt = Lident "false" }, None)
111+
-> false
112+
| _ ->
113+
Location.raise_errorf ~loc:e.pexp_loc "expect `true` or `false` in this field"

jscomp/syntax/ast_payload.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ val as_string_exp : t -> Parsetree.expression option
3434
val as_empty_structure : t -> bool
3535
val is_string_or_strings :
3636
t -> [ `None | `Single of string | `Some of string list ]
37+
val as_record_and_process :
38+
Location.t ->
39+
t -> (Longident.t Asttypes.loc * Parsetree.expression -> unit) -> unit
40+
41+
val assert_bool_lit : Parsetree.expression -> bool

jscomp/syntax/ppx_entry.ml

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ let arrow = Ast_helper.Typ.arrow
7676

7777
let record_as_js_object = ref None (* otherwise has an attribute *)
7878
let obj_type_as_js_obj_type = ref false
79+
let uncurry_type = ref false
80+
let obj_type_auto_uncurry = ref false
81+
let non_export = ref false
82+
let lift_js_type ~loc x = Typ.constr ~loc {txt = js_obj_type_id (); loc} [x]
83+
let lift_curry_type ~loc x = Typ.constr ~loc {txt = curry_type_id (); loc} [x]
84+
7985
let handle_record_as_js_object
8086
loc
8187
attr
@@ -96,10 +102,9 @@ let handle_record_as_js_object
96102
Typ.var ~loc ("a" ^ string_of_int i))) in
97103

98104
let result_type =
99-
Typ.constr ~loc {txt = js_obj_type_id () ; loc}
100-
[
101-
Typ.object_ ~loc (List.map2 (fun x y -> x ,[], y) labels tyvars) Closed
102-
]
105+
lift_js_type ~loc
106+
@@ Typ.object_ ~loc (List.map2 (fun x y -> x ,[], y) labels tyvars) Closed
107+
103108
in
104109
List.fold_right2
105110
(fun label tyvar acc -> arrow ~loc label tyvar acc) labels tyvars result_type
@@ -126,8 +131,7 @@ let gen_fn_run loc arity args : Parsetree.expression_desc =
126131
Parsetree.Ptyp_tuple tyvars
127132
in
128133
let uncurry_fn =
129-
Typ.constr ~loc {txt = curry_type_id (); loc}
130-
[ Typ.mk ~loc tuple_type_desc] in
134+
lift_curry_type ~loc @@ Typ.mk ~loc tuple_type_desc in
131135
(** could be optimized *)
132136
let pval_type =
133137
Ext_list.reduce_from_right (fun a b -> arrow ~loc "" a b) (uncurry_fn :: tyvars) in
@@ -153,8 +157,7 @@ let gen_fn_mk loc arity args : Parsetree.expression_desc =
153157
Parsetree.Ptyp_tuple tyvars
154158
in
155159
let uncurry_fn =
156-
Typ.constr ~loc {txt = curry_type_id (); loc}
157-
[Typ.mk ~loc tuple_type_desc]
160+
lift_curry_type ~loc @@ Typ.mk ~loc tuple_type_desc
158161
in
159162
let arrow = arrow ~loc "" in
160163
(** could be optimized *)
@@ -163,10 +166,8 @@ let gen_fn_mk loc arity args : Parsetree.expression_desc =
163166
arrow (arrow (Ast_literal.type_unit ~loc ()) (List.hd tyvars) ) uncurry_fn
164167
else
165168
arrow (Ext_list.reduce_from_right arrow tyvars) uncurry_fn in
166-
let local_module_name = "Tmp" in
167-
let local_fun_name = "mk" in
168169
Ast_comb.create_local_external loc ~pval_prim ~pval_type
169-
~local_module_name ~local_fun_name args
170+
args
170171

171172

172173
let find_uncurry_attrs_and_remove (attrs : Parsetree.attributes ) =
@@ -192,10 +193,10 @@ let uncurry_fn_type loc ty attrs
192193
| v ->
193194
Typ.tuple ~loc ~attrs [v ; body]
194195
in
195-
Typ.constr ~loc {txt = curry_type_id () ; loc} [ fn_type]
196+
lift_curry_type ~loc fn_type
197+
196198

197199

198-
let uncurry_type = ref false
199200

200201
(*
201202
Attributes are very hard to attribute
@@ -239,27 +240,31 @@ let handle_typ
239240
| _ -> false)
240241
ptyp_attributes with
241242
| None, None, _ ->
243+
let check_auto_uncurry core_type =
244+
if !obj_type_auto_uncurry then
245+
Ext_ref.protect uncurry_type true (fun _ -> self.typ self core_type )
246+
else self.typ self core_type in
247+
242248
let methods =
243249
List.map (fun (label, ptyp_attrs, core_type ) ->
244250
match find_uncurry_attrs_and_remove ptyp_attrs with
245-
| None, _ -> label, ptyp_attrs , self.typ self core_type
251+
| None, _ ->
252+
label, ptyp_attrs , check_auto_uncurry core_type
246253
| Some v, ptyp_attrs ->
247-
label , ptyp_attrs, self.typ self
254+
label , ptyp_attrs,
255+
check_auto_uncurry
248256
{ core_type with ptyp_attributes = v :: core_type.ptyp_attributes}
249257
) methods
250258
in
251259
if !obj_type_as_js_obj_type then
252-
{ptyp_desc =
253-
Ptyp_constr ({ txt = js_obj_type_id () ; loc},
254-
[{ ty with ptyp_desc = Ptyp_object(methods, closed_flag);
255-
ptyp_attributes }]);
256-
ptyp_attributes = [];
257-
ptyp_loc = loc }
260+
lift_js_type ~loc { ty with ptyp_desc = Ptyp_object(methods, closed_flag);
261+
ptyp_attributes }
262+
258263
else
259264
{ty with ptyp_desc = Ptyp_object (methods, closed_flag)}
260265
| fact1 , fact2, ptyp_attributes ->
261266
let obj_type_as_js_obj_type_cxt = fact1 <> None || !obj_type_as_js_obj_type in
262-
let uncurry_type_cxt = fact2 <> None || !uncurry_type in
267+
let uncurry_type_cxt = fact2 <> None || !uncurry_type || !obj_type_auto_uncurry in
263268
let methods =
264269
Ext_ref.protect2
265270
obj_type_as_js_obj_type
@@ -287,7 +292,7 @@ let handle_typ
287292
end
288293
| _ -> super.typ self ty
289294

290-
let handle_ctyp
295+
let handle_class_obj_typ
291296
(super : Ast_mapper.mapper)
292297
(self : Ast_mapper.mapper)
293298
(ty : Parsetree.class_type) =
@@ -301,7 +306,13 @@ let handle_ctyp
301306
Ext_ref.protect uncurry_type true begin fun () ->
302307
self.class_type self {ty with pcty_attributes = pcty_attributes'}
303308
end
304-
| None, _ -> super.class_type self ty
309+
| None, _ ->
310+
if !obj_type_auto_uncurry then
311+
Ext_ref.protect uncurry_type true begin fun () ->
312+
super.class_type self ty
313+
end
314+
else
315+
super.class_type self ty
305316
end
306317

307318

@@ -374,13 +385,8 @@ let handle_obj_property loc obj name e
374385
~pval_prim:"js_unsafe_downgrade"
375386
~pval_type:(
376387
Ast_comb.arrow_no_label ~loc
377-
(Typ.constr ~loc
378-
{txt = js_obj_type_id () ; loc}
379-
[var])
380-
var)
381-
382-
~local_module_name:"Tmp"
383-
~local_fun_name:"cast" ["", obj] in
388+
(lift_js_type ~loc var) var)
389+
["", obj] in
384390
{ e with pexp_desc =
385391
Pexp_send
386392
({pexp_desc = down ;
@@ -429,20 +435,12 @@ let handle_obj_method loc (obj : Parsetree.expression)
429435
let down = Ast_comb.create_local_external loc
430436
~pval_prim:"js_unsafe_downgrade"
431437
~pval_type:(Ast_comb.arrow_no_label ~loc
432-
(Typ.constr ~loc {txt = js_obj_type_id () ; loc} [var])
438+
(lift_js_type ~loc var)
433439
var )
434440
~local_module_name:"Tmp"
435441
~local_fun_name:"cast" ["", obj] in
436442
{e with pexp_desc = gen_fn_run loc len
437-
(("",
438-
{pexp_desc =
439-
Pexp_send
440-
({pexp_desc = down ;
441-
pexp_loc = loc ;
442-
pexp_attributes = []},
443-
name);
444-
pexp_loc = loc ;
445-
pexp_attributes = [] }) ::
443+
(("", Exp.send ~loc (Exp.mk ~loc down) name) ::
446444
List.map (fun x -> "", x) args
447445
)}
448446
(** TODO:
@@ -610,7 +608,7 @@ let rec unsafe_mapper : Ast_mapper.mapper =
610608
| _ -> Ast_mapper.default_mapper.expr mapper e
611609
);
612610
typ = (fun self typ -> handle_typ Ast_mapper.default_mapper self typ);
613-
class_type = (fun self ctyp -> handle_ctyp Ast_mapper.default_mapper self ctyp);
611+
class_type = (fun self ctyp -> handle_class_obj_typ Ast_mapper.default_mapper self ctyp);
614612
structure_item = (fun mapper (str : Parsetree.structure_item) ->
615613
begin match str.pstr_desc with
616614
| Pstr_extension ( ({txt = "bs.raw"; loc}, payload), _attrs)
@@ -635,11 +633,70 @@ let rec unsafe_mapper : Ast_mapper.mapper =
635633
end
636634
)
637635
}
636+
637+
638+
let common_actions_table :
639+
(string * (Parsetree.expression -> unit)) list =
640+
[ "obj_type_auto_uncurry",
641+
(fun e ->
642+
obj_type_auto_uncurry := Ast_payload.assert_bool_lit e
643+
)
644+
]
645+
646+
647+
let structural_config_table =
648+
String_map.of_list
649+
(( "non_export" ,
650+
(fun e -> non_export := Ast_payload.assert_bool_lit e ))
651+
:: common_actions_table)
652+
653+
let signature_config_table =
654+
String_map.of_list common_actions_table
655+
656+
657+
let make_call_back table ((x : Longident.t Asttypes.loc) , y) =
658+
match x with
659+
| {txt = Lident name; loc } ->
660+
begin match String_map.find name table with
661+
| fn -> fn y
662+
| exception _ -> Location.raise_errorf ~loc "%s is not supported" name
663+
end
664+
| {loc} ->
665+
Location.raise_errorf ~loc "invalid label for config"
666+
638667
let rewrite_signature : (Parsetree.signature -> Parsetree.signature) ref =
639668
ref (fun x ->
640-
unsafe_mapper.signature unsafe_mapper x
669+
match (x : Parsetree.signature) with
670+
| {psig_desc = Psig_attribute ({txt = "bs.config"; loc}, payload); _} :: rest
671+
->
672+
begin
673+
Ast_payload.as_record_and_process loc payload
674+
(make_call_back signature_config_table) ;
675+
unsafe_mapper.signature unsafe_mapper rest
676+
end
677+
| _ ->
678+
unsafe_mapper.signature unsafe_mapper x
641679
)
642680

643681
let rewrite_implementation : (Parsetree.structure -> Parsetree.structure) ref =
644-
ref (fun x -> unsafe_mapper.structure unsafe_mapper x )
682+
ref (fun (x : Parsetree.structure) ->
683+
match x with
684+
| {pstr_desc = Pstr_attribute ({txt = "bs.config"; loc}, payload); _} :: rest
685+
->
686+
begin
687+
Ast_payload.as_record_and_process loc payload
688+
(make_call_back structural_config_table) ;
689+
let rest = unsafe_mapper.structure unsafe_mapper rest in
690+
if !non_export then
691+
[Str.include_ ~loc
692+
(Incl.mk ~loc
693+
(Mod.constraint_ ~loc
694+
(Mod.structure ~loc rest )
695+
(Mty.signature ~loc [])
696+
))]
697+
else rest
698+
699+
end
700+
| _ ->
701+
unsafe_mapper.structure unsafe_mapper x )
645702

jscomp/test/.depend

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ abstract_type.cmi :
33
ari_regress_test.cmi :
44
array_test.cmi :
55
basic_module_test.cmi :
6+
config2_test.cmi : ../runtime/js.cmj
67
const_block_test.cmi :
78
demo_int_map.cmi :
89
ext_pervasives.cmi : ../stdlib/int32.cmi ../stdlib/format.cmi
@@ -107,6 +108,10 @@ complex_test.cmj : mt.cmi ../stdlib/complex.cmi
107108
complex_test.cmx : mt.cmx ../stdlib/complex.cmx
108109
complex_while_loop.cmj :
109110
complex_while_loop.cmx :
111+
config1_test.cmj :
112+
config1_test.cmx :
113+
config2_test.cmj : ../runtime/js.cmj config2_test.cmi
114+
config2_test.cmx : ../runtime/js.cmx config2_test.cmi
110115
const_block_test.cmj : mt.cmi ../stdlib/array.cmi const_block_test.cmi
111116
const_block_test.cmx : mt.cmx ../stdlib/array.cmx const_block_test.cmi
112117
const_defs.cmj :
@@ -761,6 +766,10 @@ complex_test.cmo : mt.cmi ../stdlib/complex.cmi
761766
complex_test.cmj : mt.cmj ../stdlib/complex.cmj
762767
complex_while_loop.cmo :
763768
complex_while_loop.cmj :
769+
config1_test.cmo :
770+
config1_test.cmj :
771+
config2_test.cmo : ../runtime/js.cmo config2_test.cmi
772+
config2_test.cmj : ../runtime/js.cmj config2_test.cmi
764773
const_block_test.cmo : mt.cmi ../stdlib/array.cmi const_block_test.cmi
765774
const_block_test.cmj : mt.cmj ../stdlib/array.cmj const_block_test.cmi
766775
const_defs.cmo :

jscomp/test/config1_test.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
;;[@@@bs.config{
3+
obj_type_auto_uncurry = true;
4+
non_export = true;
5+
}]
6+
;;
7+
8+
9+
let a = 3

jscomp/test/config2_test.ml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[@@@bs.config{
2+
obj_type_auto_uncurry = true;
3+
(* non_export = true; *)
4+
}]
5+
6+
7+
8+
class type v = object [@uncurry]
9+
method hey : int * int -> int
10+
end
11+
12+
class type v2 = object
13+
method hey : int * int -> int
14+
end
15+
16+
type vv =
17+
<
18+
hey : int * int -> int
19+
> [@bs.obj] [@uncurry]
20+
21+
type vv2 =
22+
<
23+
hey : int * int -> int
24+
> [@bs.obj]
25+
26+
27+
let hh (x : v) : v2 = x
28+
29+
let hh2 ( x : vv) : vv2 = x
30+
31+
32+
let test_v (x : v Js.t) =
33+
x##hey(1,2)
34+
35+
let test_vv (h : vv) =
36+
h##hey(1,2)

0 commit comments

Comments
 (0)