Skip to content

Commit 056cedc

Browse files
Hongbo Zhangbobzhang
Hongbo Zhang
authored andcommitted
1. add complete object ffi support
2. add zero cost nullable support
1 parent d93e027 commit 056cedc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1980
-203
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ ocaml/man
4545
*~
4646
*.annot
4747
*.mj
48-
jscomp/bench/*.js
48+
4949
*.bak
5050
.vscode
5151
*.jsx

jscomp/compiler.mllib

+4
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,11 @@ lam_register
6060
lam_analysis
6161
lam_group
6262
lam_current_unit
63+
lam_methname
6364

6465
j
6566
js_config
67+
js_array
6668
js_program_loader
6769
js_output
6870
js_dump
@@ -75,6 +77,8 @@ js_pass_flatten_and_mark_dead
7577
js_pass_scope
7678
js_call_info
7779
js_pass_debug
80+
81+
js_of_lam_option
7882
js_of_lam_float_record
7983
js_of_lam_record
8084
js_of_lam_tuple

jscomp/ext_ident.ml

+6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ let js_object_flag = 32 (* javascript object flags *)
3535
let is_js (i : Ident.t) =
3636
i.flags land js_flag <> 0
3737

38+
let is_js_or_global (i : Ident.t) =
39+
i.flags land (8 lor 1) <> 0
40+
3841
let is_js_module (i : Ident.t) =
3942
i.flags land js_module_flag <> 0
4043

@@ -234,3 +237,6 @@ let reset () =
234237
begin
235238
Hashtbl.clear js_module_table
236239
end
240+
241+
let undefined = create_js "undefined"
242+
let null = create_js "null"

jscomp/ext_ident.mli

+3
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ val make_unused : unit -> Ident.t
4343
val is_unused_ident : Ident.t -> bool
4444

4545
val convert : string -> string
46+
val undefined : Ident.t
47+
val is_js_or_global : Ident.t -> bool
48+
val null : Ident.t

jscomp/ext_list.ml

+7
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ let take n l =
116116
else (Array.to_list (Array.sub arr 0 n ),
117117
Array.to_list (Array.sub arr n (arr_length - n)))
118118

119+
let try_take n l =
120+
let arr = Array.of_list l in
121+
let arr_length = Array.length arr in
122+
if arr_length <= n then
123+
l, arr_length, []
124+
else Array.to_list (Array.sub arr 0 n ), n, (Array.to_list (Array.sub arr n (arr_length - n)))
125+
119126
let exclude_tail (x : 'a list) : 'a list =
120127
let rec aux acc x =
121128
match x with

jscomp/ext_list.mli

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ val same_length : 'a list -> 'b list -> bool
3131
val init : int -> (int -> 'a) -> 'a list
3232

3333
val take : int -> 'a list -> 'a list * 'a list
34+
val try_take : int -> 'a list -> 'a list * int * 'a list
3435

3536
val exclude_tail : 'a list -> 'a list
3637

jscomp/ext_log.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
type 'a logging = ('a, Format.formatter, unit, unit, unit, unit) format6 -> 'a
2626

2727
let err str f =
28-
Format.fprintf Format.err_formatter ("%s " ^^ f) str
28+
Format.fprintf Format.err_formatter ("%s " ^^ f ^^ "@.") str
2929

3030
let ierr b str f =
3131
if b then

jscomp/ext_string.ml

+47
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ let split_by ?(keep_empty=false) is_delim str =
3838
loop [] len (len - 1)
3939

4040
let split ?keep_empty str on =
41+
if str = "" then [] else
4142
split_by ?keep_empty (fun x -> (x : char) = on) str ;;
4243

4344
let starts_with s beg =
@@ -102,3 +103,49 @@ let repeat n s =
102103
Bytes.to_string res
103104

104105
let equal (x : string) y = x = y
106+
107+
108+
109+
let _is_sub ~sub i s j ~len =
110+
let rec check k =
111+
if k = len
112+
then true
113+
else
114+
String.unsafe_get sub (i+k) =
115+
String.unsafe_get s (j+k) && check (k+1)
116+
in
117+
j+len <= String.length s && check 0
118+
119+
120+
121+
let find ?(start=0) ~sub s =
122+
let n = String.length sub in
123+
let i = ref start in
124+
let module M = struct exception Exit end in
125+
try
126+
while !i + n <= String.length s do
127+
if _is_sub ~sub 0 s !i ~len:n then raise M.Exit;
128+
incr i
129+
done;
130+
-1
131+
with M.Exit ->
132+
!i
133+
134+
135+
let rfind ~sub s =
136+
let n = String.length sub in
137+
let i = ref (String.length s - n) in
138+
let module M = struct exception Exit end in
139+
try
140+
while !i >= 0 do
141+
if _is_sub ~sub 0 s !i ~len:n then raise M.Exit;
142+
decr i
143+
done;
144+
-1
145+
with M.Exit ->
146+
!i
147+
148+
let tail_from s x =
149+
let len = String.length s in
150+
if x > len then invalid_arg ("Ext_string.tail_from " ^s ^ " : "^ string_of_int x )
151+
else String.sub s x (len - x)

jscomp/ext_string.mli

+6
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,9 @@ val is_empty : string -> bool
4141
val repeat : int -> string -> string
4242

4343
val equal : string -> string -> bool
44+
45+
val find : ?start:int -> sub:string -> string -> int
46+
47+
val rfind : sub:string -> string -> int
48+
49+
val tail_from : string -> int -> string

jscomp/idents_analysis.ml

+14-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,20 @@ let calculate_used_idents
3838
Ident_set.(
3939
delta :=
4040
diff (fold (fun id acc ->
41-
union acc (Hashtbl.find ident_free_vars id )) !delta empty)
41+
42+
if Ext_ident.is_js_or_global id then
43+
acc (* will not pull in dependencies any more *)
44+
else
45+
union acc (
46+
begin match Hashtbl.find ident_free_vars id with
47+
| exception Not_found ->
48+
Ext_log.err __LOC__ "%s/%d" id.name id.stamp;
49+
assert false
50+
| e -> e
51+
end
52+
)
53+
54+
) !delta empty)
4255
!current_ident_sets;
4356
not (is_empty !delta)) do
4457
current_ident_sets := Ident_set.(union !current_ident_sets !delta)

jscomp/j.ml

+5
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ and expression_desc =
165165
if it's know at compile time, we can turn it into
166166
f(args[0], args[1], ... )
167167
*)
168+
| Bind of expression * expression
169+
(* {[ Bind (a,b) ]}
170+
is literally
171+
{[ a.bind(b) ]}
172+
*)
168173
| Call of expression * expression list * Js_call_info.t
169174
(* Analysze over J expression is hard since,
170175
some primitive call is translated

jscomp/js_analyzer.ml

+4-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ let rec no_side_effect (x : J.expression) =
8787
the block is mutable does not mean this operation is non-pure
8888
*)
8989
List.for_all no_side_effect xs
90+
| Bind(fn, obj) -> no_side_effect fn && no_side_effect obj
91+
| Object kvs ->
92+
List.for_all (fun (_property_name, y) -> no_side_effect y ) kvs
9093
| Array_append (a,b)
9194
| String_append (a,b)
9295
| Seq (a,b) -> no_side_effect a && no_side_effect b
@@ -117,7 +120,7 @@ let rec no_side_effect (x : J.expression) =
117120
| New _
118121
| Caml_uninitialized_obj _
119122
| String_access _
120-
| Object _
123+
121124
| Caml_block_set_tag _
122125
| Caml_block_set_length _ (* actually true? *)
123126
-> false

jscomp/js_array.ml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
(* BuckleScript compiler
2+
* Copyright (C) 2015-2016 Bloomberg Finance L.P.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, with linking exception;
7+
* either version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17+
*)
18+
19+
(* Author: Hongbo Zhang *)
20+
21+
module E = Js_exp_make
22+
23+
let set_array e e0 e1 =
24+
E.assign (E.access e e0) e1
25+
26+
let ref_array e e0 =
27+
E.access e e0

jscomp/js_array.mli

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(* BuckleScript compiler
2+
* Copyright (C) 2015-2016 Bloomberg Finance L.P.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, with linking exception;
7+
* either version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17+
*)
18+
19+
(* Author: Hongbo Zhang *)
20+
21+
22+
val set_array : J.expression -> J.expression -> J.expression -> J.expression
23+
24+
val ref_array : J.expression -> J.expression -> J.expression

jscomp/js_dump.ml

+7-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ module L = struct
9090

9191
let curry = "curry" (* curry arbitrary args *)
9292
let tag = "tag"
93+
let bind = "bind"
9394
end
9495
let return_indent = (String.length L.return / Ext_pp.indent_length)
9596

@@ -419,7 +420,11 @@ and
419420
in
420421
if l > 15 then P.paren_group f 1 action
421422
else action ()
422-
423+
| Bind (a,b) ->
424+
begin
425+
expression_desc cxt l f
426+
(Call ({expression_desc = Dot(a,L.bind, true); comment = None }, [b], {arity = Full}))
427+
end
423428
(* | Tag_ml_obj e -> *)
424429
(* P.group f 1 (fun _ -> *)
425430
(* P.string f "Object.defineProperty"; *)
@@ -1056,6 +1061,7 @@ and statement_desc top cxt f (s : J.statement_desc) : Ext_pp_scope.t =
10561061
| Caml_block _
10571062
| FlatCall _
10581063
| Typeof _
1064+
| Bind _
10591065
| Number _
10601066
| Not _
10611067
| New _

jscomp/js_exp_make.ml

+36-5
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ let index ?comment (e0 : t) (e1 : int) : t =
188188
match e0.expression_desc with
189189
| Array (l,_mutable_flag) when no_side_effect e0 ->
190190
List.nth l e1 (* Float i -- should not appear here *)
191+
| Caml_block (l,_mutable_flag, _, _) when no_side_effect e0 ->
192+
List.nth l e1 (* Float i -- should not appear here *)
193+
191194
| _ -> { expression_desc = Access (e0, int e1); comment}
192195

193196
let call ?comment ?info e0 args : t =
@@ -237,7 +240,7 @@ let is_caml_block ?comment (e : t) : t =
237240
let array_length ?comment (e : t) : t =
238241
match e.expression_desc with
239242
(* TODO: use array instead? *)
240-
| Array (l, _) -> int ?comment (List.length l)
243+
| (Array (l, _) | Caml_block(l,_,_,_)) when no_side_effect e -> int ?comment (List.length l)
241244
| _ -> { expression_desc = Length (e, Array) ; comment }
242245

243246
let string_length ?comment (e : t) : t =
@@ -330,6 +333,18 @@ let tag_ml_obj ?comment e : t =
330333
let var_dot ?comment (x : Ident.t) (e1 : string) : t =
331334
{expression_desc = Dot (var x, e1, true); comment}
332335

336+
let bind_call ?comment obj (e1 : string) args : t =
337+
call {expression_desc =
338+
Bind ({expression_desc = Dot (obj, e1, true); comment} , obj);
339+
comment = None } args
340+
341+
let bind_var_call ?comment (x : Ident.t) (e1 : string) args : t =
342+
let obj = var x in
343+
call {expression_desc =
344+
Bind ({expression_desc = Dot (obj, e1, true); comment} , obj);
345+
comment = None } args
346+
347+
333348
(* Dot .....................**)
334349

335350
let float ?comment f : t =
@@ -466,7 +481,7 @@ let rec econd ?comment (b : t) (t : t) (f : t) : t =
466481

467482
| Number ((Int { i = 0; _}) ), _, _
468483
-> f (* TODO: constant folding: could be refined *)
469-
| (Number _ | Array _), _, _
484+
| (Number _ | Array _ | Caml_block _), _, _ when no_side_effect b && no_side_effect f
470485
-> t (* a block can not be false in OCAML, CF - relies on flow inference*)
471486
| (Bin (Bor, v , {expression_desc = Number (Int {i = 0 ; _})})), _, _
472487
-> econd v t f
@@ -687,6 +702,9 @@ let tag ?comment e : t =
687702
Bin (Bor, {expression_desc = Caml_block_tag e; comment }, int 0 );
688703
comment = None }
689704

705+
let bind ?comment fn obj : t =
706+
{expression_desc = Bind (fn, obj) ; comment }
707+
690708
let public_method_call meth_name obj label cache args =
691709
let len = List.length args in
692710
(** FIXME: not caml object *)
@@ -714,13 +732,26 @@ let public_method_call meth_name obj label cache args =
714732
how about x#|getElementById|2|
715733
*)
716734
(
717-
if len <=8 then
735+
let fn = bind (dot obj meth_name) obj in
736+
if len = 0 then
737+
dot obj meth_name
738+
(* Note that when no args supplied,
739+
it is not necessarily a function, [bind]
740+
is dangerous
741+
so if user write such code
742+
{[
743+
let u = x # say in
744+
u 3
745+
]}
746+
It's reasonable to drop [this] support
747+
*)
748+
else if len <=8 then
718749
let len_str = string_of_int len in
719750
runtime_call Js_config.curry ("app"^len_str)
720-
(dot obj meth_name :: args)
751+
(fn :: args)
721752
else
722753
runtime_call Js_config.curry "app"
723-
[dot obj meth_name ; arr NA args ]
754+
[fn ; arr NA args ]
724755
)
725756

726757
let set_tag ?comment e tag : t =

jscomp/js_exp_make.mli

+3-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ val string_append : binary_op
118118
val tag_ml_obj : unary_op
119119

120120
val var_dot : ?comment:string -> Ident.t -> string -> t
121-
121+
val bind_var_call : ?comment:string -> Ident.t -> string -> t list -> t
122+
val bind_call : ?comment:string -> J.expression -> string -> J.expression list -> t
122123
val js_global_dot : ?comment:string -> string -> string -> t
123124

124125
val index : ?comment:string -> t -> int -> t
@@ -244,3 +245,4 @@ val dummy_obj : ?comment:string -> unit -> t
244245
(** convert a block to expresion by using IIFE *)
245246
val of_block : ?comment:string -> J.statement list -> J.expression -> t
246247

248+
val bind : binary_op

0 commit comments

Comments
 (0)