diff --git a/jscomp/bin/all_ounit_tests.ml b/jscomp/bin/all_ounit_tests.ml index 84362790af..6a8fcda6a7 100644 --- a/jscomp/bin/all_ounit_tests.ml +++ b/jscomp/bin/all_ounit_tests.ml @@ -3529,6 +3529,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string @@ -3663,6 +3664,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" @@ -6895,9 +6897,9 @@ val make_unused : unit -> Ident.t val convert : string -> string -val undefined : Ident.t + val is_js_or_global : Ident.t -> bool - val nil : Ident.t + val compare : Ident.t -> Ident.t -> int @@ -7219,9 +7221,6 @@ let reset () = String_hashtbl.clear js_module_table -let undefined = create_js "undefined" -let nil = create_js "null" - (* Has to be total order, [x < y] and [x > y] should be consistent flags are not relevant here diff --git a/jscomp/core/bs_conditional_initial.ml b/jscomp/core/bs_conditional_initial.ml index 9b0bf7299b..df5ba896e9 100644 --- a/jscomp/core/bs_conditional_initial.ml +++ b/jscomp/core/bs_conditional_initial.ml @@ -25,7 +25,7 @@ let setup_env () = #if BS_DEBUG then - Js_config.set_debug_file "pipe_syntax.ml"; + Js_config.set_debug_file "gpr_2700_test.ml"; #end Lexer.replace_directive_bool "BS" true; Lexer.replace_directive_string "BS_VERSION" Bs_version.version diff --git a/jscomp/core/j.ml b/jscomp/core/j.ml index af5bebecfd..b580e3b5e1 100644 --- a/jscomp/core/j.ml +++ b/jscomp/core/j.ml @@ -102,68 +102,17 @@ and expression_desc = | Length of expression * length_object | Char_of_int of expression | Char_to_int of expression - | Is_null_undefined_to_boolean of expression + | Is_null_or_undefined of expression (** where we use a trick [== null ] *) - | Array_of_size of expression - (* used in [#create_array] primitive, note having - uninitilized array is not as bad as in ocaml, - since GC does not rely on it - *) | Array_copy of expression (* shallow copy, like [x.slice] *) - | Array_append of expression * expression (* For [caml_array_append]*) - (* | Tag_ml_obj of expression *) - | String_append of expression * expression - | Anything_to_number of expression + | String_append of expression * expression | Bool of bool (* js true/false*) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence [typeof] is an operator *) | Typeof of expression | Js_not of expression (* !v *) - | String_of_small_int_array of expression - (* String.fromCharCode.apply(null, args) *) - (* Convert JS boolean into OCaml boolean - like [+true], note this ast talks using js - terminnology unless explicity stated - *) - | Json_stringify of expression - (* TODO: in the future, it might make sense to group primitivie by type, - which makes optimizations easier - {[ JSON.stringify(value, replacer[, space]) ]} - *) - | Anything_to_string of expression - (* for debugging utitlites, - TODO: [Dump] is not necessary with this primitive - Note that the semantics is slightly different from [JSON.stringify] - {[ - JSON.stringify("x") - ]} - {[ - ""x"" - ]} - {[ - JSON.stringify(undefined) - ]} - {[ - undefined - ]} - {[ '' + undefined - ]} - {[ 'undefined' - ]} - *) - | Dump of Js_op.level * expression list - (* TODO: - add - {[ Assert of bool * expression ]} - *) - (* to support - val log1 : 'a -> unit - val log2 : 'a -> 'b -> unit - val log3 : 'a -> 'b -> 'c -> unit - *) - (* TODO: Add some primitives so that [js inliner] can do a better job *) | Seq of expression * expression | Cond of expression * expression * expression @@ -178,11 +127,6 @@ and expression_desc = if it's know at compile time, we can turn it into f(args[0], args[1], ... ) *) - | Bind of expression * expression - (* {[ Bind (a,b) ]} - is literally - {[ a.bind(b) ]} - *) | Call of expression * expression list * Js_call_info.t (* Analysze over J expression is hard since, some primitive call is translated @@ -250,7 +194,8 @@ and expression_desc = *) | Number of number | Object of property_map - + | Undefined + | Null and for_ident_expression = expression (* pure*) and finish_ident_expression = expression (* pure *) diff --git a/jscomp/core/js_analyzer.ml b/jscomp/core/js_analyzer.ml index 0ac91704fd..949c132abd 100644 --- a/jscomp/core/js_analyzer.ml +++ b/jscomp/core/js_analyzer.ml @@ -83,13 +83,15 @@ let free_variables_of_expression used_idents defined_idents st = let rec no_side_effect_expression_desc (x : J.expression_desc) = match x with + | Undefined + | Null | Bool _ | Var _ | Unicode _ -> true | Fun _ -> true | Number _ -> true (* Can be refined later *) | Access (a,b) -> no_side_effect a && no_side_effect b - | Is_null_undefined_to_boolean b -> no_side_effect b + | Is_null_or_undefined b -> no_side_effect b | Str (b,_) -> b | Array (xs,_mutable_flag) | Caml_block (xs, _mutable_flag, _, _) @@ -100,10 +102,8 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = the block is mutable does not mean this operation is non-pure *) List.for_all no_side_effect xs - | Bind(fn, obj) -> no_side_effect fn && no_side_effect obj | Object kvs -> List.for_all (fun (_property_name, y) -> no_side_effect y ) kvs - | Array_append (a,b) | String_append (a,b) | Seq (a,b) -> no_side_effect a && no_side_effect b | Length (e, _) @@ -115,15 +115,8 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = | Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b | Math _ - | Array_of_size _ | Array_copy _ - (* | Tag_ml_obj _ *) - | J.Anything_to_number _ | Js_not _ - | String_of_small_int_array _ - | Json_stringify _ - | Anything_to_string _ - | Dump _ | Cond _ | FlatCall _ @@ -184,6 +177,8 @@ let rec eq_expression ({expression_desc = x0} : J.expression) ({expression_desc = y0} : J.expression) = begin match x0 with + | Null -> y0 = Null + | Undefined -> y0 = Undefined | Number (Int i) -> begin match y0 with | Number (Int j) -> i = j @@ -244,12 +239,6 @@ let rec eq_expression p0 = p1 && b0 = b1 && eq_expression e0 e1 | _ -> false end - | Dump (l0,es0) -> - begin match y0 with - | Dump(l1,es1) -> - l0 = l1 && eq_expression_list es0 es1 - | _ -> false - end | Seq (a0,b0) -> begin match y0 with | Seq(a1,b1) -> @@ -264,23 +253,13 @@ let rec eq_expression | Length _ | Char_of_int _ | Char_to_int _ - | Is_null_undefined_to_boolean _ - | Array_of_size _ + | Is_null_or_undefined _ | Array_copy _ - | Array_append _ | String_append _ - | Anything_to_number _ - | Typeof _ | Js_not _ - | String_of_small_int_array _ - | Json_stringify _ - | Anything_to_string _ - - | Cond _ | FlatCall _ - | Bind _ | String_access _ | New _ diff --git a/jscomp/core/js_dump.ml b/jscomp/core/js_dump.ml index d73b48f037..959b40ee9c 100644 --- a/jscomp/core/js_dump.ml +++ b/jscomp/core/js_dump.ml @@ -421,6 +421,11 @@ and expression l cxt f (exp : J.expression) : Ext_pp_scope.t = and expression_desc cxt (l:int) f x : Ext_pp_scope.t = match x with + | Null -> + P.string f L.null; cxt + | Undefined + -> + P.string f L.undefined; cxt | Var v -> vident cxt f v | Bool b -> @@ -476,16 +481,7 @@ and in if l > 15 then P.paren_group f 1 action else action () - | Bind (a,b) -> - (* a.bind(b) - {[ fun b -> a.bind(b) ==? a.bind ]} - *) - begin - expression_desc cxt l f - (Call ({expression_desc = Dot(a,L.bind, true); comment = None }, [b], - {arity = Full; call_info = Call_na})) - end - + | FlatCall(e,el) -> P.group f 1 (fun _ -> let cxt = expression 15 cxt f e in @@ -498,34 +494,6 @@ and expression 1 cxt f el ) ) - | String_of_small_int_array ({expression_desc = desc } as e) -> - let action () = - P.group f 1 (fun _ -> - P.string f L.string_cap; - P.string f L.dot ; - P.string f L.fromCharcode; - begin match desc with - | Array (el, _mutable) - -> - P.paren_group f 1 (fun _ -> arguments cxt f el) - | _ -> - P.string f L.dot ; - P.string f L.apply; - P.paren_group f 1 (fun _ -> - P.string f L.null; - P.string f L.comma; - expression 1 cxt f e ) - end ) - in - if l > 15 then P.paren_group f 1 action - else action () - - - | Array_append (e, el) -> - P.group f 1 (fun _ -> - let cxt = expression 15 cxt f e in - P.string f ".concat"; - P.paren_group f 1 (fun _ -> arguments cxt f [el])) | Array_copy e -> P.group f 1 (fun _ -> @@ -534,27 +502,6 @@ and P.string f "()" ; cxt ) - - | Dump (level, el) -> - let obj = - match level with - | Log -> "log" - | Info -> "info" - | Warn -> "warn" - | Error -> "error" in - P.group f 1 (fun _ -> - P.string f L.console; - P.string f L.dot; - P.string f obj ; - P.paren_group f 1 (fun _ -> arguments cxt f el)) - | Json_stringify e - -> - P.group f 1 (fun _ -> - P.string f L.json ; - P.string f L.dot; - P.string f L.stringify; - P.paren_group f 1 (fun _ -> expression 0 cxt f e ) - ) | Char_to_int e -> begin match e.expression_desc with | String_access (a,b) -> @@ -640,20 +587,7 @@ and else action () ); cxt - | J.Anything_to_number e - -> - let action () = - P.group f 0 @@ fun _ -> - P.string f "+" ; - expression 13 cxt f e - in - (* need to tweak precedence carefully - here [++x --> +(+x)] - *) - if l > 12 - then P.paren_group f 1 action - else action () - | Is_null_undefined_to_boolean e -> + | Is_null_or_undefined e -> let action = (fun _ -> let cxt = expression 1 cxt f e in P.space f ; @@ -791,11 +725,6 @@ and P.space f ; expression 13 cxt f delta end - | Anything_to_string e -> - (* Note that we should not apply any smart construtor here, - it's purely a convenice for pretty-printing - *) - expression_desc cxt l f (Bin (Plus, E.empty_string_literal , e)) | Bin (Minus, {expression_desc = Number (Int {i=0l;_} | Float {f = "0."})}, e) (* TODO: @@ -929,16 +858,6 @@ and in if l > 15 then P.paren_group f 1 action else action () - | Array_of_size e -> - let action () = - P.group f 1 @@ fun _ -> - P.string f L.new_; - P.space f; - P.string f L.array; - P.paren_group f 1 @@ fun _ -> expression 0 cxt f e - in - if l > 15 then P.paren_group f 1 action else action () - | Cond (e, e1, e2) -> let action () = (* P.group f 1 @@ fun _ -> *) @@ -1119,39 +1038,33 @@ and statement_desc top cxt f (s : J.statement_desc) : Ext_pp_scope.t = | Caml_block_set_tag _ | Length _ | Caml_block_set_length _ - | Anything_to_string _ - | String_of_small_int_array _ | Call _ - | Array_append _ | Array_copy _ | Caml_block_tag _ | Seq _ | Dot _ | Cond _ | Bin _ - | Is_null_undefined_to_boolean _ + | Is_null_or_undefined _ | String_access _ | Access _ - | Array_of_size _ | String_append _ | Char_of_int _ | Char_to_int _ - | Dump _ - | Json_stringify _ | Math _ | Var _ + | Undefined + | Null | Str _ | Unicode _ | Array _ | Caml_block _ | FlatCall _ | Typeof _ - | Bind _ | Number _ | Js_not _ | Bool _ | New _ - | J.Anything_to_number _ -> false (* e = function(x){...}(x); is good *) diff --git a/jscomp/core/js_dump_lit.ml b/jscomp/core/js_dump_lit.ml index 8d8d473a72..74da7ce126 100644 --- a/jscomp/core/js_dump_lit.ml +++ b/jscomp/core/js_dump_lit.ml @@ -73,6 +73,7 @@ let bind = "bind" let math = "Math" let apply = "apply" let null = "null" +let undefined = "undefined" let string_cap = "String" let fromCharcode = "fromCharCode" let eq = "=" diff --git a/jscomp/core/js_exp_make.ml b/jscomp/core/js_exp_make.ml index 0a4de5223a..55adc03e8f 100644 --- a/jscomp/core/js_exp_make.ml +++ b/jscomp/core/js_exp_make.ml @@ -87,10 +87,11 @@ let var ?comment id : t = let js_global ?comment (v : string) = var ?comment (Ext_ident.create_js v ) -let undefined = var Ext_ident.undefined - -let nil = var Ext_ident.nil +let undefined : t = + {expression_desc = Undefined ; comment = None} +let nil : t = + {expression_desc = Null ; comment = None} let call ?comment ~info e0 args : t = {expression_desc = Call(e0,args,info); comment } @@ -173,14 +174,6 @@ let make_block ?comment tag tag_info es mutable_flag : t = comment } -(* let uninitialized_object ?comment tag size : t = - { expression_desc = Caml_uninitialized_obj(tag,size); comment } *) - -(* let uninitialized_array ?comment (e : t) : t = - match e.expression_desc with - | Number (Int {i = 0l; _}) -> array ?comment NA [] - | _ -> {comment; expression_desc = Array_of_size e} *) - module L = Literals (* Invariant: this is relevant to how we encode string @@ -194,6 +187,7 @@ let typeof ?comment (e : t) : t = -> str ?comment L.js_type_string | Array _ -> str ?comment L.js_type_object + | Bool _ -> str ?comment L.js_type_boolean | _ -> {expression_desc = Typeof e ; comment } @@ -222,8 +216,6 @@ let math ?comment v args : t = Used in [string_of_int] and format "%d" TODO: optimize *) -let int_to_string ?comment (e : t) : t = - {expression_desc = Anything_to_string e ; comment} (* Attention: Shared *mutable state* is evil, [Js_fun_env.empty] is a mutable state .. @@ -448,22 +440,10 @@ let char_to_int ?comment (v : t) : t = | Char_of_int v -> v | _ -> {comment; expression_desc = Char_to_int v } -let array_append ?comment e el : t = - { comment ; expression_desc = Array_append (e, el)} let array_copy ?comment e : t = { comment ; expression_desc = Array_copy e} -(* Note that this return [undefined] in JS, - it should be wrapped to avoid leak [undefined] into - OCaml -*) -let dump ?comment level el : t = - {comment ; expression_desc = Dump(level,el)} - -(* let to_json_string ?comment e : t = - { comment; expression_desc = Json_stringify e } *) - let rec string_append ?comment (e : t) (el : t) : t = match e.expression_desc , el.expression_desc with | Str(_,a), String_append ({expression_desc = Str(_,b)}, c) -> @@ -474,8 +454,6 @@ let rec string_append ?comment (e : t) (el : t) : t = String_append ({expression_desc = Str(_,c)} ,d) -> string_append ?comment (string_append a (str (b ^ c))) d | Str (_,a), Str (_,b) -> str ?comment (a ^ b) - | _, Anything_to_string b -> string_append ?comment e b - | Anything_to_string b, _ -> string_append ?comment b el | _, _ -> {comment ; expression_desc = String_append(e,el)} @@ -519,17 +497,17 @@ let float_mod ?comment e1 e2 : J.expression = *) let rec triple_equal ?comment (e0 : t) (e1 : t ) : t = match e0.expression_desc, e1.expression_desc with - | Var (Id ({name = "undefined"|"null"} as id)), + | (Null| Undefined), (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ) - when Ext_ident.is_js id && no_side_effect e1 -> + when no_side_effect e1 -> caml_false (* TODO: rename it as [caml_false] *) | (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ - | Fun _ | Array _ | Caml_block _ ), Var (Id ({name = "undefined"|"null"; } as id)) - when Ext_ident.is_js id && no_side_effect e0 -> + | Fun _ | Array _ | Caml_block _ ), (Null|Undefined) + when no_side_effect e0 -> caml_false | Str (_,x), Str (_,y) -> (* CF*) bool (Ext_string.equal x y) @@ -543,6 +521,10 @@ let rec triple_equal ?comment (e0 : t) (e1 : t ) : t = bool (i0 = i1) | Char_of_int a , Char_of_int b -> triple_equal ?comment a b + | Null, Undefined + | Undefined, Null -> caml_false + | Null, Null + | Undefined, Undefined -> caml_true | _ -> {expression_desc = Bin(EqEqEq, e0,e1); comment} @@ -551,14 +533,7 @@ let bin ?comment (op : J.binop) e0 e1 : t = | EqEqEq -> triple_equal ?comment e0 e1 | _ -> {expression_desc = Bin(op,e0,e1); comment} -(* | (Bin (NotEqEq, e1, *) -(* {expression_desc = Var (Id ({name = "undefined"; _} as id))}) *) -(* | Bin (NotEqEq, *) -(* {expression_desc = Var (Id ({name = "undefined"; _} as id))}, *) -(* e1) *) -(* ), *) -(* _ when Ext_ident.is_js id -> *) -(* and_ e1 e2 *) + (* TODO: Constant folding, Google Closure will do that?, Even if Google Clsoure can do that, we will see how it interact with other optimizations @@ -775,11 +750,6 @@ let is_type_number ?comment (e : t) : t = string_equal ?comment (typeof e) (str "number") -let string_of_small_int_array ?comment xs : t = - {expression_desc = String_of_small_int_array xs; comment} - - - (* we are calling [Caml_primitive.primitive_name], since it's under our control, we should make it follow the javascript name convention, and call plain [dot] @@ -841,7 +811,7 @@ let public_method_call meth_name obj label cache args = (* [fn ; arr NA args ] *) (* ) *) -let set_tag ?comment e tag : t = +let block_set_tag ?comment e tag : t = seq {expression_desc = Caml_block_set_tag (e,tag); comment } unit @@ -1245,47 +1215,47 @@ let of_block ?comment ?e block : t = , Js_fun_env.empty 0) } [] -let is_null ?comment x = triple_equal ?comment x nil +let is_null ?comment (x : t) = + triple_equal ?comment x nil let is_undef ?comment x = triple_equal ?comment x undefined let for_sure_js_null_undefined (x : t) = match x.expression_desc with - | Var (Id ({name = "undefined" | "null"} as id)) - -> Ext_ident.is_js id + | Null | Undefined + -> true | _ -> false let is_null_undefined ?comment (x: t) : t = match x.expression_desc with - | Var (Id ({name = "undefined" | "null"} as id)) - when Ext_ident.is_js id + | Null | Undefined -> caml_true | Number _ | Array _ | Caml_block _ -> caml_false - | _ -> - + | _ -> { comment ; - expression_desc = Is_null_undefined_to_boolean x + expression_desc = Is_null_or_undefined x } let eq_null_undefined_boolean ?comment (a : t) (b : t) = match a.expression_desc, b.expression_desc with - | Var (Id ({name = "null" | "undefined"} as id) ), + | (Null | Undefined), (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ) - when Ext_ident.is_js id -> + -> caml_false | (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ), - Var (Id ({name = "null" | "undefined"} as id) ) - when Ext_ident.is_js id -> + (Null | Undefined) + -> caml_false - | Var (Id ({name = "null" | "undefined" as n1 } as id1) ), - Var (Id ({name = "null" | "undefined" as n2 } as id2) ) - when Ext_ident.is_js id1 && Ext_ident.is_js id2 - -> bool (n1 = n2) + | (Null, Undefined) + | (Undefined, Null) -> caml_false + | (Null, Null) + | (Undefined, Undefined) + -> caml_true | _ -> {expression_desc = Bin(EqEqEq, a, b); comment} @@ -1293,23 +1263,24 @@ let eq_null_undefined_boolean ?comment (a : t) (b : t) = let neq_null_undefined_boolean ?comment (a : t) (b : t) = match a.expression_desc, b.expression_desc with - | Var (Id ({name = "null" | "undefined"} as id) ), + | (Null | Undefined), (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ) - when Ext_ident.is_js id -> + -> caml_true | (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ), - Var (Id ({name = "null" | "undefined"} as id) ) - when Ext_ident.is_js id -> + (Null | Undefined) + -> caml_true - | Var (Id ({name = "null" | "undefined" as n1 } as id1) ), - Var (Id ({name = "null" | "undefined" as n2 } as id2) ) - when Ext_ident.is_js id1 && Ext_ident.is_js id2 - -> - if n1 <> n2 then caml_true else caml_false + | (Null , Null ) + | (Undefined, Undefined) + -> caml_false + | (Null, Undefined) + | (Undefined, Null) + -> caml_true | _ -> {expression_desc = Bin(NotEqEq, a, b); comment} diff --git a/jscomp/core/js_exp_make.mli b/jscomp/core/js_exp_make.mli index 52a1ebad19..c8fc9b25f5 100644 --- a/jscomp/core/js_exp_make.mli +++ b/jscomp/core/js_exp_make.mli @@ -139,8 +139,6 @@ val array_length : unary_op val string_length : unary_op -val string_of_small_int_array : unary_op - val bytes_length : unary_op val function_length : unary_op @@ -148,9 +146,6 @@ val function_length : unary_op val char_of_int : unary_op val char_to_int : unary_op - -val array_append : binary_op - val array_copy : unary_op val string_append : binary_op (** @@ -249,15 +244,6 @@ val call : ?comment:string -> info:Js_call_info.t -> t -> t list -> t val flat_call : binary_op -val dump : ?comment:string -> Js_op.level -> t list -> t - - - -(** see {!https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus}*) -(* val to_number : unary_op *) -val int_to_string : unary_op - - val new_ : ?comment:string -> J.expression -> J.expression list -> t val array : @@ -308,7 +294,7 @@ val is_caml_block : ?comment:string -> t -> t val tag : ?comment:string -> J.expression -> t -val set_tag : ?comment:string -> J.expression -> J.expression -> t +val block_set_tag : ?comment:string -> J.expression -> J.expression -> t (** Note that this is coupled with how we encode block, if we use the `Object.defineProperty(..)` since the array already hold the length, diff --git a/jscomp/core/js_fold.ml b/jscomp/core/js_fold.ml index d5b2d7aa36..9540e705ac 100644 --- a/jscomp/core/js_fold.ml +++ b/jscomp/core/js_fold.ml @@ -125,54 +125,11 @@ class virtual fold = ]} *) (** where we use a trick [== null ] *) - (* used in [#create_array] primitive, note having - uninitilized array is not as bad as in ocaml, - since GC does not rely on it - *) - (* shallow copy, like [x.slice] *) - (* For [caml_array_append]*) - (* | Tag_ml_obj of expression *) (* js true/false*) + (* shallow copy, like [x.slice] *) (* js true/false*) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence [typeof] is an operator *) - (* !v *) (* String.fromCharCode.apply(null, args) *) - (* Convert JS boolean into OCaml boolean - like [+true], note this ast talks using js - terminnology unless explicity stated - *) - (* TODO: in the future, it might make sense to group primitivie by type, - which makes optimizations easier - {[ JSON.stringify(value, replacer[, space]) ]} - *) - (* for debugging utitlites, - TODO: [Dump] is not necessary with this primitive - Note that the semantics is slightly different from [JSON.stringify] - {[ - JSON.stringify("x") - ]} - {[ - ""x"" - ]} - {[ - JSON.stringify(undefined) - ]} - {[ - undefined - ]} - {[ '' + undefined - ]} - {[ 'undefined' - ]} - *) - (* TODO: - add - {[ Assert of bool * expression ]} - *) - (* to support - val log1 : 'a -> unit - val log2 : 'a -> 'b -> unit - val log3 : 'a -> 'b -> 'c -> unit - *) + (* !v *) (* TODO: Add some primitives so that [js inliner] can do a better job *) (* [int_op] will guarantee return [int32] bits https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *) @@ -182,10 +139,6 @@ class virtual fold = if it's know at compile time, we can turn it into f(args[0], args[1], ... ) *) - (* {[ Bind (a,b) ]} - is literally - {[ a.bind(b) ]} - *) (* Analysze over J expression is hard since, some primitive call is translated into a plain call, it's better to keep them @@ -366,23 +319,13 @@ class virtual fold = let o = o#expression _x in let o = o#length_object _x_i1 in o | Char_of_int _x -> let o = o#expression _x in o | Char_to_int _x -> let o = o#expression _x in o - | Is_null_undefined_to_boolean _x -> let o = o#expression _x in o - | Array_of_size _x -> let o = o#expression _x in o + | Is_null_or_undefined _x -> let o = o#expression _x in o | Array_copy _x -> let o = o#expression _x in o - | Array_append (_x, _x_i1) -> - let o = o#expression _x in let o = o#expression _x_i1 in o | String_append (_x, _x_i1) -> let o = o#expression _x in let o = o#expression _x_i1 in o - | Anything_to_number _x -> let o = o#expression _x in o | Bool _x -> let o = o#bool _x in o | Typeof _x -> let o = o#expression _x in o | Js_not _x -> let o = o#expression _x in o - | String_of_small_int_array _x -> let o = o#expression _x in o - | Json_stringify _x -> let o = o#expression _x in o - | Anything_to_string _x -> let o = o#expression _x in o - | Dump (_x, _x_i1) -> - let o = o#unknown _x in - let o = o#list (fun o -> o#expression) _x_i1 in o | Seq (_x, _x_i1) -> let o = o#expression _x in let o = o#expression _x_i1 in o | Cond (_x, _x_i1, _x_i2) -> @@ -393,8 +336,6 @@ class virtual fold = let o = o#expression _x_i1 in let o = o#expression _x_i2 in o | FlatCall (_x, _x_i1) -> let o = o#expression _x in let o = o#expression _x_i1 in o - | Bind (_x, _x_i1) -> - let o = o#expression _x in let o = o#expression _x_i1 in o | Call (_x, _x_i1, _x_i2) -> let o = o#expression _x in let o = o#list (fun o -> o#expression) _x_i1 in @@ -433,6 +374,8 @@ class virtual fold = let o = o#expression _x in let o = o#expression _x_i1 in o | Number _x -> let o = o#number _x in o | Object _x -> let o = o#property_map _x in o + | Undefined -> o + | Null -> o method expression : expression -> 'self_type = fun { expression_desc = _x; comment = _x_i1 } -> let o = o#expression_desc _x in diff --git a/jscomp/core/js_map.ml b/jscomp/core/js_map.ml index 73c6f97b21..dfb241d0e8 100644 --- a/jscomp/core/js_map.ml +++ b/jscomp/core/js_map.ml @@ -138,54 +138,11 @@ class virtual map = ]} *) (** where we use a trick [== null ] *) - (* used in [#create_array] primitive, note having - uninitilized array is not as bad as in ocaml, - since GC does not rely on it - *) - (* shallow copy, like [x.slice] *) - (* For [caml_array_append]*) - (* | Tag_ml_obj of expression *) (* js true/false*) + (* shallow copy, like [x.slice] *) (* js true/false*) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence [typeof] is an operator *) - (* !v *) (* String.fromCharCode.apply(null, args) *) - (* Convert JS boolean into OCaml boolean - like [+true], note this ast talks using js - terminnology unless explicity stated - *) - (* TODO: in the future, it might make sense to group primitivie by type, - which makes optimizations easier - {[ JSON.stringify(value, replacer[, space]) ]} - *) - (* for debugging utitlites, - TODO: [Dump] is not necessary with this primitive - Note that the semantics is slightly different from [JSON.stringify] - {[ - JSON.stringify("x") - ]} - {[ - ""x"" - ]} - {[ - JSON.stringify(undefined) - ]} - {[ - undefined - ]} - {[ '' + undefined - ]} - {[ 'undefined' - ]} - *) - (* TODO: - add - {[ Assert of bool * expression ]} - *) - (* to support - val log1 : 'a -> unit - val log2 : 'a -> 'b -> unit - val log3 : 'a -> 'b -> 'c -> unit - *) + (* !v *) (* TODO: Add some primitives so that [js inliner] can do a better job *) (* [int_op] will guarantee return [int32] bits https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *) @@ -195,10 +152,6 @@ class virtual map = if it's know at compile time, we can turn it into f(args[0], args[1], ... ) *) - (* {[ Bind (a,b) ]} - is literally - {[ a.bind(b) ]} - *) (* Analysze over J expression is hard since, some primitive call is translated into a plain call, it's better to keep them @@ -391,30 +344,15 @@ class virtual map = let _x_i1 = o#length_object _x_i1 in Length (_x, _x_i1) | Char_of_int _x -> let _x = o#expression _x in Char_of_int _x | Char_to_int _x -> let _x = o#expression _x in Char_to_int _x - | Is_null_undefined_to_boolean _x -> - let _x = o#expression _x in Is_null_undefined_to_boolean _x - | Array_of_size _x -> let _x = o#expression _x in Array_of_size _x + | Is_null_or_undefined _x -> + let _x = o#expression _x in Is_null_or_undefined _x | Array_copy _x -> let _x = o#expression _x in Array_copy _x - | Array_append (_x, _x_i1) -> - let _x = o#expression _x in - let _x_i1 = o#expression _x_i1 in Array_append (_x, _x_i1) | String_append (_x, _x_i1) -> let _x = o#expression _x in let _x_i1 = o#expression _x_i1 in String_append (_x, _x_i1) - | Anything_to_number _x -> - let _x = o#expression _x in Anything_to_number _x | Bool _x -> let _x = o#bool _x in Bool _x | Typeof _x -> let _x = o#expression _x in Typeof _x | Js_not _x -> let _x = o#expression _x in Js_not _x - | String_of_small_int_array _x -> - let _x = o#expression _x in String_of_small_int_array _x - | Json_stringify _x -> let _x = o#expression _x in Json_stringify _x - | Anything_to_string _x -> - let _x = o#expression _x in Anything_to_string _x - | Dump (_x, _x_i1) -> - let _x = o#unknown _x in - let _x_i1 = o#list (fun o -> o#expression) _x_i1 - in Dump (_x, _x_i1) | Seq (_x, _x_i1) -> let _x = o#expression _x in let _x_i1 = o#expression _x_i1 in Seq (_x, _x_i1) @@ -429,9 +367,6 @@ class virtual map = | FlatCall (_x, _x_i1) -> let _x = o#expression _x in let _x_i1 = o#expression _x_i1 in FlatCall (_x, _x_i1) - | Bind (_x, _x_i1) -> - let _x = o#expression _x in - let _x_i1 = o#expression _x_i1 in Bind (_x, _x_i1) | Call (_x, _x_i1, _x_i2) -> let _x = o#expression _x in let _x_i1 = o#list (fun o -> o#expression) _x_i1 in @@ -481,6 +416,8 @@ class virtual map = let _x_i1 = o#expression _x_i1 in Caml_block_set_length (_x, _x_i1) | Number _x -> let _x = o#number _x in Number _x | Object _x -> let _x = o#property_map _x in Object _x + | Undefined -> Undefined + | Null -> Null method expression : expression -> expression = fun { expression_desc = _x; comment = _x_i1 } -> let _x = o#expression_desc _x in diff --git a/jscomp/core/js_pass_tailcall_inline.ml b/jscomp/core/js_pass_tailcall_inline.ml index 66e46e834c..a7faaeaabb 100644 --- a/jscomp/core/js_pass_tailcall_inline.ml +++ b/jscomp/core/js_pass_tailcall_inline.ml @@ -220,7 +220,7 @@ let subst name export_set stats = (* Mark a function as dead means it will never be scanned, here we inline the function *) - Ext_list.append block @@ self#block rest + Ext_list.append block (self#block rest) | (None | Some _) -> self#statement st :: self#block rest end @@ -235,9 +235,8 @@ let subst name export_set stats = let tailcall_inline (program : J.program) = - let _stats = get_stats program in - let _export_set = program.export_set in - program - |> (subst program.name _export_set _stats )# program - (* |> pass_beta #program *) + let stats = get_stats program in + let export_set = program.export_set in + (subst program.name export_set stats )#program program + diff --git a/jscomp/core/js_stmt_make.ml b/jscomp/core/js_stmt_make.ml index 67ce93164f..1fe3a70a9c 100644 --- a/jscomp/core/js_stmt_make.ml +++ b/jscomp/core/js_stmt_make.ml @@ -268,11 +268,7 @@ let rec if_ ?comment ?declaration ?else_ (e : J.expression) (then_ : J.block) | Bin (Bor , {expression_desc = Number (Int { i = 0l ; _})}, a), _, _ -> aux ?comment a then_ else_ acc - (* | Bin (NotEqEq, e1, *) - (* {expression_desc = Var (Id ({name = "undefined"; _} as id))}), *) - (* _, _ *) - (* when Ext_ident.is_js id -> *) - (* aux ?comment e1 then_ else_ acc *) + | ((Bin (Gt, ({expression_desc = diff --git a/jscomp/core/lam.ml b/jscomp/core/lam.ml index c2ac867eb2..41d0551219 100644 --- a/jscomp/core/lam.ml +++ b/jscomp/core/lam.ml @@ -197,9 +197,6 @@ type primitive = | Pis_null_undefined | Pjs_typeof | Pjs_function_length - - | Pjs_string_of_small_array - (* | Pjs_is_instance_array *) | Pcaml_obj_length | Pcaml_obj_set_length | Pwrap_exn (* convert either JS exception or OCaml exception into OCaml format *) @@ -1866,12 +1863,6 @@ let convert exports lam : _ * _ = | "#null_to_opt" -> Pnull_to_opt | "#is_nil_undef" -> Pis_null_undefined | "#string_append" -> Pstringadd - - - | "#string_of_small_int_array" -> Pjs_string_of_small_array - (* {[String.fromCharCode.apply(null,x)]} - Note if we have better suport [@bs.splice], - we can get rid of it*) | "#obj_set_length" -> Pcaml_obj_set_length | "#obj_length" -> Pcaml_obj_length | "#function_length" -> Pjs_function_length diff --git a/jscomp/core/lam.mli b/jscomp/core/lam.mli index ffaceb1949..1ce9907502 100644 --- a/jscomp/core/lam.mli +++ b/jscomp/core/lam.mli @@ -192,9 +192,6 @@ type primitive = | Pjs_typeof | Pjs_function_length - - | Pjs_string_of_small_array - (* | Pjs_is_instance_array *) | Pcaml_obj_length | Pcaml_obj_set_length | Pwrap_exn (* convert either JS exception or OCaml exception into OCaml format *) diff --git a/jscomp/core/lam_analysis.ml b/jscomp/core/lam_analysis.ml index e0a6cb510a..6e422b940e 100644 --- a/jscomp/core/lam_analysis.ml +++ b/jscomp/core/lam_analysis.ml @@ -160,7 +160,6 @@ let rec no_side_effects (lam : Lam.t) : bool = (* | Pjs_is_instance_array *) | Pwrap_exn -> true - | Pjs_string_of_small_array | Pcaml_obj_set_length | Pjs_apply | Pjs_runtime_apply @@ -541,7 +540,7 @@ and eq_primitive ( lhs : Lam.primitive) (rhs : Lam.primitive) = | Pupdate_mod -> rhs = Pupdate_mod | Pbswap16 -> rhs = Pbswap16 | Pjs_function_length -> rhs = Pjs_function_length - | Pjs_string_of_small_array -> rhs = Pjs_string_of_small_array + (* | Pjs_string_of_small_array -> rhs = Pjs_string_of_small_array *) (* | Pjs_is_instance_array -> rhs = Pjs_is_instance_array *) | Pcaml_obj_length -> rhs = Pcaml_obj_length | Pcaml_obj_set_length -> rhs = Pcaml_obj_set_length diff --git a/jscomp/core/lam_compile_const.ml b/jscomp/core/lam_compile_const.ml index 1182d7f013..5880a0f5e8 100644 --- a/jscomp/core/lam_compile_const.ml +++ b/jscomp/core/lam_compile_const.ml @@ -107,7 +107,7 @@ let translate_arg_cst (cst : External_arg_spec.cst) = E.int (Int32.of_int i) | Arg_string_lit i -> E.str i - | Arg_js_null -> E.raw_js_code Exp "null" + | Arg_js_null -> E.nil | Arg_js_json s -> E.raw_js_code Exp s diff --git a/jscomp/core/lam_compile_external_call.ml b/jscomp/core/lam_compile_external_call.ml index dee4fc6885..32b3e149d4 100644 --- a/jscomp/core/lam_compile_external_call.ml +++ b/jscomp/core/lam_compile_external_call.ml @@ -321,12 +321,8 @@ let translate_ffi 2. support [@@bs.scope "window"] we need know whether we should call [add_js_module] or not *) - begin match name, handle_external_opt external_module_name , scopes with - | "null", None, [] -> E.nil - | "undefined", None, [] -> E.undefined - | _, _, _ -> - translate_scoped_module_val external_module_name name scopes - end + translate_scoped_module_val external_module_name name scopes + | Js_send {splice = js_splice ; name ; pipe = false; js_send_scopes = scopes } -> begin match args with | self :: args -> diff --git a/jscomp/core/lam_compile_primitive.ml b/jscomp/core/lam_compile_primitive.ml index 54fbbb956f..94d3b78636 100644 --- a/jscomp/core/lam_compile_primitive.ml +++ b/jscomp/core/lam_compile_primitive.ml @@ -75,8 +75,8 @@ let translate loc begin match args with | [e] -> begin match e.expression_desc with - | Var _ -> - E.econd (E.is_null e) Js_of_lam_option.none (Js_of_lam_option.some e) + | Var _ | Undefined | Null -> + E.econd (E.is_null e) Js_of_lam_option.none (Js_of_lam_option.some e) | _ -> E.runtime_call Js_runtime_modules.js_primitive "null_to_opt" args @@ -93,7 +93,7 @@ let translate loc begin match args with | [e] -> begin match e.expression_desc with - | Var _ -> + | Var _ | Undefined | Null -> E.econd (E.is_undef e) Js_of_lam_option.none (Js_of_lam_option.some e) | _ -> E.runtime_call Js_runtime_modules.js_primitive @@ -111,7 +111,7 @@ let translate loc begin match args with | [e] -> begin match e.expression_desc with - | Var _ -> + | Var _ | Undefined | Null -> E.econd (E.is_null_undefined e) Js_of_lam_option.none (Js_of_lam_option.some e) @@ -137,18 +137,6 @@ let translate loc | [a;b] -> E.set_length a b | _ -> assert false end - | Lam.Pjs_string_of_small_array -> - begin match args with - | [e] -> E.string_of_small_int_array e - | _ -> assert false - end - (* | Lam.Pjs_is_instance_array -> - begin match args with - | [e] -> E.is_instance_array e - | _ -> assert false - end *) - - | Pis_null -> begin match args with | [e] -> E.is_null e @@ -703,9 +691,7 @@ let translate loc (* assert false (\* already handled *\) *) (* assert false *) | Pduprecord ((Record_regular - | Record_float ),0) - | Pduprecord ((Record_regular - | Record_float ),_) -> + | Record_float ),_size) -> (* _size is the length of all_lables*) begin match args with | [e] -> Js_of_lam_record.copy e | _ -> assert false diff --git a/jscomp/core/lam_dispatch_primitive.ml b/jscomp/core/lam_dispatch_primitive.ml index 2c4b743ede..ed743d3aea 100644 --- a/jscomp/core/lam_dispatch_primitive.ml +++ b/jscomp/core/lam_dispatch_primitive.ml @@ -138,13 +138,6 @@ let translate loc (prim_name : string) | "caml_power_float" -> E.math "pow" args - - | "caml_array_append" -> - begin match args with - | [e0;e1] -> E.array_append e0 e1 - | _ -> assert false - end - | "caml_array_get" -> call Js_runtime_modules.array | "caml_array_get_addr" @@ -659,8 +652,6 @@ let translate loc (prim_name : string) *) | _ -> E.array_copy a end - (* if Js_analyzer.is_constant a then a - else E.array_copy a *) | _ -> assert false end | "caml_obj_block" -> @@ -694,20 +685,11 @@ let translate loc (prim_name : string) | "caml_nativeint_of_string" | "caml_int64_format" | "caml_int64_of_string" + | "caml_format_int" -> call Js_runtime_modules.format - | "caml_format_int" -> - begin match args with - | [ {expression_desc = Str (_, "%d"); _}; v] - -> - E.int_to_string v - | _ -> - call Js_runtime_modules.format - end (* "caml_alloc_dummy"; *) (* TODO: "caml_alloc_dummy_float"; *) - - | "caml_obj_is_block" -> begin match args with @@ -764,7 +746,7 @@ let translate loc (prim_name : string) call Js_runtime_modules.obj_runtime | "caml_obj_set_tag" -> begin match args with - | [a;b] -> E.set_tag a b + | [a;b] -> E.block_set_tag a b | _ -> assert false end | "caml_obj_tag" -> (* Note that in ocaml, [int] has tag [1000] and [string] has tag [252] diff --git a/jscomp/core/lam_print.ml b/jscomp/core/lam_print.ml index caedd92592..f596576eb3 100644 --- a/jscomp/core/lam_print.ml +++ b/jscomp/core/lam_print.ml @@ -108,8 +108,6 @@ let primitive ppf (prim : Lam.primitive) = match prim with (* | Pcreate_exception s -> fprintf ppf "[exn-create]%S" s *) | Pcreate_extension s -> fprintf ppf "[ext-create]%S" s | Pwrap_exn -> fprintf ppf "#exn" - | Pjs_string_of_small_array -> fprintf ppf "#string_of_small_array" - (* | Pjs_is_instance_array -> fprintf ppf "#is_instance_array" *) | Pcaml_obj_length -> fprintf ppf "#obj_length" | Pcaml_obj_set_length -> fprintf ppf "#obj_set_length" | Pinit_mod -> fprintf ppf "init_mod!" diff --git a/jscomp/ext/ext_ident.ml b/jscomp/ext/ext_ident.ml index ea98bdd93a..33c17448e0 100644 --- a/jscomp/ext/ext_ident.ml +++ b/jscomp/ext/ext_ident.ml @@ -312,9 +312,6 @@ let reset () = String_hashtbl.clear js_module_table -let undefined = create_js "undefined" -let nil = create_js "null" - (* Has to be total order, [x < y] and [x > y] should be consistent flags are not relevant here diff --git a/jscomp/ext/ext_ident.mli b/jscomp/ext/ext_ident.mli index adb286b2d7..90869c55a3 100644 --- a/jscomp/ext/ext_ident.mli +++ b/jscomp/ext/ext_ident.mli @@ -56,9 +56,9 @@ val make_unused : unit -> Ident.t val convert : string -> string -val undefined : Ident.t + val is_js_or_global : Ident.t -> bool - val nil : Ident.t + val compare : Ident.t -> Ident.t -> int diff --git a/jscomp/ext/literals.ml b/jscomp/ext/literals.ml index 47ce84cccd..09e01835eb 100644 --- a/jscomp/ext/literals.ml +++ b/jscomp/ext/literals.ml @@ -32,6 +32,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" diff --git a/jscomp/ext/literals.mli b/jscomp/ext/literals.mli index d3e3de6980..c298775c0c 100644 --- a/jscomp/ext/literals.mli +++ b/jscomp/ext/literals.mli @@ -31,6 +31,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string diff --git a/jscomp/others/js_null_undefined.ml b/jscomp/others/js_null_undefined.ml index c4d10ad0d4..0d19d58017 100644 --- a/jscomp/others/js_null_undefined.ml +++ b/jscomp/others/js_null_undefined.ml @@ -29,8 +29,8 @@ external toOption : 'a t -> 'a option = "#null_undefined_to_opt" external to_opt : 'a t -> 'a option = "#null_undefined_to_opt" external return : 'a -> 'a t = "%identity" external test : 'a t -> bool = "#is_nil_undef" -external null : 'a t = "null" [@@bs.val] -external undefined : 'a t = "undefined" [@@bs.val] +external null : 'a t = "#null" +external undefined : 'a t = "#undefined" let bind x f = match to_opt x with diff --git a/jscomp/others/js_null_undefined.mli b/jscomp/others/js_null_undefined.mli index 6dd23b350c..56fadbff75 100644 --- a/jscomp/others/js_null_undefined.mli +++ b/jscomp/others/js_null_undefined.mli @@ -34,10 +34,10 @@ external return : 'a -> 'a t = "%identity" external test : 'a t -> bool = "#is_nil_undef" (** The [null] value of type ['a Js.null_undefined]*) -external null : 'a t = "null" [@@bs.val] +external null : 'a t = "#null" (** The [undefined] value of type ['a Js.null_undefined] *) -external undefined : 'a t = "undefined" [@@bs.val] +external undefined : 'a t = "#undefined" diff --git a/jscomp/runtime/bs_string.ml b/jscomp/runtime/bs_string.ml index 69647a3f07..5be372dab5 100644 --- a/jscomp/runtime/bs_string.ml +++ b/jscomp/runtime/bs_string.ml @@ -45,8 +45,17 @@ external slice_rest : string -> int -> string = "slice" external index_of : string -> string -> int = "indexOf" [@@bs.send] external append : string -> string -> string = "#string_append" -external of_small_int_array : int array -> string = "#string_of_small_int_array" -external of_small_int32_array : int32 array -> string = "#string_of_small_int_array" +external of_small_int_array : + (_ [@bs.as {json|null|json}] ) -> + int array -> string = + "String.fromCharCode.apply" +[@@bs.val] + +external of_small_int32_array : + int32 array -> string = + "String.fromCharCode" +[@@bs.val] [@@bs.splice] + external lastIndexOf : string -> string -> int = "lastIndexOf" [@@bs.send] external of_any : 'a -> string = "String" diff --git a/jscomp/stdlib/array.ml b/jscomp/stdlib/array.ml index 243eeade17..8d6d5aadcd 100644 --- a/jscomp/stdlib/array.ml +++ b/jscomp/stdlib/array.ml @@ -21,7 +21,12 @@ external unsafe_set: 'a array -> int -> 'a -> unit = "%array_unsafe_set" external make: int -> 'a -> 'a array = "caml_make_vect" external create: int -> 'a -> 'a array = "caml_make_vect" external unsafe_sub : 'a array -> int -> int -> 'a array = "caml_array_sub" +#if BS then +external append_prim : 'a array -> 'a array -> 'a array = "concat" +[@@bs.send] +#else external append_prim : 'a array -> 'a array -> 'a array = "caml_array_append" +#end external concat : 'a array list -> 'a array = "caml_array_concat" external unsafe_blit : 'a array -> int -> 'a array -> int -> int -> unit = "caml_array_blit" diff --git a/jscomp/test/.depend b/jscomp/test/.depend index ab49dcecc2..38d30d61b0 100644 --- a/jscomp/test/.depend +++ b/jscomp/test/.depend @@ -311,6 +311,7 @@ gpr_2614_test.cmj : gpr_2633_test.cmj : gpr_2642_test.cmj : gpr_2652_test.cmj : ../others/node.cmj ../stdlib/buffer.cmj +gpr_2700_test.cmj : gpr_405_test.cmj : ../stdlib/hashtbl.cmj gpr_405_test.cmi gpr_441.cmj : gpr_459_test.cmj : mt.cmj diff --git a/jscomp/test/Makefile b/jscomp/test/Makefile index 52fcd4a8db..105721d2d1 100644 --- a/jscomp/test/Makefile +++ b/jscomp/test/Makefile @@ -249,6 +249,7 @@ OTHERS := test_literals a test_ari test_export2 test_internalOO test_obj_simple_ gpr_2642_test\ gpr_2652_test\ gpr_2614_test\ + gpr_2700_test\ # bs_uncurry_test # needs Lam to get rid of Uncurry arity first # simple_derive_test diff --git a/jscomp/test/bang_primitive.js b/jscomp/test/bang_primitive.js index 02db9387b8..1de53f634d 100644 --- a/jscomp/test/bang_primitive.js +++ b/jscomp/test/bang_primitive.js @@ -14,7 +14,7 @@ function test(x, y) { function f(x, _) { return /* tuple */[ - String.fromCharCode.apply(null,x), + String.fromCharCode.apply(null, x), 0 ]; } diff --git a/jscomp/test/bang_primitive.ml b/jscomp/test/bang_primitive.ml index 447f214a7a..1c6ab6d23e 100644 --- a/jscomp/test/bang_primitive.ml +++ b/jscomp/test/bang_primitive.ml @@ -35,7 +35,12 @@ external append : 'a array -> 'a array -> 'a array = "#array_append" let f x y = append x y *) -external of_small_int_array : int array -> string = "#string_of_small_int_array" +external of_small_int_array : + (_ [@bs.as {json|null|json}] ) -> + int array -> string = + "String.fromCharCode.apply" +[@@bs.val] + (* external string_of_char : char -> string = "#string_of_char" *) (* string_of_char y *) diff --git a/jscomp/test/gpr_1484.js b/jscomp/test/gpr_1484.js index c0e9fac5f8..27e856c65c 100644 --- a/jscomp/test/gpr_1484.js +++ b/jscomp/test/gpr_1484.js @@ -2,7 +2,7 @@ function test(x) { - x.nodeValue = (null); + x.nodeValue = null; return /* () */0; } diff --git a/jscomp/test/gpr_2700_test.js b/jscomp/test/gpr_2700_test.js new file mode 100644 index 0000000000..886e951c8a --- /dev/null +++ b/jscomp/test/gpr_2700_test.js @@ -0,0 +1,13 @@ +'use strict'; + + +function f(x) { + if (x === 3) { + return true; + } else { + return x === 4; + } +} + +exports.f = f; +/* No side effect */ diff --git a/jscomp/test/gpr_2700_test.ml b/jscomp/test/gpr_2700_test.ml new file mode 100644 index 0000000000..a08820c13c --- /dev/null +++ b/jscomp/test/gpr_2700_test.ml @@ -0,0 +1,4 @@ + + + +let f x = x = 3 || x = 4 \ No newline at end of file diff --git a/jscomp/test/js_null_test.js b/jscomp/test/js_null_test.js index f24ae1a333..0ba403c824 100644 --- a/jscomp/test/js_null_test.js +++ b/jscomp/test/js_null_test.js @@ -10,7 +10,7 @@ var suites_000 = /* tuple */[ (function () { return /* Eq */Block.__(0, [ /* None */0, - null === null ? /* None */0 : [null] + /* None */0 ]); }) ]; @@ -31,7 +31,7 @@ var suites_001 = /* :: */[ (function () { return /* Eq */Block.__(0, [ /* None */0, - null === null ? /* None */0 : [null] + /* None */0 ]); }) ], diff --git a/jscomp/test/js_undefined_test.js b/jscomp/test/js_undefined_test.js index 826cee0da4..7f8e79b5d4 100644 --- a/jscomp/test/js_undefined_test.js +++ b/jscomp/test/js_undefined_test.js @@ -10,7 +10,7 @@ var suites_000 = /* tuple */[ (function () { return /* Eq */Block.__(0, [ /* None */0, - undefined === undefined ? /* None */0 : [undefined] + /* None */0 ]); }) ]; diff --git a/jscomp/test/test_per.js b/jscomp/test/test_per.js index 900e09542b..b9f793f670 100644 --- a/jscomp/test/test_per.js +++ b/jscomp/test/test_per.js @@ -131,7 +131,7 @@ function bool_of_string(param) { } function string_of_int(n) { - return "" + n; + return Caml_format.caml_format_int("%d", n); } function valid_float_lexem(s) { @@ -438,7 +438,7 @@ function print_bytes(s) { } function print_int(i) { - return output_string(stdout, "" + i); + return output_string(stdout, Caml_format.caml_format_int("%d", i)); } function print_float(f) { @@ -469,7 +469,7 @@ function prerr_bytes(s) { } function prerr_int(i) { - return output_string(stderr, "" + i); + return output_string(stderr, Caml_format.caml_format_int("%d", i)); } function prerr_float(f) { diff --git a/lib/bsb.ml b/lib/bsb.ml index a5a83c7bac..be71463476 100644 --- a/lib/bsb.ml +++ b/lib/bsb.ml @@ -3376,6 +3376,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string @@ -3510,6 +3511,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" diff --git a/lib/bsb_helper.ml b/lib/bsb_helper.ml index ef1c0a26b8..9ac1a2792c 100644 --- a/lib/bsb_helper.ml +++ b/lib/bsb_helper.ml @@ -3360,6 +3360,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string @@ -3494,6 +3495,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" diff --git a/lib/bsdep.ml b/lib/bsdep.ml index 3fca73d989..150034bf45 100644 --- a/lib/bsdep.ml +++ b/lib/bsdep.ml @@ -27873,6 +27873,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string @@ -28007,6 +28008,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" diff --git a/lib/bsppx.ml b/lib/bsppx.ml index 277b4109f7..d736f918a1 100644 --- a/lib/bsppx.ml +++ b/lib/bsppx.ml @@ -9815,6 +9815,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string @@ -9949,6 +9950,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" diff --git a/lib/js/array.js b/lib/js/array.js index a7dfc2ecef..185d81e57d 100644 --- a/lib/js/array.js +++ b/lib/js/array.js @@ -279,7 +279,7 @@ function sort(cmp, a) { Caml_builtin_exceptions.assert_failure, [ "array.ml", - 168, + 173, 4 ] ]; diff --git a/lib/js/caml_string.js b/lib/js/caml_string.js index 993e015fbf..a80b7e3143 100644 --- a/lib/js/caml_string.js +++ b/lib/js/caml_string.js @@ -129,14 +129,14 @@ function bytes_to_string(a) { var s = ""; var s_len = len; if (i === 0 && len <= 4096 && len === bytes.length) { - return String.fromCharCode.apply(null,bytes); + return String.fromCharCode.apply(null, bytes); } else { var offset = 0; while(s_len > 0) { var next = s_len < 1024 ? s_len : 1024; var tmp_bytes = new Array(next); caml_blit_bytes(bytes, offset, tmp_bytes, 0, next); - s = s + String.fromCharCode.apply(null,tmp_bytes); + s = s + String.fromCharCode.apply(null, tmp_bytes); s_len = s_len - next | 0; offset = offset + next | 0; }; diff --git a/lib/whole_compiler.ml b/lib/whole_compiler.ml index ea1d40da01..4ba0f25a58 100644 --- a/lib/whole_compiler.ml +++ b/lib/whole_compiler.ml @@ -24857,6 +24857,7 @@ val js_array_ctor : string val js_type_number : string val js_type_string : string val js_type_object : string +val js_type_boolean : string val js_undefined : string val js_prop_length : string @@ -24991,6 +24992,7 @@ let js_array_ctor = "Array" let js_type_number = "number" let js_type_string = "string" let js_type_object = "object" +let js_type_boolean = "boolean" let js_undefined = "undefined" let js_prop_length = "length" @@ -60340,9 +60342,9 @@ val make_unused : unit -> Ident.t val convert : string -> string -val undefined : Ident.t + val is_js_or_global : Ident.t -> bool - val nil : Ident.t + val compare : Ident.t -> Ident.t -> int @@ -60664,9 +60666,6 @@ let reset () = String_hashtbl.clear js_module_table -let undefined = create_js "undefined" -let nil = create_js "null" - (* Has to be total order, [x < y] and [x > y] should be consistent flags are not relevant here @@ -63301,68 +63300,17 @@ and expression_desc = | Length of expression * length_object | Char_of_int of expression | Char_to_int of expression - | Is_null_undefined_to_boolean of expression + | Is_null_or_undefined of expression (** where we use a trick [== null ] *) - | Array_of_size of expression - (* used in [#create_array] primitive, note having - uninitilized array is not as bad as in ocaml, - since GC does not rely on it - *) | Array_copy of expression (* shallow copy, like [x.slice] *) - | Array_append of expression * expression (* For [caml_array_append]*) - (* | Tag_ml_obj of expression *) - | String_append of expression * expression - | Anything_to_number of expression + | String_append of expression * expression | Bool of bool (* js true/false*) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence [typeof] is an operator *) | Typeof of expression | Js_not of expression (* !v *) - | String_of_small_int_array of expression - (* String.fromCharCode.apply(null, args) *) - (* Convert JS boolean into OCaml boolean - like [+true], note this ast talks using js - terminnology unless explicity stated - *) - | Json_stringify of expression - (* TODO: in the future, it might make sense to group primitivie by type, - which makes optimizations easier - {[ JSON.stringify(value, replacer[, space]) ]} - *) - | Anything_to_string of expression - (* for debugging utitlites, - TODO: [Dump] is not necessary with this primitive - Note that the semantics is slightly different from [JSON.stringify] - {[ - JSON.stringify("x") - ]} - {[ - ""x"" - ]} - {[ - JSON.stringify(undefined) - ]} - {[ - undefined - ]} - {[ '' + undefined - ]} - {[ 'undefined' - ]} - *) - | Dump of Js_op.level * expression list - (* TODO: - add - {[ Assert of bool * expression ]} - *) - (* to support - val log1 : 'a -> unit - val log2 : 'a -> 'b -> unit - val log3 : 'a -> 'b -> 'c -> unit - *) - (* TODO: Add some primitives so that [js inliner] can do a better job *) | Seq of expression * expression | Cond of expression * expression * expression @@ -63377,11 +63325,6 @@ and expression_desc = if it's know at compile time, we can turn it into f(args[0], args[1], ... ) *) - | Bind of expression * expression - (* {[ Bind (a,b) ]} - is literally - {[ a.bind(b) ]} - *) | Call of expression * expression list * Js_call_info.t (* Analysze over J expression is hard since, some primitive call is translated @@ -63449,7 +63392,8 @@ and expression_desc = *) | Number of number | Object of property_map - + | Undefined + | Null and for_ident_expression = expression (* pure*) and finish_ident_expression = expression (* pure *) @@ -66747,9 +66691,6 @@ type primitive = | Pjs_typeof | Pjs_function_length - - | Pjs_string_of_small_array - (* | Pjs_is_instance_array *) | Pcaml_obj_length | Pcaml_obj_set_length | Pwrap_exn (* convert either JS exception or OCaml exception into OCaml format *) @@ -67110,9 +67051,6 @@ type primitive = | Pis_null_undefined | Pjs_typeof | Pjs_function_length - - | Pjs_string_of_small_array - (* | Pjs_is_instance_array *) | Pcaml_obj_length | Pcaml_obj_set_length | Pwrap_exn (* convert either JS exception or OCaml exception into OCaml format *) @@ -68779,12 +68717,6 @@ let convert exports lam : _ * _ = | "#null_to_opt" -> Pnull_to_opt | "#is_nil_undef" -> Pis_null_undefined | "#string_append" -> Pstringadd - - - | "#string_of_small_int_array" -> Pjs_string_of_small_array - (* {[String.fromCharCode.apply(null,x)]} - Note if we have better suport [@bs.splice], - we can get rid of it*) | "#obj_set_length" -> Pcaml_obj_set_length | "#obj_length" -> Pcaml_obj_length | "#function_length" -> Pjs_function_length @@ -69613,54 +69545,11 @@ class virtual fold = ]} *) (** where we use a trick [== null ] *) - (* used in [#create_array] primitive, note having - uninitilized array is not as bad as in ocaml, - since GC does not rely on it - *) - (* shallow copy, like [x.slice] *) - (* For [caml_array_append]*) - (* | Tag_ml_obj of expression *) (* js true/false*) + (* shallow copy, like [x.slice] *) (* js true/false*) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence [typeof] is an operator *) - (* !v *) (* String.fromCharCode.apply(null, args) *) - (* Convert JS boolean into OCaml boolean - like [+true], note this ast talks using js - terminnology unless explicity stated - *) - (* TODO: in the future, it might make sense to group primitivie by type, - which makes optimizations easier - {[ JSON.stringify(value, replacer[, space]) ]} - *) - (* for debugging utitlites, - TODO: [Dump] is not necessary with this primitive - Note that the semantics is slightly different from [JSON.stringify] - {[ - JSON.stringify("x") - ]} - {[ - ""x"" - ]} - {[ - JSON.stringify(undefined) - ]} - {[ - undefined - ]} - {[ '' + undefined - ]} - {[ 'undefined' - ]} - *) - (* TODO: - add - {[ Assert of bool * expression ]} - *) - (* to support - val log1 : 'a -> unit - val log2 : 'a -> 'b -> unit - val log3 : 'a -> 'b -> 'c -> unit - *) + (* !v *) (* TODO: Add some primitives so that [js inliner] can do a better job *) (* [int_op] will guarantee return [int32] bits https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *) @@ -69670,10 +69559,6 @@ class virtual fold = if it's know at compile time, we can turn it into f(args[0], args[1], ... ) *) - (* {[ Bind (a,b) ]} - is literally - {[ a.bind(b) ]} - *) (* Analysze over J expression is hard since, some primitive call is translated into a plain call, it's better to keep them @@ -69854,23 +69739,13 @@ class virtual fold = let o = o#expression _x in let o = o#length_object _x_i1 in o | Char_of_int _x -> let o = o#expression _x in o | Char_to_int _x -> let o = o#expression _x in o - | Is_null_undefined_to_boolean _x -> let o = o#expression _x in o - | Array_of_size _x -> let o = o#expression _x in o + | Is_null_or_undefined _x -> let o = o#expression _x in o | Array_copy _x -> let o = o#expression _x in o - | Array_append (_x, _x_i1) -> - let o = o#expression _x in let o = o#expression _x_i1 in o | String_append (_x, _x_i1) -> let o = o#expression _x in let o = o#expression _x_i1 in o - | Anything_to_number _x -> let o = o#expression _x in o | Bool _x -> let o = o#bool _x in o | Typeof _x -> let o = o#expression _x in o | Js_not _x -> let o = o#expression _x in o - | String_of_small_int_array _x -> let o = o#expression _x in o - | Json_stringify _x -> let o = o#expression _x in o - | Anything_to_string _x -> let o = o#expression _x in o - | Dump (_x, _x_i1) -> - let o = o#unknown _x in - let o = o#list (fun o -> o#expression) _x_i1 in o | Seq (_x, _x_i1) -> let o = o#expression _x in let o = o#expression _x_i1 in o | Cond (_x, _x_i1, _x_i2) -> @@ -69881,8 +69756,6 @@ class virtual fold = let o = o#expression _x_i1 in let o = o#expression _x_i2 in o | FlatCall (_x, _x_i1) -> let o = o#expression _x in let o = o#expression _x_i1 in o - | Bind (_x, _x_i1) -> - let o = o#expression _x in let o = o#expression _x_i1 in o | Call (_x, _x_i1, _x_i2) -> let o = o#expression _x in let o = o#list (fun o -> o#expression) _x_i1 in @@ -69921,6 +69794,8 @@ class virtual fold = let o = o#expression _x in let o = o#expression _x_i1 in o | Number _x -> let o = o#number _x in o | Object _x -> let o = o#property_map _x in o + | Undefined -> o + | Null -> o method expression : expression -> 'self_type = fun { expression_desc = _x; comment = _x_i1 } -> let o = o#expression_desc _x in @@ -70138,13 +70013,15 @@ let free_variables_of_expression used_idents defined_idents st = let rec no_side_effect_expression_desc (x : J.expression_desc) = match x with + | Undefined + | Null | Bool _ | Var _ | Unicode _ -> true | Fun _ -> true | Number _ -> true (* Can be refined later *) | Access (a,b) -> no_side_effect a && no_side_effect b - | Is_null_undefined_to_boolean b -> no_side_effect b + | Is_null_or_undefined b -> no_side_effect b | Str (b,_) -> b | Array (xs,_mutable_flag) | Caml_block (xs, _mutable_flag, _, _) @@ -70155,10 +70032,8 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = the block is mutable does not mean this operation is non-pure *) List.for_all no_side_effect xs - | Bind(fn, obj) -> no_side_effect fn && no_side_effect obj | Object kvs -> List.for_all (fun (_property_name, y) -> no_side_effect y ) kvs - | Array_append (a,b) | String_append (a,b) | Seq (a,b) -> no_side_effect a && no_side_effect b | Length (e, _) @@ -70170,15 +70045,8 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = | Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b | Math _ - | Array_of_size _ | Array_copy _ - (* | Tag_ml_obj _ *) - | J.Anything_to_number _ | Js_not _ - | String_of_small_int_array _ - | Json_stringify _ - | Anything_to_string _ - | Dump _ | Cond _ | FlatCall _ @@ -70239,6 +70107,8 @@ let rec eq_expression ({expression_desc = x0} : J.expression) ({expression_desc = y0} : J.expression) = begin match x0 with + | Null -> y0 = Null + | Undefined -> y0 = Undefined | Number (Int i) -> begin match y0 with | Number (Int j) -> i = j @@ -70299,12 +70169,6 @@ let rec eq_expression p0 = p1 && b0 = b1 && eq_expression e0 e1 | _ -> false end - | Dump (l0,es0) -> - begin match y0 with - | Dump(l1,es1) -> - l0 = l1 && eq_expression_list es0 es1 - | _ -> false - end | Seq (a0,b0) -> begin match y0 with | Seq(a1,b1) -> @@ -70319,23 +70183,13 @@ let rec eq_expression | Length _ | Char_of_int _ | Char_to_int _ - | Is_null_undefined_to_boolean _ - | Array_of_size _ + | Is_null_or_undefined _ | Array_copy _ - | Array_append _ | String_append _ - | Anything_to_number _ - | Typeof _ | Js_not _ - | String_of_small_int_array _ - | Json_stringify _ - | Anything_to_string _ - - | Cond _ | FlatCall _ - | Bind _ | String_access _ | New _ @@ -70965,8 +70819,6 @@ val array_length : unary_op val string_length : unary_op -val string_of_small_int_array : unary_op - val bytes_length : unary_op val function_length : unary_op @@ -70974,9 +70826,6 @@ val function_length : unary_op val char_of_int : unary_op val char_to_int : unary_op - -val array_append : binary_op - val array_copy : unary_op val string_append : binary_op (** @@ -71075,15 +70924,6 @@ val call : ?comment:string -> info:Js_call_info.t -> t -> t list -> t val flat_call : binary_op -val dump : ?comment:string -> Js_op.level -> t list -> t - - - -(** see {!https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus}*) -(* val to_number : unary_op *) -val int_to_string : unary_op - - val new_ : ?comment:string -> J.expression -> J.expression list -> t val array : @@ -71134,7 +70974,7 @@ val is_caml_block : ?comment:string -> t -> t val tag : ?comment:string -> J.expression -> t -val set_tag : ?comment:string -> J.expression -> J.expression -> t +val block_set_tag : ?comment:string -> J.expression -> J.expression -> t (** Note that this is coupled with how we encode block, if we use the `Object.defineProperty(..)` since the array already hold the length, @@ -71258,10 +71098,11 @@ let var ?comment id : t = let js_global ?comment (v : string) = var ?comment (Ext_ident.create_js v ) -let undefined = var Ext_ident.undefined - -let nil = var Ext_ident.nil +let undefined : t = + {expression_desc = Undefined ; comment = None} +let nil : t = + {expression_desc = Null ; comment = None} let call ?comment ~info e0 args : t = {expression_desc = Call(e0,args,info); comment } @@ -71344,14 +71185,6 @@ let make_block ?comment tag tag_info es mutable_flag : t = comment } -(* let uninitialized_object ?comment tag size : t = - { expression_desc = Caml_uninitialized_obj(tag,size); comment } *) - -(* let uninitialized_array ?comment (e : t) : t = - match e.expression_desc with - | Number (Int {i = 0l; _}) -> array ?comment NA [] - | _ -> {comment; expression_desc = Array_of_size e} *) - module L = Literals (* Invariant: this is relevant to how we encode string @@ -71365,6 +71198,7 @@ let typeof ?comment (e : t) : t = -> str ?comment L.js_type_string | Array _ -> str ?comment L.js_type_object + | Bool _ -> str ?comment L.js_type_boolean | _ -> {expression_desc = Typeof e ; comment } @@ -71393,8 +71227,6 @@ let math ?comment v args : t = Used in [string_of_int] and format "%d" TODO: optimize *) -let int_to_string ?comment (e : t) : t = - {expression_desc = Anything_to_string e ; comment} (* Attention: Shared *mutable state* is evil, [Js_fun_env.empty] is a mutable state .. @@ -71619,22 +71451,10 @@ let char_to_int ?comment (v : t) : t = | Char_of_int v -> v | _ -> {comment; expression_desc = Char_to_int v } -let array_append ?comment e el : t = - { comment ; expression_desc = Array_append (e, el)} let array_copy ?comment e : t = { comment ; expression_desc = Array_copy e} -(* Note that this return [undefined] in JS, - it should be wrapped to avoid leak [undefined] into - OCaml -*) -let dump ?comment level el : t = - {comment ; expression_desc = Dump(level,el)} - -(* let to_json_string ?comment e : t = - { comment; expression_desc = Json_stringify e } *) - let rec string_append ?comment (e : t) (el : t) : t = match e.expression_desc , el.expression_desc with | Str(_,a), String_append ({expression_desc = Str(_,b)}, c) -> @@ -71645,8 +71465,6 @@ let rec string_append ?comment (e : t) (el : t) : t = String_append ({expression_desc = Str(_,c)} ,d) -> string_append ?comment (string_append a (str (b ^ c))) d | Str (_,a), Str (_,b) -> str ?comment (a ^ b) - | _, Anything_to_string b -> string_append ?comment e b - | Anything_to_string b, _ -> string_append ?comment b el | _, _ -> {comment ; expression_desc = String_append(e,el)} @@ -71690,17 +71508,17 @@ let float_mod ?comment e1 e2 : J.expression = *) let rec triple_equal ?comment (e0 : t) (e1 : t ) : t = match e0.expression_desc, e1.expression_desc with - | Var (Id ({name = "undefined"|"null"} as id)), + | (Null| Undefined), (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ) - when Ext_ident.is_js id && no_side_effect e1 -> + when no_side_effect e1 -> caml_false (* TODO: rename it as [caml_false] *) | (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ - | Fun _ | Array _ | Caml_block _ ), Var (Id ({name = "undefined"|"null"; } as id)) - when Ext_ident.is_js id && no_side_effect e0 -> + | Fun _ | Array _ | Caml_block _ ), (Null|Undefined) + when no_side_effect e0 -> caml_false | Str (_,x), Str (_,y) -> (* CF*) bool (Ext_string.equal x y) @@ -71714,6 +71532,10 @@ let rec triple_equal ?comment (e0 : t) (e1 : t ) : t = bool (i0 = i1) | Char_of_int a , Char_of_int b -> triple_equal ?comment a b + | Null, Undefined + | Undefined, Null -> caml_false + | Null, Null + | Undefined, Undefined -> caml_true | _ -> {expression_desc = Bin(EqEqEq, e0,e1); comment} @@ -71722,14 +71544,7 @@ let bin ?comment (op : J.binop) e0 e1 : t = | EqEqEq -> triple_equal ?comment e0 e1 | _ -> {expression_desc = Bin(op,e0,e1); comment} -(* | (Bin (NotEqEq, e1, *) -(* {expression_desc = Var (Id ({name = "undefined"; _} as id))}) *) -(* | Bin (NotEqEq, *) -(* {expression_desc = Var (Id ({name = "undefined"; _} as id))}, *) -(* e1) *) -(* ), *) -(* _ when Ext_ident.is_js id -> *) -(* and_ e1 e2 *) + (* TODO: Constant folding, Google Closure will do that?, Even if Google Clsoure can do that, we will see how it interact with other optimizations @@ -71946,11 +71761,6 @@ let is_type_number ?comment (e : t) : t = string_equal ?comment (typeof e) (str "number") -let string_of_small_int_array ?comment xs : t = - {expression_desc = String_of_small_int_array xs; comment} - - - (* we are calling [Caml_primitive.primitive_name], since it's under our control, we should make it follow the javascript name convention, and call plain [dot] @@ -72012,7 +71822,7 @@ let public_method_call meth_name obj label cache args = (* [fn ; arr NA args ] *) (* ) *) -let set_tag ?comment e tag : t = +let block_set_tag ?comment e tag : t = seq {expression_desc = Caml_block_set_tag (e,tag); comment } unit @@ -72416,47 +72226,47 @@ let of_block ?comment ?e block : t = , Js_fun_env.empty 0) } [] -let is_null ?comment x = triple_equal ?comment x nil +let is_null ?comment (x : t) = + triple_equal ?comment x nil let is_undef ?comment x = triple_equal ?comment x undefined let for_sure_js_null_undefined (x : t) = match x.expression_desc with - | Var (Id ({name = "undefined" | "null"} as id)) - -> Ext_ident.is_js id + | Null | Undefined + -> true | _ -> false let is_null_undefined ?comment (x: t) : t = match x.expression_desc with - | Var (Id ({name = "undefined" | "null"} as id)) - when Ext_ident.is_js id + | Null | Undefined -> caml_true | Number _ | Array _ | Caml_block _ -> caml_false - | _ -> - + | _ -> { comment ; - expression_desc = Is_null_undefined_to_boolean x + expression_desc = Is_null_or_undefined x } let eq_null_undefined_boolean ?comment (a : t) (b : t) = match a.expression_desc, b.expression_desc with - | Var (Id ({name = "null" | "undefined"} as id) ), + | (Null | Undefined), (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ) - when Ext_ident.is_js id -> + -> caml_false | (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ), - Var (Id ({name = "null" | "undefined"} as id) ) - when Ext_ident.is_js id -> + (Null | Undefined) + -> caml_false - | Var (Id ({name = "null" | "undefined" as n1 } as id1) ), - Var (Id ({name = "null" | "undefined" as n2 } as id2) ) - when Ext_ident.is_js id1 && Ext_ident.is_js id2 - -> bool (n1 = n2) + | (Null, Undefined) + | (Undefined, Null) -> caml_false + | (Null, Null) + | (Undefined, Undefined) + -> caml_true | _ -> {expression_desc = Bin(EqEqEq, a, b); comment} @@ -72464,23 +72274,24 @@ let eq_null_undefined_boolean ?comment (a : t) (b : t) = let neq_null_undefined_boolean ?comment (a : t) (b : t) = match a.expression_desc, b.expression_desc with - | Var (Id ({name = "null" | "undefined"} as id) ), + | (Null | Undefined), (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ) - when Ext_ident.is_js id -> + -> caml_true | (Char_of_int _ | Char_to_int _ | Bool _ | Number _ | Typeof _ | Fun _ | Array _ | Caml_block _ ), - Var (Id ({name = "null" | "undefined"} as id) ) - when Ext_ident.is_js id -> + (Null | Undefined) + -> caml_true - | Var (Id ({name = "null" | "undefined" as n1 } as id1) ), - Var (Id ({name = "null" | "undefined" as n2 } as id2) ) - when Ext_ident.is_js id1 && Ext_ident.is_js id2 - -> - if n1 <> n2 then caml_true else caml_false + | (Null , Null ) + | (Undefined, Undefined) + -> caml_false + | (Null, Undefined) + | (Undefined, Null) + -> caml_true | _ -> {expression_desc = Bin(NotEqEq, a, b); comment} @@ -72647,8 +72458,6 @@ let primitive ppf (prim : Lam.primitive) = match prim with (* | Pcreate_exception s -> fprintf ppf "[exn-create]%S" s *) | Pcreate_extension s -> fprintf ppf "[ext-create]%S" s | Pwrap_exn -> fprintf ppf "#exn" - | Pjs_string_of_small_array -> fprintf ppf "#string_of_small_array" - (* | Pjs_is_instance_array -> fprintf ppf "#is_instance_array" *) | Pcaml_obj_length -> fprintf ppf "#obj_length" | Pcaml_obj_set_length -> fprintf ppf "#obj_set_length" | Pinit_mod -> fprintf ppf "init_mod!" @@ -73614,11 +73423,7 @@ let rec if_ ?comment ?declaration ?else_ (e : J.expression) (then_ : J.block) | Bin (Bor , {expression_desc = Number (Int { i = 0l ; _})}, a), _, _ -> aux ?comment a then_ else_ acc - (* | Bin (NotEqEq, e1, *) - (* {expression_desc = Var (Id ({name = "undefined"; _} as id))}), *) - (* _, _ *) - (* when Ext_ident.is_js id -> *) - (* aux ?comment e1 then_ else_ acc *) + | ((Bin (Gt, ({expression_desc = @@ -83757,6 +83562,7 @@ let bind = "bind" let math = "Math" let apply = "apply" let null = "null" +let undefined = "undefined" let string_cap = "String" let fromCharcode = "fromCharCode" let eq = "=" @@ -84646,6 +84452,11 @@ and expression l cxt f (exp : J.expression) : Ext_pp_scope.t = and expression_desc cxt (l:int) f x : Ext_pp_scope.t = match x with + | Null -> + P.string f L.null; cxt + | Undefined + -> + P.string f L.undefined; cxt | Var v -> vident cxt f v | Bool b -> @@ -84701,16 +84512,7 @@ and in if l > 15 then P.paren_group f 1 action else action () - | Bind (a,b) -> - (* a.bind(b) - {[ fun b -> a.bind(b) ==? a.bind ]} - *) - begin - expression_desc cxt l f - (Call ({expression_desc = Dot(a,L.bind, true); comment = None }, [b], - {arity = Full; call_info = Call_na})) - end - + | FlatCall(e,el) -> P.group f 1 (fun _ -> let cxt = expression 15 cxt f e in @@ -84723,34 +84525,6 @@ and expression 1 cxt f el ) ) - | String_of_small_int_array ({expression_desc = desc } as e) -> - let action () = - P.group f 1 (fun _ -> - P.string f L.string_cap; - P.string f L.dot ; - P.string f L.fromCharcode; - begin match desc with - | Array (el, _mutable) - -> - P.paren_group f 1 (fun _ -> arguments cxt f el) - | _ -> - P.string f L.dot ; - P.string f L.apply; - P.paren_group f 1 (fun _ -> - P.string f L.null; - P.string f L.comma; - expression 1 cxt f e ) - end ) - in - if l > 15 then P.paren_group f 1 action - else action () - - - | Array_append (e, el) -> - P.group f 1 (fun _ -> - let cxt = expression 15 cxt f e in - P.string f ".concat"; - P.paren_group f 1 (fun _ -> arguments cxt f [el])) | Array_copy e -> P.group f 1 (fun _ -> @@ -84759,27 +84533,6 @@ and P.string f "()" ; cxt ) - - | Dump (level, el) -> - let obj = - match level with - | Log -> "log" - | Info -> "info" - | Warn -> "warn" - | Error -> "error" in - P.group f 1 (fun _ -> - P.string f L.console; - P.string f L.dot; - P.string f obj ; - P.paren_group f 1 (fun _ -> arguments cxt f el)) - | Json_stringify e - -> - P.group f 1 (fun _ -> - P.string f L.json ; - P.string f L.dot; - P.string f L.stringify; - P.paren_group f 1 (fun _ -> expression 0 cxt f e ) - ) | Char_to_int e -> begin match e.expression_desc with | String_access (a,b) -> @@ -84865,20 +84618,7 @@ and else action () ); cxt - | J.Anything_to_number e - -> - let action () = - P.group f 0 @@ fun _ -> - P.string f "+" ; - expression 13 cxt f e - in - (* need to tweak precedence carefully - here [++x --> +(+x)] - *) - if l > 12 - then P.paren_group f 1 action - else action () - | Is_null_undefined_to_boolean e -> + | Is_null_or_undefined e -> let action = (fun _ -> let cxt = expression 1 cxt f e in P.space f ; @@ -85016,11 +84756,6 @@ and P.space f ; expression 13 cxt f delta end - | Anything_to_string e -> - (* Note that we should not apply any smart construtor here, - it's purely a convenice for pretty-printing - *) - expression_desc cxt l f (Bin (Plus, E.empty_string_literal , e)) | Bin (Minus, {expression_desc = Number (Int {i=0l;_} | Float {f = "0."})}, e) (* TODO: @@ -85154,16 +84889,6 @@ and in if l > 15 then P.paren_group f 1 action else action () - | Array_of_size e -> - let action () = - P.group f 1 @@ fun _ -> - P.string f L.new_; - P.space f; - P.string f L.array; - P.paren_group f 1 @@ fun _ -> expression 0 cxt f e - in - if l > 15 then P.paren_group f 1 action else action () - | Cond (e, e1, e2) -> let action () = (* P.group f 1 @@ fun _ -> *) @@ -85344,39 +85069,33 @@ and statement_desc top cxt f (s : J.statement_desc) : Ext_pp_scope.t = | Caml_block_set_tag _ | Length _ | Caml_block_set_length _ - | Anything_to_string _ - | String_of_small_int_array _ | Call _ - | Array_append _ | Array_copy _ | Caml_block_tag _ | Seq _ | Dot _ | Cond _ | Bin _ - | Is_null_undefined_to_boolean _ + | Is_null_or_undefined _ | String_access _ | Access _ - | Array_of_size _ | String_append _ | Char_of_int _ | Char_to_int _ - | Dump _ - | Json_stringify _ | Math _ | Var _ + | Undefined + | Null | Str _ | Unicode _ | Array _ | Caml_block _ | FlatCall _ | Typeof _ - | Bind _ | Number _ | Js_not _ | Bool _ | New _ - | J.Anything_to_number _ -> false (* e = function(x){...}(x); is good *) @@ -86690,7 +86409,6 @@ let rec no_side_effects (lam : Lam.t) : bool = (* | Pjs_is_instance_array *) | Pwrap_exn -> true - | Pjs_string_of_small_array | Pcaml_obj_set_length | Pjs_apply | Pjs_runtime_apply @@ -87071,7 +86789,7 @@ and eq_primitive ( lhs : Lam.primitive) (rhs : Lam.primitive) = | Pupdate_mod -> rhs = Pupdate_mod | Pbswap16 -> rhs = Pbswap16 | Pjs_function_length -> rhs = Pjs_function_length - | Pjs_string_of_small_array -> rhs = Pjs_string_of_small_array + (* | Pjs_string_of_small_array -> rhs = Pjs_string_of_small_array *) (* | Pjs_is_instance_array -> rhs = Pjs_is_instance_array *) | Pcaml_obj_length -> rhs = Pcaml_obj_length | Pcaml_obj_set_length -> rhs = Pcaml_obj_set_length @@ -88383,54 +88101,11 @@ class virtual map = ]} *) (** where we use a trick [== null ] *) - (* used in [#create_array] primitive, note having - uninitilized array is not as bad as in ocaml, - since GC does not rely on it - *) - (* shallow copy, like [x.slice] *) - (* For [caml_array_append]*) - (* | Tag_ml_obj of expression *) (* js true/false*) + (* shallow copy, like [x.slice] *) (* js true/false*) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence [typeof] is an operator *) - (* !v *) (* String.fromCharCode.apply(null, args) *) - (* Convert JS boolean into OCaml boolean - like [+true], note this ast talks using js - terminnology unless explicity stated - *) - (* TODO: in the future, it might make sense to group primitivie by type, - which makes optimizations easier - {[ JSON.stringify(value, replacer[, space]) ]} - *) - (* for debugging utitlites, - TODO: [Dump] is not necessary with this primitive - Note that the semantics is slightly different from [JSON.stringify] - {[ - JSON.stringify("x") - ]} - {[ - ""x"" - ]} - {[ - JSON.stringify(undefined) - ]} - {[ - undefined - ]} - {[ '' + undefined - ]} - {[ 'undefined' - ]} - *) - (* TODO: - add - {[ Assert of bool * expression ]} - *) - (* to support - val log1 : 'a -> unit - val log2 : 'a -> 'b -> unit - val log3 : 'a -> 'b -> 'c -> unit - *) + (* !v *) (* TODO: Add some primitives so that [js inliner] can do a better job *) (* [int_op] will guarantee return [int32] bits https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators *) @@ -88440,10 +88115,6 @@ class virtual map = if it's know at compile time, we can turn it into f(args[0], args[1], ... ) *) - (* {[ Bind (a,b) ]} - is literally - {[ a.bind(b) ]} - *) (* Analysze over J expression is hard since, some primitive call is translated into a plain call, it's better to keep them @@ -88636,30 +88307,15 @@ class virtual map = let _x_i1 = o#length_object _x_i1 in Length (_x, _x_i1) | Char_of_int _x -> let _x = o#expression _x in Char_of_int _x | Char_to_int _x -> let _x = o#expression _x in Char_to_int _x - | Is_null_undefined_to_boolean _x -> - let _x = o#expression _x in Is_null_undefined_to_boolean _x - | Array_of_size _x -> let _x = o#expression _x in Array_of_size _x + | Is_null_or_undefined _x -> + let _x = o#expression _x in Is_null_or_undefined _x | Array_copy _x -> let _x = o#expression _x in Array_copy _x - | Array_append (_x, _x_i1) -> - let _x = o#expression _x in - let _x_i1 = o#expression _x_i1 in Array_append (_x, _x_i1) | String_append (_x, _x_i1) -> let _x = o#expression _x in let _x_i1 = o#expression _x_i1 in String_append (_x, _x_i1) - | Anything_to_number _x -> - let _x = o#expression _x in Anything_to_number _x | Bool _x -> let _x = o#bool _x in Bool _x | Typeof _x -> let _x = o#expression _x in Typeof _x | Js_not _x -> let _x = o#expression _x in Js_not _x - | String_of_small_int_array _x -> - let _x = o#expression _x in String_of_small_int_array _x - | Json_stringify _x -> let _x = o#expression _x in Json_stringify _x - | Anything_to_string _x -> - let _x = o#expression _x in Anything_to_string _x - | Dump (_x, _x_i1) -> - let _x = o#unknown _x in - let _x_i1 = o#list (fun o -> o#expression) _x_i1 - in Dump (_x, _x_i1) | Seq (_x, _x_i1) -> let _x = o#expression _x in let _x_i1 = o#expression _x_i1 in Seq (_x, _x_i1) @@ -88674,9 +88330,6 @@ class virtual map = | FlatCall (_x, _x_i1) -> let _x = o#expression _x in let _x_i1 = o#expression _x_i1 in FlatCall (_x, _x_i1) - | Bind (_x, _x_i1) -> - let _x = o#expression _x in - let _x_i1 = o#expression _x_i1 in Bind (_x, _x_i1) | Call (_x, _x_i1, _x_i2) -> let _x = o#expression _x in let _x_i1 = o#list (fun o -> o#expression) _x_i1 in @@ -88726,6 +88379,8 @@ class virtual map = let _x_i1 = o#expression _x_i1 in Caml_block_set_length (_x, _x_i1) | Number _x -> let _x = o#number _x in Number _x | Object _x -> let _x = o#property_map _x in Object _x + | Undefined -> Undefined + | Null -> Null method expression : expression -> expression = fun { expression_desc = _x; comment = _x_i1 } -> let _x = o#expression_desc _x in @@ -89907,7 +89562,7 @@ let subst name export_set stats = (* Mark a function as dead means it will never be scanned, here we inline the function *) - Ext_list.append block @@ self#block rest + Ext_list.append block (self#block rest) | (None | Some _) -> self#statement st :: self#block rest end @@ -89922,11 +89577,10 @@ let subst name export_set stats = let tailcall_inline (program : J.program) = - let _stats = get_stats program in - let _export_set = program.export_set in - program - |> (subst program.name _export_set _stats )# program - (* |> pass_beta #program *) + let stats = get_stats program in + let export_set = program.export_set in + (subst program.name export_set stats )#program program + end @@ -93462,7 +93116,7 @@ let translate_arg_cst (cst : External_arg_spec.cst) = E.int (Int32.of_int i) | Arg_string_lit i -> E.str i - | Arg_js_null -> E.raw_js_code Exp "null" + | Arg_js_null -> E.nil | Arg_js_json s -> E.raw_js_code Exp s @@ -94121,12 +93775,8 @@ let translate_ffi 2. support [@@bs.scope "window"] we need know whether we should call [add_js_module] or not *) - begin match name, handle_external_opt external_module_name , scopes with - | "null", None, [] -> E.nil - | "undefined", None, [] -> E.undefined - | _, _, _ -> - translate_scoped_module_val external_module_name name scopes - end + translate_scoped_module_val external_module_name name scopes + | Js_send {splice = js_splice ; name ; pipe = false; js_send_scopes = scopes } -> begin match args with | self :: args -> @@ -95059,13 +94709,6 @@ let translate loc (prim_name : string) | "caml_power_float" -> E.math "pow" args - - | "caml_array_append" -> - begin match args with - | [e0;e1] -> E.array_append e0 e1 - | _ -> assert false - end - | "caml_array_get" -> call Js_runtime_modules.array | "caml_array_get_addr" @@ -95580,8 +95223,6 @@ let translate loc (prim_name : string) *) | _ -> E.array_copy a end - (* if Js_analyzer.is_constant a then a - else E.array_copy a *) | _ -> assert false end | "caml_obj_block" -> @@ -95615,20 +95256,11 @@ let translate loc (prim_name : string) | "caml_nativeint_of_string" | "caml_int64_format" | "caml_int64_of_string" + | "caml_format_int" -> call Js_runtime_modules.format - | "caml_format_int" -> - begin match args with - | [ {expression_desc = Str (_, "%d"); _}; v] - -> - E.int_to_string v - | _ -> - call Js_runtime_modules.format - end (* "caml_alloc_dummy"; *) (* TODO: "caml_alloc_dummy_float"; *) - - | "caml_obj_is_block" -> begin match args with @@ -95685,7 +95317,7 @@ let translate loc (prim_name : string) call Js_runtime_modules.obj_runtime | "caml_obj_set_tag" -> begin match args with - | [a;b] -> E.set_tag a b + | [a;b] -> E.block_set_tag a b | _ -> assert false end | "caml_obj_tag" -> (* Note that in ocaml, [int] has tag [1000] and [string] has tag [252] @@ -95932,8 +95564,8 @@ let translate loc begin match args with | [e] -> begin match e.expression_desc with - | Var _ -> - E.econd (E.is_null e) Js_of_lam_option.none (Js_of_lam_option.some e) + | Var _ | Undefined | Null -> + E.econd (E.is_null e) Js_of_lam_option.none (Js_of_lam_option.some e) | _ -> E.runtime_call Js_runtime_modules.js_primitive "null_to_opt" args @@ -95950,7 +95582,7 @@ let translate loc begin match args with | [e] -> begin match e.expression_desc with - | Var _ -> + | Var _ | Undefined | Null -> E.econd (E.is_undef e) Js_of_lam_option.none (Js_of_lam_option.some e) | _ -> E.runtime_call Js_runtime_modules.js_primitive @@ -95968,7 +95600,7 @@ let translate loc begin match args with | [e] -> begin match e.expression_desc with - | Var _ -> + | Var _ | Undefined | Null -> E.econd (E.is_null_undefined e) Js_of_lam_option.none (Js_of_lam_option.some e) @@ -95994,18 +95626,6 @@ let translate loc | [a;b] -> E.set_length a b | _ -> assert false end - | Lam.Pjs_string_of_small_array -> - begin match args with - | [e] -> E.string_of_small_int_array e - | _ -> assert false - end - (* | Lam.Pjs_is_instance_array -> - begin match args with - | [e] -> E.is_instance_array e - | _ -> assert false - end *) - - | Pis_null -> begin match args with | [e] -> E.is_null e @@ -96560,9 +96180,7 @@ let translate loc (* assert false (\* already handled *\) *) (* assert false *) | Pduprecord ((Record_regular - | Record_float ),0) - | Pduprecord ((Record_regular - | Record_float ),_) -> + | Record_float ),_size) -> (* _size is the length of all_lables*) begin match args with | [e] -> Js_of_lam_record.copy e | _ -> assert false