Skip to content

Commit 30fb9a5

Browse files
committed
Merge pull request #416 from bloomberg/clean_up_uncurry_obj
done with object type protection
2 parents a8937cc + 90f7fd0 commit 30fb9a5

File tree

12 files changed

+209
-94
lines changed

12 files changed

+209
-94
lines changed

docs/Playground.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
There are two Playgrounds, one for
4+
[vanilla OCaml](https:////bloomberg.github.io/bucklescript/js-demo),
5+
the other for
6+
[Facebook Reason](https:////bloomberg.github.io/bucklescript/reason-demo)
7+
8+
Note that the playgrounds are only for demos, it might not be the latest,
9+
you should always use the command line as your production tools.
10+
11+

docs/README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
* [FAQ](./FAQ.md)
55

6-
* [About OCaml](https://ocaml.org/)
7-
86
* [Compiler options](./Compiler-options.md)
97

108
* [How to adapt your build system](./How-to-adapt-your-build-system.md)
@@ -21,11 +19,11 @@ everywhere: users don't need to install binaries or use package managers to acce
2119
Another important factor is that the JavaScript VM is quite fast and keeps getting faster.
2220
The JavaScript platform is therefore increasingly capable of supporting large applications.
2321

24-
# Why OCaml?
22+
# Why [BuckleScript](https://github.com/bloomberg/bucklescript)?
2523

2624
BuckleScript is mainly designed to solve the problems of large scale JavaScript programming:
2725

28-
1. **Lack of type-safety:** OCaml offers an industrial-strength state-of-the-art type system and provides type inference (i.e. No verbose type annotation required), which proves [invaluable](http://programmers.stackexchange.com/questions/215482/what-are-the-safety-benefits-of-a-type-system) in managing large projects.
26+
1. **Lack of type-safety:** [OCaml]((https://ocaml.org/) offers an industrial-strength state-of-the-art type system and provides type inference (i.e. No verbose type annotation required), which proves [invaluable](http://programmers.stackexchange.com/questions/215482/what-are-the-safety-benefits-of-a-type-system) in managing large projects.
2927

3028
2. **Dead code:** A large amount of web-development relies on inclusion of code dependencies by copying or referencing CDNs (the very thing that makes JavaScript highly accessible), but this also introduces a lot of [dead code](https://en.wikipedia.org/wiki/Dead_code). This impacts performance adversely when the JavaScript VM has to interpret code that will never be invoked. BuckleScript provides powerful dead-code elimination at all levels. Function and module level elimination is facilitated by the sophistication of the type-system of OCaml, and at the global level BuckleScript generates code ready for dead-code elimination done by bundling tools such as the [Google closure-compiler](https://developers.google.com/closure/compiler/).
3129

docs/SUMMARY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
* [Home](./README.md)
22

3-
* [Playground](https://bloomberg.github.io/bucklescript/js-demo)
3+
* Playground
4+
* [OCaml & Reason Playgrounds](./Playground.md)
45

56
* Get Started
67
* [Installation](./Installation.md)
@@ -29,7 +30,7 @@
2930
* [Unsupported IO primitives](./Unsupported-IO-primitives.md)
3031

3132
* Contributions
32-
* [Github Link](https://github.com/bloomberg/bucklescript)
33+
3334
* [Dev mode How to](./Dev-mode-How-to.md)
3435
* [Help move runtime functions from OCaml to Javascript](./Help-move-runtime-functions-from-OCaml-to-Javascript.md)
3536

jscomp/ext_list.ml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,28 @@ let exclude_with_fact p l =
6767
!excluded , if !excluded <> None then v else l
6868

6969

70+
(** Make sure [p2 x] and [p1 x] will not hold at the same time *)
71+
let exclude_with_fact2 p1 p2 l =
72+
let excluded1 = ref None in
73+
let excluded2 = ref None in
74+
let rec aux accu = function
75+
| [] -> List.rev accu
76+
| x :: l ->
77+
if p1 x then
78+
begin
79+
excluded1 := Some x ;
80+
aux accu l
81+
end
82+
else if p2 x then
83+
begin
84+
excluded2 := Some x ;
85+
aux accu l
86+
end
87+
else aux (x :: accu) l in
88+
let v = aux [] l in
89+
!excluded1, !excluded2 , if !excluded1 <> None && !excluded2 <> None then v else l
90+
91+
7092

7193
let rec same_length xs ys =
7294
match xs, ys with

jscomp/ext_list.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ val filter_map : ('a -> 'b option) -> 'a list -> 'b list
3737

3838
val excludes : ('a -> bool) -> 'a list -> bool * 'a list
3939
val exclude_with_fact : ('a -> bool) -> 'a list -> 'a option * 'a list
40+
val exclude_with_fact2 :
41+
('a -> bool) -> ('a -> bool) -> 'a list -> 'a option * 'a option * 'a list
4042
val same_length : 'a list -> 'b list -> bool
4143

4244
val init : int -> (int -> 'a) -> 'a list

jscomp/ext_ref.ml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,19 @@ let protect r v body =
3232
with x ->
3333
r := old;
3434
raise x
35+
36+
37+
let protect2 r1 r2 v1 v2 body =
38+
let old1 = !r1 in
39+
let old2 = !r2 in
40+
try
41+
r1 := v1;
42+
r2 := v2;
43+
let res = body() in
44+
r1 := old1;
45+
r2 := old2;
46+
res
47+
with x ->
48+
r1 := old1;
49+
r2 := old2;
50+
raise x

jscomp/ext_ref.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@
2323
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
2424

2525
val protect : 'a ref -> 'a -> (unit -> 'b) -> 'b
26+
27+
val protect2 : 'a ref -> 'b ref -> 'a -> 'b -> (unit -> 'c) -> 'c

jscomp/ppx_entry.ml

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ let uncurry_fn_type loc ty ptyp_attributes
312312
ptyp_attributes = []
313313
}
314314

315-
let uncurry = ref false
315+
let uncurry_type = ref false
316316

317317
(*
318318
Attributes are very hard to attribute
@@ -326,13 +326,6 @@ let handle_typ
326326
(self : Ast_mapper.mapper)
327327
(ty : Parsetree.core_type) =
328328
match ty with
329-
| {ptyp_desc =
330-
Ptyp_extension({txt = "uncurry"},
331-
PTyp ty )}
332-
->
333-
Ext_ref.protect uncurry true begin fun () ->
334-
self.typ self ty
335-
end
336329
| {ptyp_attributes ;
337330
ptyp_desc = Ptyp_arrow ("", args, body);
338331
ptyp_loc = loc
@@ -345,7 +338,7 @@ let handle_typ
345338
| None, _ ->
346339
let args = self.typ self args in
347340
let body = self.typ self body in
348-
if !uncurry then
341+
if !uncurry_type then
349342
uncurry_fn_type loc ty ptyp_attributes args body
350343
else {ty with ptyp_desc = Ptyp_arrow("", args, body)}
351344
end
@@ -354,29 +347,15 @@ let handle_typ
354347
ptyp_attributes ;
355348
ptyp_loc = loc
356349
} ->
357-
begin match Ext_list.exclude_with_fact (function
358-
| {Location.txt = "bs.obj" ; _}, _ -> true
359-
| _ -> false ) ptyp_attributes with
360-
| 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-
373-
{ptyp_desc =
374-
Ptyp_constr ({ txt = js_obj_type_id () ; loc},
375-
[{ ty with ptyp_desc = Ptyp_object(methods, closed_flag);
376-
ptyp_attributes }]);
377-
ptyp_attributes = [];
378-
ptyp_loc = loc }
379-
| None, _ ->
350+
begin match Ext_list.exclude_with_fact2
351+
(function
352+
| {Location.txt = "bs.obj" ; _}, _ -> true
353+
| _ -> false )
354+
(function
355+
| {Location.txt = "uncurry"; _}, _ -> true
356+
| _ -> false)
357+
ptyp_attributes with
358+
| None, None, _ ->
380359
let methods =
381360
List.map (fun (label, ptyp_attrs, core_type ) ->
382361
match find_uncurry_attrs_and_remove ptyp_attrs with
@@ -395,7 +374,33 @@ let handle_typ
395374
ptyp_loc = loc }
396375
else
397376
{ty with ptyp_desc = Ptyp_object (methods, closed_flag)}
398-
377+
| fact1 , fact2, ptyp_attributes ->
378+
let obj_type_as_js_obj_type_cxt = fact1 <> None || !obj_type_as_js_obj_type in
379+
let uncurry_type_cxt = fact2 <> None || !uncurry_type in
380+
let methods =
381+
Ext_ref.protect2
382+
obj_type_as_js_obj_type
383+
uncurry_type
384+
obj_type_as_js_obj_type_cxt
385+
uncurry_type_cxt begin fun _ ->
386+
List.map (fun (label, ptyp_attrs, core_type ) ->
387+
match find_uncurry_attrs_and_remove ptyp_attrs with
388+
| None, _ -> label, ptyp_attrs , self.typ self core_type
389+
| Some v, ptyp_attrs ->
390+
label , ptyp_attrs, self.typ self
391+
{ core_type with ptyp_attributes = v :: core_type.ptyp_attributes}
392+
) methods
393+
end
394+
in
395+
let inner_type = { ty with ptyp_desc = Ptyp_object(methods, closed_flag);
396+
ptyp_attributes } in
397+
if obj_type_as_js_obj_type_cxt then
398+
{ptyp_desc =
399+
Ptyp_constr ({ txt = js_obj_type_id () ; loc},
400+
[inner_type]);
401+
ptyp_attributes = [];
402+
ptyp_loc = loc }
403+
else inner_type
399404
end
400405
| _ -> super.typ self ty
401406

@@ -410,7 +415,7 @@ let handle_ctyp
410415
} ->
411416
begin match find_uncurry_attrs_and_remove pcty_attributes with
412417
| Some _, pcty_attributes' ->
413-
Ext_ref.protect uncurry true begin fun () ->
418+
Ext_ref.protect uncurry_type true begin fun () ->
414419
self.class_type self {ty with pcty_attributes = pcty_attributes'}
415420
end
416421
| None, _ -> super.class_type self ty

jscomp/test/attr_test.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ let u = fun [@uncurry] (x,y) -> x + y
44
let h = u (1,2) [@uncurry]
55

66
type u = < v : int ; y : int > [@uncurry]
7+
type ('a,'b) xx =
8+
(< case : (int -> (int -> 'a [@uncurry]) [@uncurry]); .. > as 'b)
9+
type ('a,'b) xx_uncurry =
10+
(< case : int -> (int -> 'a ); .. > [@uncurry]) as 'b
711

12+
type yy_uncurry = < x : int > [@uncurry]
13+
type yy = < x : int >
814
type number = float
915

1016
class type date =

jscomp/test/http_types.ml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,24 @@
1414

1515
type req
1616

17-
type resp = [%uncurry: <
17+
type resp =
18+
<
1819
statusCode__set : int -> unit ;
1920
setHeader : string * string -> unit ;
2021
end__ : string -> unit
21-
> Js.t ]
22+
> [@bs.obj] [@uncurry]
2223

23-
type server = [%uncurry: <
24-
listen : int * string * (unit -> unit) -> unit
25-
> Js.t]
24+
type server =
25+
<
26+
listen : int * string * (unit -> unit) -> unit
27+
> [@bs.obj] [@uncurry]
2628

2729

2830

29-
type http = [%uncurry:<
31+
type http =
32+
<
3033
createServer : (req * resp -> unit ) -> server
31-
> Js.t ]
34+
> [@bs.obj] [@uncurry]
3235

3336

3437
external http : http = "http" [@@bs.val_of_module ]

jscomp/test/test_index.ml

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44

55

66

7-
let f (x : (< case : int -> 'a [@uncurry];
8-
case__set : int * int -> unit [@uncurry];
9-
.. > as 'b) Js.t)
7+
let f (x : < case : int -> 'a ;
8+
case__set : int * int -> unit ;
9+
.. > [@uncurry] [@bs.obj])
1010
=
1111
x ## case__set (3, 2) ;
1212
x ## case 3
1313

14-
class type ['a] case = object
15-
method case : int -> 'a [@uncurry]
16-
method case__set : int * 'a -> unit [@uncurry]
14+
class type ['a] case = object [@uncurry]
15+
method case : int -> 'a
16+
method case__set : int * 'a -> unit
1717
end
1818

1919
let ff (x : int case Js.t)
@@ -23,26 +23,29 @@ let ff (x : int case Js.t)
2323

2424

2525

26-
let h (x : (< case : (int -> (int -> 'a [@uncurry]) [@uncurry]); .. > as 'b) Js.t) =
26+
let h (x :
27+
< case : (int -> (int -> 'a ) ); .. > [@uncurry] [@bs.obj]) =
2728
let a = x##case 3 in
28-
a #@ 2
29+
a 2 [@uncurry]
2930

3031

31-
type x_obj = [%uncurry: <
32-
case : int -> int ;
33-
case__set : int * int -> unit ;
34-
> Js.t ]
32+
type x_obj =
33+
<
34+
case : int -> int ;
35+
case__set : int * int -> unit ;
36+
> [@uncurry] [@bs.obj]
3537

3638
let f_ext
3739
(x : x_obj)
3840
=
3941
x ## case__set (3, 2) ;
4042
x ## case 3
4143

42-
type 'a h_obj = [%uncurry: <
43-
case : int -> (int -> 'a)
44-
> Js.t ]
44+
type 'a h_obj =
45+
<
46+
case : int -> (int -> 'a)
47+
> [@uncurry] [@bs.obj]
4548

4649
let h_ext (x : 'a h_obj) =
4750
let a = x ##case 3 in
48-
a #@ 2
51+
a 2 [@uncurry]

0 commit comments

Comments
 (0)