From e1c5a5b568bfcec53722b6e7ef4f8ed53c8fc773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 9 May 2023 11:48:04 +0200 Subject: [PATCH 01/22] first pass at tagged templates basically kevinbarabash/rescript-compiler#2 rebased on master --- jscomp/core/j.ml | 1 + jscomp/core/js_analyzer.ml | 8 +- jscomp/core/js_dump.ml | 25 +++ jscomp/core/js_exp_make.ml | 3 + jscomp/core/js_exp_make.mli | 2 + jscomp/core/js_fold.ml | 2 + jscomp/core/js_record_fold.ml | 3 + jscomp/core/js_record_iter.ml | 3 + jscomp/core/js_record_map.ml | 3 + jscomp/core/lam.ml | 1 + jscomp/core/lam.mli | 1 + jscomp/core/lam_analysis.ml | 2 +- jscomp/core/lam_compile.ml | 1 + jscomp/core/lam_compile_external_call.mli | 6 + jscomp/core/lam_compile_primitive.ml | 15 ++ jscomp/core/lam_convert.ml | 6 +- jscomp/core/lam_eta_conversion.ml | 2 +- jscomp/core/lam_pass_remove_alias.ml | 17 +- jscomp/core/lam_primitive.ml | 9 ++ jscomp/core/lam_primitive.mli | 4 + jscomp/core/lam_print.ml | 6 +- jscomp/ml/lambda.ml | 6 +- jscomp/ml/lambda.mli | 1 + jscomp/ml/matching.ml | 8 +- jscomp/ml/translattribute.ml | 13 ++ jscomp/ml/translattribute.mli | 3 + jscomp/ml/translcore.ml | 32 +++- jscomp/ml/translmod.ml | 2 + jscomp/syntax/src/res_core.ml | 147 ++++++++++++------ jscomp/syntax/src/res_parsetree_viewer.ml | 14 ++ jscomp/syntax/src/res_parsetree_viewer.mli | 1 + jscomp/syntax/src/res_printer.ml | 53 ++++++- .../tests/printer/other/ocamlString.res | 25 +++ jscomp/test/tagged_template_lib.js | 8 + jscomp/test/tagged_template_test.js | 38 +++++ jscomp/test/tagged_template_test.res | 14 ++ 36 files changed, 417 insertions(+), 68 deletions(-) create mode 100644 jscomp/syntax/tests/printer/other/ocamlString.res create mode 100644 jscomp/test/tagged_template_lib.js create mode 100644 jscomp/test/tagged_template_test.js create mode 100644 jscomp/test/tagged_template_test.res diff --git a/jscomp/core/j.ml b/jscomp/core/j.ml index 2d3e9329bc..acbdc06998 100644 --- a/jscomp/core/j.ml +++ b/jscomp/core/j.ml @@ -115,6 +115,7 @@ and expression_desc = This can be constructed either in a static way [E.array_index_by_int] or a dynamic way [E.array_index] *) + | Tagged_template of expression * expression list * expression list | Static_index of expression * string * int32 option (* The third argument bool indicates whether we should print it as diff --git a/jscomp/core/js_analyzer.ml b/jscomp/core/js_analyzer.ml index d2de7d61bc..68edf5677d 100644 --- a/jscomp/core/js_analyzer.ml +++ b/jscomp/core/js_analyzer.ml @@ -103,6 +103,12 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = | String_append (a, b) | Seq (a, b) -> no_side_effect a && no_side_effect b | Length (e, _) | Caml_block_tag (e, _) | Typeof e -> no_side_effect e | Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b + (* + TODO: we should check look at each of the expressions in the 'values' list/array + to determine if any of them have side-effects. For now we'll just return false + to make the compiler happy. + *) + | Tagged_template _ -> false | Js_not _ | Cond _ | FlatCall _ | Call _ | New _ | Raw_js_code _ (* actually true? *) -> false @@ -204,7 +210,7 @@ let rec eq_expression ({ expression_desc = x0 } : J.expression) | _ -> false) | Length _ | Is_null_or_undefined _ | String_append _ | Typeof _ | Js_not _ | Cond _ | FlatCall _ | New _ | Fun _ | Raw_js_code _ | Array _ - | Caml_block_tag _ | Object _ + | Caml_block_tag _ | Object _ | Tagged_template _ | Number (Uint _) -> false | Await _ -> false diff --git a/jscomp/core/js_dump.ml b/jscomp/core/js_dump.ml index c0bcdfbda1..269fb8ab59 100644 --- a/jscomp/core/js_dump.ml +++ b/jscomp/core/js_dump.ml @@ -147,6 +147,8 @@ let exp_need_paren (e : J.expression) = match e.expression_desc with (* | Caml_uninitialized_obj _ *) | Call ({ expression_desc = Fun _ | Raw_js_code _ }, _, _) -> true + (* TODO: implement this *) + | Tagged_template _ -> false | Raw_js_code { code_info = Exp _ } | Fun _ | Caml_block @@ -596,6 +598,29 @@ and expression_desc cxt ~(level : int) f x : cxt = P.string f L.null; comma_sp f; expression ~level:1 cxt f el)) + | Tagged_template (callExpr, stringArgs, valueArgs) -> + let cxt = expression cxt ~level f callExpr in + P.string f "`"; + let rec aux cxt xs ys = match xs, ys with + | [], [] -> () + | x_head :: x_rest, ys -> + let cxt = (match x_head with + | {J.expression_desc = Str { txt; _ }} -> + P.string f txt; + cxt + | _ -> + P.string f "${"; + let cxt = expression cxt ~level f x_head in + P.string f "}"; + cxt + ) + in + aux cxt ys x_rest + | _ -> assert false + in + aux cxt stringArgs valueArgs; + P.string f "`"; + cxt | String_index (a, b) -> P.group f 1 (fun _ -> let cxt = expression ~level:15 cxt f a in diff --git a/jscomp/core/js_exp_make.ml b/jscomp/core/js_exp_make.ml index 10e9e93929..7821d6dd3e 100644 --- a/jscomp/core/js_exp_make.ml +++ b/jscomp/core/js_exp_make.ml @@ -72,6 +72,9 @@ let call ?comment ~info e0 args : t = let flat_call ?comment e0 es : t = { expression_desc = FlatCall (e0, es); comment } +let tagged_template ?comment callExpr stringArgs valueArgs : t = + { expression_desc = Tagged_template (callExpr, stringArgs, valueArgs); comment } + let runtime_var_dot ?comment (x : string) (e1 : string) : J.expression = { expression_desc = diff --git a/jscomp/core/js_exp_make.mli b/jscomp/core/js_exp_make.mli index 9bcdd5549a..a267c118e1 100644 --- a/jscomp/core/js_exp_make.mli +++ b/jscomp/core/js_exp_make.mli @@ -279,6 +279,8 @@ val call : ?comment:string -> info:Js_call_info.t -> t -> t list -> t val flat_call : ?comment:string -> t -> t -> t +val tagged_template : ?comment:string -> t -> t list -> t list -> t + val new_ : ?comment:string -> J.expression -> J.expression list -> t val array : ?comment:string -> J.mutable_flag -> J.expression list -> t diff --git a/jscomp/core/js_fold.ml b/jscomp/core/js_fold.ml index fd4eba1356..4708f1b10f 100644 --- a/jscomp/core/js_fold.ml +++ b/jscomp/core/js_fold.ml @@ -124,6 +124,8 @@ class fold = let _self = _self#expression _x0 in let _self = list (fun _self -> _self#expression) _self _x1 in _self + | Tagged_template (_, _, _) -> + _self | String_index (_x0, _x1) -> let _self = _self#expression _x0 in let _self = _self#expression _x1 in diff --git a/jscomp/core/js_record_fold.ml b/jscomp/core/js_record_fold.ml index 86117cbcf7..b4a41bc177 100644 --- a/jscomp/core/js_record_fold.ml +++ b/jscomp/core/js_record_fold.ml @@ -130,6 +130,9 @@ let expression_desc : 'a. ('a, expression_desc) fn = let st = _self.expression _self st _x0 in let st = list _self.expression _self st _x1 in st + | Tagged_template (_, _, _) -> + (* TODO: implement this *) + st | String_index (_x0, _x1) -> let st = _self.expression _self st _x0 in let st = _self.expression _self st _x1 in diff --git a/jscomp/core/js_record_iter.ml b/jscomp/core/js_record_iter.ml index d0f523ed7e..ff55592c02 100644 --- a/jscomp/core/js_record_iter.ml +++ b/jscomp/core/js_record_iter.ml @@ -107,6 +107,9 @@ let expression_desc : expression_desc fn = | Call (_x0, _x1, _x2) -> _self.expression _self _x0; list _self.expression _self _x1 + | Tagged_template (exprCall, _, _) -> + (* TODO: implement this *) + _self.expression _self exprCall; | String_index (_x0, _x1) -> _self.expression _self _x0; _self.expression _self _x1 diff --git a/jscomp/core/js_record_map.ml b/jscomp/core/js_record_map.ml index 371d54eb6a..8680c4fcdd 100644 --- a/jscomp/core/js_record_map.ml +++ b/jscomp/core/js_record_map.ml @@ -130,6 +130,9 @@ let expression_desc : expression_desc fn = let _x0 = _self.expression _self _x0 in let _x1 = list _self.expression _self _x1 in Call (_x0, _x1, _x2) + | Tagged_template (callExpr, stringsArray, valuesArray) -> + (* TODO: implement this *) + Tagged_template (callExpr, stringsArray, valuesArray) | String_index (_x0, _x1) -> let _x0 = _self.expression _self _x0 in let _x1 = _self.expression _self _x1 in diff --git a/jscomp/core/lam.ml b/jscomp/core/lam.ml index 7eb7881d44..5e59730151 100644 --- a/jscomp/core/lam.ml +++ b/jscomp/core/lam.ml @@ -28,6 +28,7 @@ type apply_status = App_na | App_infer_full | App_uncurry type ap_info = { ap_loc : Location.t; ap_inlined : Lambda.inline_attribute; + ap_tagged_template : bool; ap_status : apply_status; } diff --git a/jscomp/core/lam.mli b/jscomp/core/lam.mli index d57bdcb316..af9621ad4e 100644 --- a/jscomp/core/lam.mli +++ b/jscomp/core/lam.mli @@ -27,6 +27,7 @@ type apply_status = App_na | App_infer_full | App_uncurry type ap_info = { ap_loc : Location.t; ap_inlined : Lambda.inline_attribute; + ap_tagged_template : bool; ap_status : apply_status; } diff --git a/jscomp/core/lam_analysis.ml b/jscomp/core/lam_analysis.ml index eacfe0a872..ff1002fc95 100644 --- a/jscomp/core/lam_analysis.ml +++ b/jscomp/core/lam_analysis.ml @@ -98,7 +98,7 @@ let rec no_side_effects (lam : Lam.t) : bool = true | Pjs_apply | Pjs_runtime_apply | Pjs_call _ | Pinit_mod | Pupdate_mod | Pjs_unsafe_downgrade _ | Pdebugger | Pvoid_run | Pfull_apply - | Pjs_fn_method + | Pjs_fn_method | Pjs_tagged_template _ (* TODO *) | Praw_js_code _ | Pbytessetu | Pbytessets (* Operations on boxed integers (Nativeint.t, Int32.t, Int64.t) *) diff --git a/jscomp/core/lam_compile.ml b/jscomp/core/lam_compile.ml index 7361a1e22d..3579e5a090 100644 --- a/jscomp/core/lam_compile.ml +++ b/jscomp/core/lam_compile.ml @@ -1599,6 +1599,7 @@ and compile_prim (prim_info : Lam.prim_info) { ap_loc = loc; ap_inlined = Default_inline; + ap_tagged_template = false; ap_status = App_uncurry; }) (*FIXME: should pass info down: `f a [@bs][@inlined]`*) diff --git a/jscomp/core/lam_compile_external_call.mli b/jscomp/core/lam_compile_external_call.mli index 51d50fbcc9..7fef8470ca 100644 --- a/jscomp/core/lam_compile_external_call.mli +++ b/jscomp/core/lam_compile_external_call.mli @@ -36,6 +36,12 @@ val translate_ffi : J.expression list -> J.expression +val translate_scoped_module_val : + External_ffi_types.external_module_name option -> + string -> + string list -> + J.expression + (** TODO: document supported attributes Attributes starting with `js` are reserved examples: "variadic" diff --git a/jscomp/core/lam_compile_primitive.ml b/jscomp/core/lam_compile_primitive.ml index b25269aaec..44f6d2f57b 100644 --- a/jscomp/core/lam_compile_primitive.ml +++ b/jscomp/core/lam_compile_primitive.ml @@ -339,6 +339,21 @@ let translate output_prefix loc (cxt : Lam_compile_context.t) | Pjs_object_create _ -> assert false | Pjs_call { arg_types; ffi } -> Lam_compile_external_call.translate_ffi cxt arg_types ffi args + | Pjs_tagged_template { ffi } -> ( + (* TODO: extract this into lam_compile_external_call.ml *) + let fn = match ffi with + | Js_call { external_module_name; name; scopes } -> + Lam_compile_external_call.translate_scoped_module_val external_module_name name scopes + | _ -> assert false + in + match args with + | [ stringArgs; valueArgs ] -> ( + match (stringArgs, valueArgs) with + | ({expression_desc = Array (strings, _)}, {expression_desc = Array (values, _)}) -> + E.tagged_template fn strings values + | _ -> assert false + ) + | _ -> assert false) (* FIXME, this can be removed later *) | Pisint -> E.is_type_number (Ext_list.singleton_exn args) | Pis_poly_var_block -> E.is_type_object (Ext_list.singleton_exn args) diff --git a/jscomp/core/lam_convert.ml b/jscomp/core/lam_convert.ml index 922184e3a1..95c48bd3c0 100644 --- a/jscomp/core/lam_convert.ml +++ b/jscomp/core/lam_convert.ml @@ -512,11 +512,11 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : match lam with | Lvar x -> Lam.var (Hash_ident.find_default alias_tbl x x) | Lconst x -> Lam.const (Lam_constant_convert.convert_constant x) - | Lapply { ap_func = fn; ap_args = args; ap_loc = loc; ap_inlined } -> + | Lapply { ap_func = fn; ap_args = args; ap_loc = loc; ap_inlined; ap_tagged_template } -> (* we need do this eargly in case [aux fn] add some wrapper *) Lam.apply (convert_aux fn) (Ext_list.map args convert_aux) - { ap_loc = loc; ap_inlined; ap_status = App_na } + { ap_loc = loc; ap_inlined; ap_tagged_template; ap_status = App_na } | Lfunction { params; body; attr } -> let new_map, body = rename_optional_parameters Map_ident.empty params body @@ -685,6 +685,7 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : { ap_loc = outer_loc; ap_inlined = ap_info.ap_inlined; + ap_tagged_template = ap_info.ap_tagged_template; ap_status = App_na; } | _ -> @@ -692,6 +693,7 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : { ap_loc = outer_loc; ap_inlined = Default_inline; + ap_tagged_template = false; ap_status = App_na; } and convert_switch (e : Lambda.lambda) (s : Lambda.lambda_switch) = diff --git a/jscomp/core/lam_eta_conversion.ml b/jscomp/core/lam_eta_conversion.ml index a92639f1f2..71f7d894f8 100644 --- a/jscomp/core/lam_eta_conversion.ml +++ b/jscomp/core/lam_eta_conversion.ml @@ -111,7 +111,7 @@ let transform_under_supply n ap_info fn args = let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : Lam.t = let ap_info : Lam.ap_info = - { ap_loc = loc; ap_inlined = Default_inline; ap_status = App_na } + { ap_loc = loc; ap_inlined = Default_inline; ap_tagged_template = false; ap_status = App_na } in let is_async_fn = match fn with | Lfunction { attr = {async}} -> async diff --git a/jscomp/core/lam_pass_remove_alias.ml b/jscomp/core/lam_pass_remove_alias.ml index 4889d1c268..afd294fd73 100644 --- a/jscomp/core/lam_pass_remove_alias.ml +++ b/jscomp/core/lam_pass_remove_alias.ml @@ -198,7 +198,8 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = (* Ext_log.dwarn __LOC__ "%s/%d" v.name v.stamp; *) let ap_args = Ext_list.map ap_args simpl in - let[@local] normal () = Lam.apply (simpl fn) ap_args ap_info in + (* todo bring back local inlining *) + let normal () = Lam.apply (simpl fn) ap_args ap_info in match Hash_ident.find_opt meta.ident_tbl v with | Some (FunctionId @@ -238,7 +239,7 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = Lam_closure.is_closed_with_map meta.export_idents params body in let is_export_id = Set_ident.mem meta.export_idents v in - match (is_export_id, param_map) with + let result = match (is_export_id, param_map) with | false, (_, param_map) | true, (true, param_map) -> ( match rec_flag with | Lam_rec -> @@ -256,6 +257,18 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = (Lam_beta_reduce.propagate_beta_reduce_with_map meta param_map params body ap_args)) | _ -> normal () + in + let result = (match result with + | Lprim {primitive; args; loc} -> (match primitive with + (* Converts Pjs_calls to Pjs_tagged_templates if ap_tagged_template is true *) + | Pjs_call {prim_name; ffi} when ap_info.ap_tagged_template -> + let prim = Lam_primitive.Pjs_tagged_template {prim_name; ffi} in + Lam.prim ~primitive:prim ~args loc + | _ -> result + ) + | _ -> result) + in + result else normal () else normal () | Some _ | None -> normal ()) diff --git a/jscomp/core/lam_primitive.ml b/jscomp/core/lam_primitive.ml index 26a9f998b2..362ef09d9d 100644 --- a/jscomp/core/lam_primitive.ml +++ b/jscomp/core/lam_primitive.ml @@ -49,6 +49,10 @@ type t = arg_types : External_arg_spec.params; ffi : External_ffi_types.external_spec; } + | Pjs_tagged_template of { + prim_name : string; + ffi : External_ffi_types.external_spec; + } | Pjs_object_create of External_arg_spec.obj_params (* Exceptions *) | Praise @@ -259,6 +263,11 @@ let eq_primitive_approx (lhs : t) (rhs : t) = match rhs with | Pjs_object_create obj_create1 -> obj_create = obj_create1 | _ -> false) + | Pjs_tagged_template { prim_name; ffi } -> ( + match rhs with + | Pjs_tagged_template rhs -> + prim_name = rhs.prim_name && ffi = rhs.ffi + | _ -> false) | Pintcomp comparison -> ( match rhs with | Pintcomp comparison1 -> Lam_compat.eq_comparison comparison comparison1 diff --git a/jscomp/core/lam_primitive.mli b/jscomp/core/lam_primitive.mli index d78dd25e64..b491468650 100644 --- a/jscomp/core/lam_primitive.mli +++ b/jscomp/core/lam_primitive.mli @@ -44,6 +44,10 @@ type t = arg_types : External_arg_spec.params; ffi : External_ffi_types.external_spec; } + | Pjs_tagged_template of { + prim_name : string; + ffi : External_ffi_types.external_spec; + } | Pjs_object_create of External_arg_spec.obj_params | Praise | Psequand diff --git a/jscomp/core/lam_print.ml b/jscomp/core/lam_print.ml index f7390234c5..0dbc51172b 100644 --- a/jscomp/core/lam_print.ml +++ b/jscomp/core/lam_print.ml @@ -93,6 +93,7 @@ let primitive ppf (prim : Lam_primitive.t) = | Plazyforce -> fprintf ppf "force" | Pccall p -> fprintf ppf "%s" p.prim_name | Pjs_call { prim_name } -> fprintf ppf "%s[js]" prim_name + | Pjs_tagged_template { prim_name } -> fprintf ppf "%s[js.tagged_template]" prim_name | Pjs_object_create _ -> fprintf ppf "[js.obj]" | Praise -> fprintf ppf "raise" | Psequand -> fprintf ppf "&&" @@ -263,12 +264,13 @@ let lambda ppf v = | Lvar id -> Ident.print ppf id | Lglobal_module (id, dynamic_import) -> fprintf ppf (if dynamic_import then "dynamic global %a" else "global %a") Ident.print id | Lconst cst -> struct_const ppf cst - | Lapply { ap_func; ap_args; ap_info = { ap_inlined } } -> + | Lapply { ap_func; ap_args; ap_info = { ap_inlined; ap_tagged_template } } -> let lams ppf args = List.iter (fun l -> fprintf ppf "@ %a" lam l) args in - fprintf ppf "@[<2>(apply%s@ %a%a)@]" + fprintf ppf "@[<2>(apply%s%s@ %a%a)@]" (match ap_inlined with Always_inline -> "%inlned" | _ -> "") + (match ap_tagged_template with true -> "%tagged_template" | _ -> "") lam ap_func lams ap_args | Lfunction { params; body; _ } -> let pr_params ppf params = diff --git a/jscomp/ml/lambda.ml b/jscomp/ml/lambda.ml index 337dd10e9e..ceaa79a64a 100644 --- a/jscomp/ml/lambda.ml +++ b/jscomp/ml/lambda.ml @@ -354,6 +354,7 @@ and lambda_apply = ap_args : lambda list; ap_loc : Location.t; ap_inlined : inline_attribute; + ap_tagged_template : bool; } and lambda_switch = @@ -688,12 +689,13 @@ let rec map f lam = | Lvar _ -> lam | Lconst _ -> lam | Lapply { ap_func; ap_args; ap_loc; - ap_inlined; } -> + ap_inlined; ap_tagged_template; } -> Lapply { ap_func = map f ap_func; ap_args = List.map (map f) ap_args; ap_loc; - ap_inlined; + ap_inlined; + ap_tagged_template ; } | Lfunction { params; body; attr; loc; } -> Lfunction { params; body = map f body; attr; loc; } diff --git a/jscomp/ml/lambda.mli b/jscomp/ml/lambda.mli index 3a9b847c9c..b5103919fe 100644 --- a/jscomp/ml/lambda.mli +++ b/jscomp/ml/lambda.mli @@ -325,6 +325,7 @@ and lambda_apply = ap_args : lambda list; ap_loc : Location.t; ap_inlined : inline_attribute; (* specified with the [@inlined] attribute *) + ap_tagged_template : bool; } and lambda_switch = diff --git a/jscomp/ml/matching.ml b/jscomp/ml/matching.ml index 30fa8efb72..b7aa805365 100644 --- a/jscomp/ml/matching.ml +++ b/jscomp/ml/matching.ml @@ -1514,7 +1514,13 @@ let code_force = let inline_lazy_force arg loc = - Lapply { ap_func = Lazy.force code_force; ap_inlined = Default_inline; ap_args = [arg]; ap_loc = loc} + Lapply { + ap_func = Lazy.force code_force; + ap_inlined = Default_inline; + ap_tagged_template = false; + ap_args = [arg]; + ap_loc = loc; + } let make_lazy_matching def = function [] -> fatal_error "Matching.make_lazy_matching" | (arg,_mut) :: argl -> diff --git a/jscomp/ml/translattribute.ml b/jscomp/ml/translattribute.ml index 4f7eca2b3d..5a03caab94 100644 --- a/jscomp/ml/translattribute.ml +++ b/jscomp/ml/translattribute.ml @@ -21,6 +21,9 @@ let is_inline_attribute (attr : t) = let is_inlined_attribute (attr : t) = match attr with { txt = "inlined" }, _ -> true | _ -> false +let is_tagged_template_attribute (attr : t) = + match attr with { txt = "res.taggedTemplate" }, _ -> true | _ -> false + let find_attribute p (attributes : t list) = let inline_attribute, other_attributes = List.partition p attributes in let attr = @@ -93,6 +96,16 @@ let get_and_remove_inlined_attribute (e : Typedtree.expression) = let inlined = parse_inline_attribute attr in (inlined, { e with exp_attributes }) +let get_and_remove_tagged_template_attribute (e : Typedtree.expression) = + let attr, exp_attributes = + find_attribute is_tagged_template_attribute e.exp_attributes + in + let tagged_template = match attr with + | Some(_) -> true + | None -> false + in + (tagged_template, { e with exp_attributes }) + let get_and_remove_inlined_attribute_on_module (e : Typedtree.module_expr) = let attr, mod_attributes = find_attribute is_inlined_attribute e.mod_attributes diff --git a/jscomp/ml/translattribute.mli b/jscomp/ml/translattribute.mli index 03115eb0ee..749f58904c 100644 --- a/jscomp/ml/translattribute.mli +++ b/jscomp/ml/translattribute.mli @@ -26,5 +26,8 @@ val get_inline_attribute : Parsetree.attributes -> Lambda.inline_attribute val get_and_remove_inlined_attribute : Typedtree.expression -> Lambda.inline_attribute * Typedtree.expression +val get_and_remove_tagged_template_attribute : + Typedtree.expression -> bool * Typedtree.expression + val get_and_remove_inlined_attribute_on_module : Typedtree.module_expr -> Lambda.inline_attribute * Typedtree.module_expr diff --git a/jscomp/ml/translcore.ml b/jscomp/ml/translcore.ml index 7033cd5405..342b460456 100644 --- a/jscomp/ml/translcore.ml +++ b/jscomp/ml/translcore.ml @@ -724,10 +724,13 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = let wrap f = if args' = [] then f else - let inlined, _ = + let inlined, funct = Translattribute.get_and_remove_inlined_attribute funct in - transl_apply ~inlined f args' e.exp_loc + let is_tagged_template, _ = + Translattribute.get_and_remove_tagged_template_attribute funct + in + transl_apply ~inlined ~is_tagged_template f args' e.exp_loc in let args = List.map (function _, Some x -> x | _ -> assert false) args @@ -759,6 +762,20 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = wrap (Lprim (prim, argl, e.exp_loc)) )) | Texp_apply (funct, oargs) -> + (* let () = print_string "#2 attrs = " in *) + (* let () = ( + List.iter ( + function ({txt = attrName}, _) -> print_string (attrName ^ "\n") + ) e.exp_attributes + ) in + let isTaggedTemplate = List.exists ( + function ({txt = attrName}, _) -> attrName = "res.taggedTemplate" + ) e.exp_attributes in + let () = if isTaggedTemplate then + (print_string "isTaggedTemplate\n") + else + (print_string "not isTaggedTemplate\n") + in *) let inlined, funct = Translattribute.get_and_remove_inlined_attribute funct in @@ -769,7 +786,10 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = arity_opt else None in - transl_apply ~inlined ~uncurried_partial_application (transl_exp funct) oargs e.exp_loc + let is_tagged_template, _ = + Translattribute.get_and_remove_tagged_template_attribute e + in + transl_apply ~inlined ~uncurried_partial_application ~is_tagged_template (transl_exp funct) oargs e.exp_loc | Texp_match (arg, pat_expr_list, exn_pat_expr_list, partial) -> transl_match e arg pat_expr_list exn_pat_expr_list partial | Texp_try (body, pat_expr_list) -> @@ -985,14 +1005,14 @@ and transl_cases_try cases = in List.map transl_case_try cases -and transl_apply ?(inlined = Default_inline) ?(uncurried_partial_application=None) lam sargs loc = +and transl_apply ?(inlined = Default_inline) ?(is_tagged_template=false) ?(uncurried_partial_application=None) lam sargs loc = let lapply funct args = match funct with (* Attention: This may not be what we need to change the application arity*) | Lapply ap -> Lapply { ap with ap_args = ap.ap_args @ args; ap_loc = loc } | lexp -> Lapply - { ap_loc = loc; ap_func = lexp; ap_args = args; ap_inlined = inlined } + { ap_loc = loc; ap_func = lexp; ap_args = args; ap_inlined = inlined; ap_tagged_template = is_tagged_template } in let rec build_apply lam args = function | (None, optional) :: l -> @@ -1051,7 +1071,7 @@ and transl_apply ?(inlined = Default_inline) ?(uncurried_partial_application=Non let extra_ids = Array.init extra_arity (fun _ -> Ident.create "extra") |> Array.to_list in let extra_args = Ext_list.map extra_ids (fun id -> Lvar id) in let ap_args = args @ extra_args in - let l0 = Lapply { ap_func = lam; ap_args; ap_inlined = inlined; ap_loc = loc } in + let l0 = Lapply { ap_func = lam; ap_args; ap_inlined = inlined; ap_loc = loc; ap_tagged_template = is_tagged_template } in Lfunction { params = List.rev_append !none_ids extra_ids ; diff --git a/jscomp/ml/translmod.ml b/jscomp/ml/translmod.ml index 8815209779..fa8fd6dd15 100644 --- a/jscomp/ml/translmod.ml +++ b/jscomp/ml/translmod.ml @@ -109,6 +109,7 @@ and apply_coercion_result loc strict funct params args cc_res = ap_func = Lvar id; ap_args = List.rev args; ap_inlined = Default_inline; + ap_tagged_template = false; }); }) @@ -308,6 +309,7 @@ and transl_module cc rootpath mexp = ap_func = transl_module Tcoerce_none None funct; ap_args = [ transl_module ccarg None arg ]; ap_inlined = inlined_attribute; + ap_tagged_template = false; }) | Tmod_constraint (arg, _, _, ccarg) -> transl_module (compose_coercions cc ccarg) rootpath arg diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index e410b36a01..3a19bfab8c 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -17,6 +17,16 @@ end let mkLoc startLoc endLoc = Location.{loc_start = startLoc; loc_end = endLoc; loc_ghost = false} +let filter_map (f : 'a -> 'b option) xs = + let rec aux acc = function + | [] -> List.rev acc + | y :: ys -> ( + match f y with + | None -> aux acc ys + | Some z -> aux (z :: acc) ys) + in + aux [] xs + module Recover = struct let defaultExpr () = let id = Location.mknoloc "rescript.exprhole" in @@ -180,6 +190,9 @@ let suppressFragileMatchWarningAttr = let makeBracesAttr loc = (Location.mkloc "res.braces" loc, Parsetree.PStr []) let templateLiteralAttr = (Location.mknoloc "res.template", Parsetree.PStr []) +let taggedTemplateLiteralAttr = + (Location.mknoloc "res.taggedTemplate", Parsetree.PStr []) + let spreadAttr = (Location.mknoloc "res.spread", Parsetree.PStr []) type argument = { @@ -2255,6 +2268,64 @@ and parseBinaryExpr ?(context = OrdinaryExpr) ?a p prec = (* ) *) and parseTemplateExpr ?(prefix = "js") p = + let partPrefix = + match prefix with + | "js" | "j" -> Some prefix + | _ -> None + in + let startPos = p.Parser.startPos in + + let parseParts p = + let rec aux acc = + let startPos = p.Parser.startPos in + Parser.nextTemplateLiteralToken p; + match p.token with + | TemplateTail (txt, lastPos) -> + Parser.next p; + let loc = mkLoc startPos lastPos in + let str = + Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc + (Pconst_string (txt, partPrefix)) + in + List.rev ((str, None) :: acc) + | TemplatePart (txt, lastPos) -> + Parser.next p; + let loc = mkLoc startPos lastPos in + let expr = parseExprBlock p in + let str = + Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc + (Pconst_string (txt, partPrefix)) + in + aux ((str, Some expr) :: acc) + | token -> + Parser.err p (Diagnostics.unexpected token p.breadcrumbs); + [] + in + aux [] + in + let parts = parseParts p in + let strings = List.map fst parts in + let values = filter_map snd parts in + let endPos = p.Parser.endPos in + + let genTaggedTemplateCall () = + let lident = Longident.Lident prefix in + let ident = + Ast_helper.Exp.ident ~attrs:[] ~loc:Location.none + (Location.mknoloc lident) + in + let strings_array = + Ast_helper.Exp.array ~attrs:[] ~loc:Location.none strings + in + let values_array = + Ast_helper.Exp.array ~attrs:[] ~loc:Location.none values + in + Ast_helper.Exp.apply + ~attrs:[taggedTemplateLiteralAttr] + ~loc:(mkLoc startPos endPos) ident + [(Nolabel, strings_array); (Nolabel, values_array)] + in + let hiddenOperator = let op = Location.mknoloc (Longident.Lident "^") in Ast_helper.Exp.ident op @@ -2264,56 +2335,34 @@ and parseTemplateExpr ?(prefix = "js") p = Ast_helper.Exp.apply ~attrs:[templateLiteralAttr] ~loc hiddenOperator [(Nolabel, e1); (Nolabel, e2)] in - let rec parseParts (acc : Parsetree.expression) = - let startPos = p.Parser.startPos in - Parser.nextTemplateLiteralToken p; - match p.token with - | TemplateTail (txt, lastPos) -> - Parser.next p; - let loc = mkLoc startPos lastPos in - let str = - Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc - (Pconst_string (txt, Some prefix)) - in - concat acc str - | TemplatePart (txt, lastPos) -> - Parser.next p; - let loc = mkLoc startPos lastPos in - let expr = parseExprBlock p in - let str = - Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc - (Pconst_string (txt, Some prefix)) - in - let next = - let a = concat acc str in - concat a expr - in - parseParts next - | token -> - Parser.err p (Diagnostics.unexpected token p.breadcrumbs); - Ast_helper.Exp.constant (Pconst_string ("", None)) - in - let startPos = p.startPos in - Parser.nextTemplateLiteralToken p; - match p.token with - | TemplateTail (txt, lastPos) -> - Parser.next p; - Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] - ~loc:(mkLoc startPos lastPos) - (Pconst_string (txt, Some prefix)) - | TemplatePart (txt, lastPos) -> - Parser.next p; - let constantLoc = mkLoc startPos lastPos in - let expr = parseExprBlock p in - let str = - Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc:constantLoc - (Pconst_string (txt, Some prefix)) + let genInterpolatedString () = + let subparts = + List.flatten + (List.map + (fun part -> + match part with + | s, Some v -> [s; v] + | s, None -> [s]) + parts) in - let next = concat str expr in - parseParts next - | token -> - Parser.err p (Diagnostics.unexpected token p.breadcrumbs); - Ast_helper.Exp.constant (Pconst_string ("", None)) + let exprOption = + List.fold_left + (fun acc subpart -> + Some + (match acc with + | Some expr -> + concat expr subpart + | None -> subpart)) + None subparts + in + match exprOption with + | Some expr -> expr + | None -> Ast_helper.Exp.constant (Pconst_string ("", None)) + in + + match prefix with + | "js" | "j" -> genInterpolatedString () + | _ -> genTaggedTemplateCall () (* Overparse: let f = a : int => a + 1, is it (a : int) => or (a): int => * Also overparse constraints: diff --git a/jscomp/syntax/src/res_parsetree_viewer.ml b/jscomp/syntax/src/res_parsetree_viewer.ml index 2e36a46e1c..8142ae33b6 100644 --- a/jscomp/syntax/src/res_parsetree_viewer.ml +++ b/jscomp/syntax/src/res_parsetree_viewer.ml @@ -634,6 +634,14 @@ let hasTemplateLiteralAttr attrs = | _ -> false) attrs +let hasTaggedTemplateLiteralAttr attrs = + List.exists + (fun attr -> + match attr with + | {Location.txt = "res.taggedTemplate"}, _ -> true + | _ -> false) + attrs + let isTemplateLiteral expr = match expr.pexp_desc with | Pexp_apply @@ -645,6 +653,12 @@ let isTemplateLiteral expr = | Pexp_constant _ when hasTemplateLiteralAttr expr.pexp_attributes -> true | _ -> false +let isTaggedTemplateLiteral expr = + match expr with + | {pexp_desc = Pexp_apply _; pexp_attributes = attrs} -> + hasTaggedTemplateLiteralAttr attrs + | _ -> false + let hasSpreadAttr attrs = List.exists (fun attr -> diff --git a/jscomp/syntax/src/res_parsetree_viewer.mli b/jscomp/syntax/src/res_parsetree_viewer.mli index 15ca9e150b..493b6e8518 100644 --- a/jscomp/syntax/src/res_parsetree_viewer.mli +++ b/jscomp/syntax/src/res_parsetree_viewer.mli @@ -137,6 +137,7 @@ val collectPatternsFromListConstruct : val isBlockExpr : Parsetree.expression -> bool val isTemplateLiteral : Parsetree.expression -> bool +val isTaggedTemplateLiteral : Parsetree.expression -> bool val hasTemplateLiteralAttr : Parsetree.attributes -> bool val isSpreadBeltListConcat : Parsetree.expression -> bool diff --git a/jscomp/syntax/src/res_printer.ml b/jscomp/syntax/src/res_printer.ml index 05484b02af..3b546e0513 100644 --- a/jscomp/syntax/src/res_printer.ml +++ b/jscomp/syntax/src/res_printer.ml @@ -2080,6 +2080,8 @@ and printValueBinding ~state ~recFlag (vb : Parsetree.value_binding) cmtTbl i = ParsetreeViewer.isBinaryExpression ifExpr || ParsetreeViewer.hasAttributes ifExpr.pexp_attributes | {pexp_desc = Pexp_newtype _} -> false + | {pexp_attributes = [({Location.txt = "res.taggedTemplate"}, _)]} -> + false | e -> ParsetreeViewer.hasAttributes e.pexp_attributes || ParsetreeViewer.isArrayAccess e) @@ -3047,11 +3049,13 @@ and printExpression ~state (e : Parsetree.expression) cmtTbl = | Pexp_apply (e, [(Nolabel, {pexp_desc = Pexp_array subLists})]) when ParsetreeViewer.isSpreadBeltListConcat e -> printBeltListConcatApply ~state subLists cmtTbl - | Pexp_apply _ -> + | Pexp_apply (callExpr, args) -> if ParsetreeViewer.isUnaryExpression e then printUnaryExpression ~state e cmtTbl else if ParsetreeViewer.isTemplateLiteral e then printTemplateLiteral ~state e cmtTbl + else if ParsetreeViewer.isTaggedTemplateLiteral e then + printTaggedTemplateLiteral ~state callExpr args cmtTbl else if ParsetreeViewer.isBinaryExpression e then printBinaryExpression ~state e cmtTbl else printPexpApply ~state e cmtTbl @@ -3474,6 +3478,53 @@ and printTemplateLiteral ~state expr cmtTbl = Doc.text "`"; ] +and printTaggedTemplateLiteral ~state callExpr args cmtTbl = + let stringsList, valuesList = + match args with + | [ + (_, {Parsetree.pexp_desc = Pexp_array strings}); + (_, {Parsetree.pexp_desc = Pexp_array values}); + ] -> + (strings, values) + | _ -> assert false + in + + let strings = + List.map + (fun x -> + match x with + | {Parsetree.pexp_desc = Pexp_constant (Pconst_string (txt, _))} -> + printStringContents txt + | _ -> assert false) + stringsList + in + + let values = + List.map + (fun x -> + Doc.concat + [ + Doc.text "${"; + printExpressionWithComments ~state x cmtTbl; + Doc.text "}"; + ]) + valuesList + in + + let process strings values = + let rec aux acc = function + | [], [] -> acc + | a_head :: a_rest, b -> aux (Doc.concat [acc; a_head]) (b, a_rest) + | _ -> assert false + in + aux Doc.nil (strings, values) + in + + let content : Doc.t = process strings values in + + let tag = printExpressionWithComments ~state callExpr cmtTbl in + Doc.concat [tag; Doc.text "`"; content; Doc.text "`"] + and printUnaryExpression ~state expr cmtTbl = let printUnaryOperator op = Doc.text diff --git a/jscomp/syntax/tests/printer/other/ocamlString.res b/jscomp/syntax/tests/printer/other/ocamlString.res new file mode 100644 index 0000000000..085aed7777 --- /dev/null +++ b/jscomp/syntax/tests/printer/other/ocamlString.res @@ -0,0 +1,25 @@ +let x = "\132\149\166" + +let s = "\123 \o111 \xA0" + +let x = "foo\010bar" +let x = "foo\x0Abar" +let x = "foo\o012bar" + +let x = "😁 this works now 😆" +let x = `😁 this works now 😆` + + +// The `//` should not result into an extra comment +let x = `https://www.apple.com` +let x = js`https://www.apple.com` +let x = `https://www.apple.com` +let x = sql`https://www.apple.com` + +// /* */ should not result in an extra comments +let x = `/* https://www.apple.com*/` +let x = js`/*https://www.apple.com*/` +let x = `/*https://www.apple.com*/` +let x = sql`/*https://www.apple.com*/` + +let x = `\`https://${appleWebsite}\`` \ No newline at end of file diff --git a/jscomp/test/tagged_template_lib.js b/jscomp/test/tagged_template_lib.js new file mode 100644 index 0000000000..4708f45e8d --- /dev/null +++ b/jscomp/test/tagged_template_lib.js @@ -0,0 +1,8 @@ +exports.sql = (strings, ...values) => { + let result = ""; + for (let i = 0; i < values.length; i++) { + result += strings[i] + values[i]; + } + result += strings[values.length]; + return result; +}; \ No newline at end of file diff --git a/jscomp/test/tagged_template_test.js b/jscomp/test/tagged_template_test.js new file mode 100644 index 0000000000..b0ff14b1da --- /dev/null +++ b/jscomp/test/tagged_template_test.js @@ -0,0 +1,38 @@ +'use strict'; + +var Mt = require("./mt.js"); +var Caml_splice_call = require("../../lib/js/caml_splice_call.js"); +var Tagged_template_libJs = require("./tagged_template_lib.js"); + +function sql(prim0, prim1) { + return Caml_splice_call.spliceApply(Tagged_template_libJs.sql, [ + prim0, + prim1 + ]); +} + +var table = "users"; + +var id = "5"; + +var query = Tagged_template_libJs.sql`SELECT * FROM ${table} WHERE id = ${id}`; + +Mt.from_pair_suites("tagged template", { + hd: [ + "it should return a string with the correct interpolations", + (function (param) { + return { + TAG: /* Eq */0, + _0: query, + _1: "SELECT * FROM users WHERE id = 5" + }; + }) + ], + tl: /* [] */0 + }); + +exports.sql = sql; +exports.table = table; +exports.id = id; +exports.query = query; +/* query Not a pure module */ \ No newline at end of file diff --git a/jscomp/test/tagged_template_test.res b/jscomp/test/tagged_template_test.res new file mode 100644 index 0000000000..09ec5e22a5 --- /dev/null +++ b/jscomp/test/tagged_template_test.res @@ -0,0 +1,14 @@ +@module("./tagged_template_lib.js") @variadic external sql: (array, array) => string = "sql" + +let table = "users" +let id = "5" + +let query = sql`SELECT * FROM ${table} WHERE id = ${id}` + +Mt.from_pair_suites( + "tagged template", + list{ + ("it should return a string with the correct interpolations", () => + Eq(query, "SELECT * FROM users WHERE id = 5")), + } +) \ No newline at end of file From 10786c8e1c9e7005704bf95a9899e994e9ac90c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 11:10:45 +0200 Subject: [PATCH 02/22] fix @json in external tests --- jscomp/syntax/src/res_core.ml | 7 +++---- jscomp/test/build.ninja | 3 ++- jscomp/test/tagged_template_test.js | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index 3a19bfab8c..157f9591a3 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -2270,7 +2270,7 @@ and parseBinaryExpr ?(context = OrdinaryExpr) ?a p prec = and parseTemplateExpr ?(prefix = "js") p = let partPrefix = match prefix with - | "js" | "j" -> Some prefix + | "js" | "j" | "json" -> Some prefix | _ -> None in let startPos = p.Parser.startPos in @@ -2350,8 +2350,7 @@ and parseTemplateExpr ?(prefix = "js") p = (fun acc subpart -> Some (match acc with - | Some expr -> - concat expr subpart + | Some expr -> concat expr subpart | None -> subpart)) None subparts in @@ -2361,7 +2360,7 @@ and parseTemplateExpr ?(prefix = "js") p = in match prefix with - | "js" | "j" -> genInterpolatedString () + | "js" | "j" | "json" -> genInterpolatedString () | _ -> genTaggedTemplateCall () (* Overparse: let f = a : int => a + 1, is it (a : int) => or (a): int => diff --git a/jscomp/test/build.ninja b/jscomp/test/build.ninja index b752adee5b..ea1a6d613c 100644 --- a/jscomp/test/build.ninja +++ b/jscomp/test/build.ninja @@ -575,6 +575,7 @@ o test/submodule.cmi test/submodule.cmj : cc test/submodule.res | $bsc $stdlib r o test/submodule_call.cmi test/submodule_call.cmj : cc test/submodule_call.res | test/submodule.cmj $bsc $stdlib runtime o test/switch_case_test.cmi test/switch_case_test.cmj : cc test/switch_case_test.res | test/mt.cmj $bsc $stdlib runtime o test/switch_string.cmi test/switch_string.cmj : cc test/switch_string.res | $bsc $stdlib runtime +o test/tagged_template_test.cmi test/tagged_template_test.cmj : cc test/tagged_template_test.res | test/mt.cmj $bsc $stdlib runtime o test/tailcall_inline_test.cmi test/tailcall_inline_test.cmj : cc test/tailcall_inline_test.res | test/mt.cmj $bsc $stdlib runtime o test/template.cmi test/template.cmj : cc test/template.res | $bsc $stdlib runtime o test/test.cmi test/test.cmj : cc test/test.res | $bsc $stdlib runtime @@ -717,4 +718,4 @@ o test/update_record_test.cmi test/update_record_test.cmj : cc test/update_recor o test/variant.cmi test/variant.cmj : cc test/variant.res | $bsc $stdlib runtime o test/variantsMatching.cmi test/variantsMatching.cmj : cc test/variantsMatching.res | $bsc $stdlib runtime o test/webpack_config.cmi test/webpack_config.cmj : cc test/webpack_config.res | $bsc $stdlib runtime -o test : phony test/406_primitive_test.cmi test/406_primitive_test.cmj test/AsInUncurriedExternals.cmi test/AsInUncurriedExternals.cmj test/Coercion.cmi test/Coercion.cmj test/DotDotDot.cmi test/DotDotDot.cmj test/EmptyRecord.cmi test/EmptyRecord.cmj test/FFI.cmi test/FFI.cmj test/Import.cmi test/Import.cmj test/RecordCoercion.cmi test/RecordCoercion.cmj test/RecordOrObject.cmi test/RecordOrObject.cmj test/SafePromises.cmi test/SafePromises.cmj test/UncurriedAlways.cmi test/UncurriedAlways.cmj test/UncurriedExternals.cmi test/UncurriedExternals.cmj test/UncurriedPervasives.cmi test/UncurriedPervasives.cmj test/UntaggedVariants.cmi test/UntaggedVariants.cmj test/VariantCoercion.cmi test/VariantCoercion.cmj test/VariantSpreads.cmi test/VariantSpreads.cmj test/a.cmi test/a.cmj test/a_filename_test.cmi test/a_filename_test.cmj test/a_list_test.cmi test/a_list_test.cmj test/a_recursive_type.cmi test/a_recursive_type.cmj test/a_scope_bug.cmi test/a_scope_bug.cmj test/a_string_test.cmi test/a_string_test.cmj test/abstract_type.cmi test/abstract_type.cmj test/adt_optimize_test.cmi test/adt_optimize_test.cmj test/alias_default_value_test.cmi test/alias_default_value_test.cmj test/alias_test.cmi test/alias_test.cmj test/and_or_tailcall_test.cmi test/and_or_tailcall_test.cmj test/argv_test.cmi test/argv_test.cmj test/ari_regress_test.cmi test/ari_regress_test.cmj test/arith_lexer.cmi test/arith_lexer.cmj test/arith_parser.cmi test/arith_parser.cmj test/arith_syntax.cmi test/arith_syntax.cmj test/arity.cmi test/arity.cmj test/arity_deopt.cmi test/arity_deopt.cmj test/arity_infer.cmi test/arity_infer.cmj test/array_data_util.cmi test/array_data_util.cmj test/array_safe_get.cmi test/array_safe_get.cmj test/array_subtle_test.cmi test/array_subtle_test.cmj test/array_test.cmi test/array_test.cmj test/as_inline_record_test.cmi test/as_inline_record_test.cmj test/ast_abstract_test.cmi test/ast_abstract_test.cmj test/ast_mapper_unused_warning_test.cmi test/ast_mapper_unused_warning_test.cmj test/async_await.cmi test/async_await.cmj test/async_ideas.cmi test/async_ideas.cmj test/async_inline.cmi test/async_inline.cmj test/async_inside_loop.cmi test/async_inside_loop.cmj test/attr_test.cmi test/attr_test.cmj test/b.cmi test/b.cmj test/bal_set_mini.cmi test/bal_set_mini.cmj test/bang_primitive.cmi test/bang_primitive.cmj test/basic_module_test.cmi test/basic_module_test.cmj test/bb.cmi test/bb.cmj test/bdd.cmi test/bdd.cmj test/belt_internal_test.cmi test/belt_internal_test.cmj test/belt_result_alias_test.cmi test/belt_result_alias_test.cmj test/bench.cmi test/bench.cmj test/big_enum.cmi test/big_enum.cmj test/big_polyvar_test.cmi test/big_polyvar_test.cmj test/block_alias_test.cmi test/block_alias_test.cmj test/boolean_test.cmi test/boolean_test.cmj test/bs_MapInt_test.cmi test/bs_MapInt_test.cmj test/bs_abstract_test.cmi test/bs_abstract_test.cmj test/bs_array_test.cmi test/bs_array_test.cmj test/bs_auto_uncurry.cmi test/bs_auto_uncurry.cmj test/bs_auto_uncurry_test.cmi test/bs_auto_uncurry_test.cmj test/bs_float_test.cmi test/bs_float_test.cmj test/bs_hashmap_test.cmi test/bs_hashmap_test.cmj test/bs_hashset_int_test.cmi test/bs_hashset_int_test.cmj test/bs_hashtbl_string_test.cmi test/bs_hashtbl_string_test.cmj test/bs_ignore_effect.cmi test/bs_ignore_effect.cmj test/bs_ignore_test.cmi test/bs_ignore_test.cmj test/bs_int_test.cmi test/bs_int_test.cmj test/bs_list_test.cmi test/bs_list_test.cmj test/bs_map_set_dict_test.cmi test/bs_map_set_dict_test.cmj test/bs_map_test.cmi test/bs_map_test.cmj test/bs_min_max_test.cmi test/bs_min_max_test.cmj test/bs_mutable_set_test.cmi test/bs_mutable_set_test.cmj test/bs_poly_map_test.cmi test/bs_poly_map_test.cmj test/bs_poly_mutable_map_test.cmi test/bs_poly_mutable_map_test.cmj test/bs_poly_mutable_set_test.cmi test/bs_poly_mutable_set_test.cmj test/bs_poly_set_test.cmi test/bs_poly_set_test.cmj test/bs_qualified.cmi test/bs_qualified.cmj test/bs_queue_test.cmi test/bs_queue_test.cmj test/bs_rbset_int_bench.cmi test/bs_rbset_int_bench.cmj test/bs_rest_test.cmi test/bs_rest_test.cmj test/bs_set_bench.cmi test/bs_set_bench.cmj test/bs_set_int_test.cmi test/bs_set_int_test.cmj test/bs_sort_test.cmi test/bs_sort_test.cmj test/bs_splice_partial.cmi test/bs_splice_partial.cmj test/bs_stack_test.cmi test/bs_stack_test.cmj test/bs_string_test.cmi test/bs_string_test.cmj test/bs_unwrap_test.cmi test/bs_unwrap_test.cmj test/buffer_test.cmi test/buffer_test.cmj test/bytes_split_gpr_743_test.cmi test/bytes_split_gpr_743_test.cmj test/caml_compare_bigint_test.cmi test/caml_compare_bigint_test.cmj test/caml_compare_test.cmi test/caml_compare_test.cmj test/caml_format_test.cmi test/caml_format_test.cmj test/chain_code_test.cmi test/chain_code_test.cmj test/chn_test.cmi test/chn_test.cmj test/class_type_ffi_test.cmi test/class_type_ffi_test.cmj test/coercion_module_alias_test.cmi test/coercion_module_alias_test.cmj test/compare_test.cmi test/compare_test.cmj test/complete_parmatch_test.cmi test/complete_parmatch_test.cmj test/complex_if_test.cmi test/complex_if_test.cmj test/complex_test.cmi test/complex_test.cmj test/complex_while_loop.cmi test/complex_while_loop.cmj test/condition_compilation_test.cmi test/condition_compilation_test.cmj test/config1_test.cmi test/config1_test.cmj test/console_log_test.cmi test/console_log_test.cmj test/const_block_test.cmi test/const_block_test.cmj test/const_defs.cmi test/const_defs.cmj test/const_defs_test.cmi test/const_defs_test.cmj test/const_test.cmi test/const_test.cmj test/cont_int_fold_test.cmi test/cont_int_fold_test.cmj test/cps_test.cmi test/cps_test.cmj test/cross_module_inline_test.cmi test/cross_module_inline_test.cmj test/custom_error_test.cmi test/custom_error_test.cmj test/debug_keep_test.cmi test/debug_keep_test.cmj test/debug_mode_value.cmi test/debug_mode_value.cmj test/debug_tmp.cmi test/debug_tmp.cmj test/debugger_test.cmi test/debugger_test.cmj test/default_export_test.cmi test/default_export_test.cmj test/defunctor_make_test.cmi test/defunctor_make_test.cmj test/demo_int_map.cmi test/demo_int_map.cmj test/demo_page.cmi test/demo_page.cmj test/demo_pipe.cmi test/demo_pipe.cmj test/derive_dyntype.cmi test/derive_dyntype.cmj test/derive_projector_test.cmi test/derive_projector_test.cmj test/derive_type_test.cmi test/derive_type_test.cmj test/digest_test.cmi test/digest_test.cmj test/directives.cmi test/directives.cmj test/div_by_zero_test.cmi test/div_by_zero_test.cmj test/dollar_escape_test.cmi test/dollar_escape_test.cmj test/earger_curry_test.cmi test/earger_curry_test.cmj test/effect.cmi test/effect.cmj test/epsilon_test.cmi test/epsilon_test.cmj test/equal_box_test.cmi test/equal_box_test.cmj test/equal_exception_test.cmi test/equal_exception_test.cmj test/equal_test.cmi test/equal_test.cmj test/es6_export.cmi test/es6_export.cmj test/es6_import.cmi test/es6_import.cmj test/es6_module_test.cmi test/es6_module_test.cmj test/escape_esmodule.cmi test/escape_esmodule.cmj test/esmodule_ref.cmi test/esmodule_ref.cmj test/event_ffi.cmi test/event_ffi.cmj test/exception_alias.cmi test/exception_alias.cmj test/exception_raise_test.cmi test/exception_raise_test.cmj test/exception_rebound_err_test.cmi test/exception_rebound_err_test.cmj test/exception_value_test.cmi test/exception_value_test.cmj test/exponentiation_precedence_test.cmi test/exponentiation_precedence_test.cmj test/export_keyword.cmi test/export_keyword.cmj test/ext_array_test.cmi test/ext_array_test.cmj test/ext_bytes_test.cmi test/ext_bytes_test.cmj test/ext_filename_test.cmi test/ext_filename_test.cmj test/ext_list_test.cmi test/ext_list_test.cmj test/ext_pervasives_test.cmi test/ext_pervasives_test.cmj test/ext_string_test.cmi test/ext_string_test.cmj test/ext_sys_test.cmi test/ext_sys_test.cmj test/extensible_variant_test.cmi test/extensible_variant_test.cmj test/external_polyfill_test.cmi test/external_polyfill_test.cmj test/external_ppx.cmi test/external_ppx.cmj test/external_ppx2.cmi test/external_ppx2.cmj test/fail_comp.cmi test/fail_comp.cmj test/ffi_arity_test.cmi test/ffi_arity_test.cmj test/ffi_array_test.cmi test/ffi_array_test.cmj test/ffi_js_test.cmi test/ffi_js_test.cmj test/ffi_splice_test.cmi test/ffi_splice_test.cmj test/ffi_test.cmi test/ffi_test.cmj test/fib.cmi test/fib.cmj test/flattern_order_test.cmi test/flattern_order_test.cmj test/flexible_array_test.cmi test/flexible_array_test.cmj test/float_array.cmi test/float_array.cmj test/float_of_bits_test.cmi test/float_of_bits_test.cmj test/float_record.cmi test/float_record.cmj test/float_test.cmi test/float_test.cmj test/floatarray_test.cmi test/floatarray_test.cmj test/for_loop_test.cmi test/for_loop_test.cmj test/for_side_effect_test.cmi test/for_side_effect_test.cmj test/format_regression.cmi test/format_regression.cmj test/format_test.cmi test/format_test.cmj test/fun_pattern_match.cmi test/fun_pattern_match.cmj test/functor_app_test.cmi test/functor_app_test.cmj test/functor_def.cmi test/functor_def.cmj test/functor_ffi.cmi test/functor_ffi.cmj test/functor_inst.cmi test/functor_inst.cmj test/functors.cmi test/functors.cmj test/gbk.cmi test/gbk.cmj test/genlex_test.cmi test/genlex_test.cmj test/gentTypeReTest.cmi test/gentTypeReTest.cmj test/global_exception_regression_test.cmi test/global_exception_regression_test.cmj test/global_mangles.cmi test/global_mangles.cmj test/global_module_alias_test.cmi test/global_module_alias_test.cmj test/google_closure_test.cmi test/google_closure_test.cmj test/gpr496_test.cmi test/gpr496_test.cmj test/gpr_1072.cmi test/gpr_1072.cmj test/gpr_1072_reg.cmi test/gpr_1072_reg.cmj test/gpr_1150.cmi test/gpr_1150.cmj test/gpr_1154_test.cmi test/gpr_1154_test.cmj test/gpr_1170.cmi test/gpr_1170.cmj test/gpr_1240_missing_unbox.cmi test/gpr_1240_missing_unbox.cmj test/gpr_1245_test.cmi test/gpr_1245_test.cmj test/gpr_1268.cmi test/gpr_1268.cmj test/gpr_1409_test.cmi test/gpr_1409_test.cmj test/gpr_1423_app_test.cmi test/gpr_1423_app_test.cmj test/gpr_1423_nav.cmi test/gpr_1423_nav.cmj test/gpr_1438.cmi test/gpr_1438.cmj test/gpr_1481.cmi test/gpr_1481.cmj test/gpr_1484.cmi test/gpr_1484.cmj test/gpr_1503_test.cmi test/gpr_1503_test.cmj test/gpr_1539_test.cmi test/gpr_1539_test.cmj test/gpr_1658_test.cmi test/gpr_1658_test.cmj test/gpr_1667_test.cmi test/gpr_1667_test.cmj test/gpr_1692_test.cmi test/gpr_1692_test.cmj test/gpr_1698_test.cmi test/gpr_1698_test.cmj test/gpr_1701_test.cmi test/gpr_1701_test.cmj test/gpr_1716_test.cmi test/gpr_1716_test.cmj test/gpr_1717_test.cmi test/gpr_1717_test.cmj test/gpr_1728_test.cmi test/gpr_1728_test.cmj test/gpr_1749_test.cmi test/gpr_1749_test.cmj test/gpr_1759_test.cmi test/gpr_1759_test.cmj test/gpr_1760_test.cmi test/gpr_1760_test.cmj test/gpr_1762_test.cmi test/gpr_1762_test.cmj test/gpr_1817_test.cmi test/gpr_1817_test.cmj test/gpr_1822_test.cmi test/gpr_1822_test.cmj test/gpr_1891_test.cmi test/gpr_1891_test.cmj test/gpr_1943_test.cmi test/gpr_1943_test.cmj test/gpr_1946_test.cmi test/gpr_1946_test.cmj test/gpr_2316_test.cmi test/gpr_2316_test.cmj test/gpr_2352_test.cmi test/gpr_2352_test.cmj test/gpr_2413_test.cmi test/gpr_2413_test.cmj test/gpr_2474.cmi test/gpr_2474.cmj test/gpr_2487.cmi test/gpr_2487.cmj test/gpr_2503_test.cmi test/gpr_2503_test.cmj test/gpr_2608_test.cmi test/gpr_2608_test.cmj test/gpr_2614_test.cmi test/gpr_2614_test.cmj test/gpr_2633_test.cmi test/gpr_2633_test.cmj test/gpr_2642_test.cmi test/gpr_2642_test.cmj test/gpr_2682_test.cmi test/gpr_2682_test.cmj test/gpr_2700_test.cmi test/gpr_2700_test.cmj test/gpr_2731_test.cmi test/gpr_2731_test.cmj test/gpr_2789_test.cmi test/gpr_2789_test.cmj test/gpr_2931_test.cmi test/gpr_2931_test.cmj test/gpr_3142_test.cmi test/gpr_3142_test.cmj test/gpr_3154_test.cmi test/gpr_3154_test.cmj test/gpr_3209_test.cmi test/gpr_3209_test.cmj test/gpr_3492_test.cmi test/gpr_3492_test.cmj test/gpr_3519_jsx_test.cmi test/gpr_3519_jsx_test.cmj test/gpr_3519_test.cmi test/gpr_3519_test.cmj test/gpr_3536_test.cmi test/gpr_3536_test.cmj test/gpr_3546_test.cmi test/gpr_3546_test.cmj test/gpr_3548_test.cmi test/gpr_3548_test.cmj test/gpr_3549_test.cmi test/gpr_3549_test.cmj test/gpr_3566_drive_test.cmi test/gpr_3566_drive_test.cmj test/gpr_3566_test.cmi test/gpr_3566_test.cmj test/gpr_3595_test.cmi test/gpr_3595_test.cmj test/gpr_3609_test.cmi test/gpr_3609_test.cmj test/gpr_3697_test.cmi test/gpr_3697_test.cmj test/gpr_373_test.cmi test/gpr_373_test.cmj test/gpr_3770_test.cmi test/gpr_3770_test.cmj test/gpr_3852_alias.cmi test/gpr_3852_alias.cmj test/gpr_3852_alias_reify.cmi test/gpr_3852_alias_reify.cmj test/gpr_3852_effect.cmi test/gpr_3852_effect.cmj test/gpr_3865.cmi test/gpr_3865.cmj test/gpr_3865_bar.cmi test/gpr_3865_bar.cmj test/gpr_3865_foo.cmi test/gpr_3865_foo.cmj test/gpr_3875_test.cmi test/gpr_3875_test.cmj test/gpr_3877_test.cmi test/gpr_3877_test.cmj test/gpr_3895_test.cmi test/gpr_3895_test.cmj test/gpr_3897_test.cmi test/gpr_3897_test.cmj test/gpr_3931_test.cmi test/gpr_3931_test.cmj test/gpr_3980_test.cmi test/gpr_3980_test.cmj test/gpr_4025_test.cmi test/gpr_4025_test.cmj test/gpr_405_test.cmi test/gpr_405_test.cmj test/gpr_4069_test.cmi test/gpr_4069_test.cmj test/gpr_4265_test.cmi test/gpr_4265_test.cmj test/gpr_4274_test.cmi test/gpr_4274_test.cmj test/gpr_4280_test.cmi test/gpr_4280_test.cmj test/gpr_4407_test.cmi test/gpr_4407_test.cmj test/gpr_441.cmi test/gpr_441.cmj test/gpr_4442_test.cmi test/gpr_4442_test.cmj test/gpr_4491_test.cmi test/gpr_4491_test.cmj test/gpr_4494_test.cmi test/gpr_4494_test.cmj test/gpr_4519_test.cmi test/gpr_4519_test.cmj test/gpr_459_test.cmi test/gpr_459_test.cmj test/gpr_4632.cmi test/gpr_4632.cmj test/gpr_4639_test.cmi test/gpr_4639_test.cmj test/gpr_4900_test.cmi test/gpr_4900_test.cmj test/gpr_4924_test.cmi test/gpr_4924_test.cmj test/gpr_4931.cmi test/gpr_4931.cmj test/gpr_4931_allow.cmi test/gpr_4931_allow.cmj test/gpr_5071_test.cmi test/gpr_5071_test.cmj test/gpr_5169_test.cmi test/gpr_5169_test.cmj test/gpr_5218_test.cmi test/gpr_5218_test.cmj test/gpr_5280_optimize_test.cmi test/gpr_5280_optimize_test.cmj test/gpr_5312.cmi test/gpr_5312.cmj test/gpr_5557.cmi test/gpr_5557.cmj test/gpr_5753.cmi test/gpr_5753.cmj test/gpr_658.cmi test/gpr_658.cmj test/gpr_858_test.cmi test/gpr_858_test.cmj test/gpr_858_unit2_test.cmi test/gpr_858_unit2_test.cmj test/gpr_904_test.cmi test/gpr_904_test.cmj test/gpr_974_test.cmi test/gpr_974_test.cmj test/gpr_977_test.cmi test/gpr_977_test.cmj test/gpr_return_type_unused_attribute.cmi test/gpr_return_type_unused_attribute.cmj test/gray_code_test.cmi test/gray_code_test.cmj test/guide_for_ext.cmi test/guide_for_ext.cmj test/hamming_test.cmi test/hamming_test.cmj test/hash_collision_test.cmi test/hash_collision_test.cmj test/hash_sugar_desugar.cmi test/hash_sugar_desugar.cmj test/hash_test.cmi test/hash_test.cmj test/hashtbl_test.cmi test/hashtbl_test.cmj test/hello.foo.cmi test/hello.foo.cmj test/hello_res.cmi test/hello_res.cmj test/ignore_test.cmi test/ignore_test.cmj test/imm_map_bench.cmi test/imm_map_bench.cmj test/import_side_effect.cmi test/import_side_effect.cmj test/import_side_effect_free.cmi test/import_side_effect_free.cmj test/include_side_effect.cmi test/include_side_effect.cmj test/include_side_effect_free.cmi test/include_side_effect_free.cmj test/incomplete_toplevel_test.cmi test/incomplete_toplevel_test.cmj test/infer_type_test.cmi test/infer_type_test.cmj test/inline_condition_with_pattern_matching.cmi test/inline_condition_with_pattern_matching.cmj test/inline_const.cmi test/inline_const.cmj test/inline_const_test.cmi test/inline_const_test.cmj test/inline_edge_cases.cmi test/inline_edge_cases.cmj test/inline_map2_test.cmi test/inline_map2_test.cmj test/inline_map_demo.cmi test/inline_map_demo.cmj test/inline_map_test.cmi test/inline_map_test.cmj test/inline_record_test.cmi test/inline_record_test.cmj test/inline_regression_test.cmi test/inline_regression_test.cmj test/inline_string_test.cmi test/inline_string_test.cmj test/inner_call.cmi test/inner_call.cmj test/inner_define.cmi test/inner_define.cmj test/inner_unused.cmi test/inner_unused.cmj test/installation_test.cmi test/installation_test.cmj test/int32_test.cmi test/int32_test.cmj test/int64_mul_div_test.cmi test/int64_mul_div_test.cmj test/int64_string_bench.cmi test/int64_string_bench.cmj test/int64_string_test.cmi test/int64_string_test.cmj test/int64_test.cmi test/int64_test.cmj test/int_hashtbl_test.cmi test/int_hashtbl_test.cmj test/int_map.cmi test/int_map.cmj test/int_overflow_test.cmi test/int_overflow_test.cmj test/int_poly_var.cmi test/int_poly_var.cmj test/int_switch_test.cmi test/int_switch_test.cmj test/internal_unused_test.cmi test/internal_unused_test.cmj test/io_test.cmi test/io_test.cmj test/js_array_test.cmi test/js_array_test.cmj test/js_bool_test.cmi test/js_bool_test.cmj test/js_cast_test.cmi test/js_cast_test.cmj test/js_date_test.cmi test/js_date_test.cmj test/js_dict_test.cmi test/js_dict_test.cmj test/js_exception_catch_test.cmi test/js_exception_catch_test.cmj test/js_float_test.cmi test/js_float_test.cmj test/js_global_test.cmi test/js_global_test.cmj test/js_int_test.cmi test/js_int_test.cmj test/js_json_test.cmi test/js_json_test.cmj test/js_list_test.cmi test/js_list_test.cmj test/js_math_test.cmi test/js_math_test.cmj test/js_null_test.cmi test/js_null_test.cmj test/js_null_undefined_test.cmi test/js_null_undefined_test.cmj test/js_nullable_test.cmi test/js_nullable_test.cmj test/js_obj_test.cmi test/js_obj_test.cmj test/js_option_test.cmi test/js_option_test.cmj test/js_re_test.cmi test/js_re_test.cmj test/js_string_test.cmi test/js_string_test.cmj test/js_typed_array_test.cmi test/js_typed_array_test.cmj test/js_undefined_test.cmi test/js_undefined_test.cmj test/js_val.cmi test/js_val.cmj test/jsoo_400_test.cmi test/jsoo_400_test.cmj test/jsoo_485_test.cmi test/jsoo_485_test.cmj test/jsxv4_newtype.cmi test/jsxv4_newtype.cmj test/key_word_property.cmi test/key_word_property.cmj test/key_word_property2.cmi test/key_word_property2.cmj test/key_word_property_plus_test.cmi test/key_word_property_plus_test.cmj test/label_uncurry.cmi test/label_uncurry.cmj test/large_integer_pat.cmi test/large_integer_pat.cmj test/large_record_duplication_test.cmi test/large_record_duplication_test.cmj test/largest_int_flow.cmi test/largest_int_flow.cmj test/lazy_demo.cmi test/lazy_demo.cmj test/lazy_test.cmi test/lazy_test.cmj test/lib_js_test.cmi test/lib_js_test.cmj test/libarg_test.cmi test/libarg_test.cmj test/libqueue_test.cmi test/libqueue_test.cmj test/limits_test.cmi test/limits_test.cmj test/list_stack.cmi test/list_stack.cmj test/list_test.cmi test/list_test.cmj test/local_exception_test.cmi test/local_exception_test.cmj test/loop_regression_test.cmi test/loop_regression_test.cmj test/loop_suites_test.cmi test/loop_suites_test.cmj test/map_find_test.cmi test/map_find_test.cmj test/map_test.cmi test/map_test.cmj test/mario_game.cmi test/mario_game.cmj test/marshal.cmi test/marshal.cmj test/meth_annotation.cmi test/meth_annotation.cmj test/method_name_test.cmi test/method_name_test.cmj test/method_string_name.cmi test/method_string_name.cmj test/minimal_test.cmi test/minimal_test.cmj test/miss_colon_test.cmi test/miss_colon_test.cmj test/mock_mt.cmi test/mock_mt.cmj test/module_alias_test.cmi test/module_alias_test.cmj test/module_as_class_ffi.cmi test/module_as_class_ffi.cmj test/module_as_function.cmi test/module_as_function.cmj test/module_missing_conversion.cmi test/module_missing_conversion.cmj test/module_parameter_test.cmi test/module_parameter_test.cmj test/module_splice_test.cmi test/module_splice_test.cmj test/more_poly_variant_test.cmi test/more_poly_variant_test.cmj test/more_uncurry.cmi test/more_uncurry.cmj test/mpr_6033_test.cmi test/mpr_6033_test.cmj test/mt.cmi test/mt.cmj test/mt_global.cmi test/mt_global.cmj test/mutable_obj_test.cmi test/mutable_obj_test.cmj test/mutable_uncurry_test.cmi test/mutable_uncurry_test.cmj test/mutual_non_recursive_type.cmi test/mutual_non_recursive_type.cmj test/name_mangle_test.cmi test/name_mangle_test.cmj test/nested_include.cmi test/nested_include.cmj test/nested_module_alias.cmi test/nested_module_alias.cmj test/nested_obj_literal.cmi test/nested_obj_literal.cmj test/nested_obj_test.cmi test/nested_obj_test.cmj test/nested_pattern_match_test.cmi test/nested_pattern_match_test.cmj test/noassert.cmi test/noassert.cmj test/node_path_test.cmi test/node_path_test.cmj test/null_list_test.cmi test/null_list_test.cmj test/number_lexer.cmi test/number_lexer.cmj test/obj_literal_ppx.cmi test/obj_literal_ppx.cmj test/obj_literal_ppx_test.cmi test/obj_literal_ppx_test.cmj test/obj_magic_test.cmi test/obj_magic_test.cmj test/obj_type_test.cmi test/obj_type_test.cmj test/ocaml_re_test.cmi test/ocaml_re_test.cmj test/of_string_test.cmi test/of_string_test.cmj test/offset.cmi test/offset.cmj test/option_encoding_test.cmi test/option_encoding_test.cmj test/option_record_none_test.cmi test/option_record_none_test.cmj test/option_repr_test.cmi test/option_repr_test.cmj test/optional_ffi_test.cmi test/optional_ffi_test.cmj test/optional_regression_test.cmi test/optional_regression_test.cmj test/pipe_send_readline.cmi test/pipe_send_readline.cmj test/pipe_syntax.cmi test/pipe_syntax.cmj test/poly_empty_array.cmi test/poly_empty_array.cmj test/poly_variant_test.cmi test/poly_variant_test.cmj test/polymorphic_raw_test.cmi test/polymorphic_raw_test.cmj test/polymorphism_test.cmi test/polymorphism_test.cmj test/polyvar_convert.cmi test/polyvar_convert.cmj test/polyvar_test.cmi test/polyvar_test.cmj test/ppx_apply_test.cmi test/ppx_apply_test.cmj test/pq_test.cmi test/pq_test.cmj test/pr6726.cmi test/pr6726.cmj test/pr_regression_test.cmi test/pr_regression_test.cmj test/prepend_data_ffi.cmi test/prepend_data_ffi.cmj test/primitive_reg_test.cmi test/primitive_reg_test.cmj test/print_alpha_test.cmi test/print_alpha_test.cmj test/queue_402.cmi test/queue_402.cmj test/queue_test.cmi test/queue_test.cmj test/random_test.cmi test/random_test.cmj test/raw_hash_tbl_bench.cmi test/raw_hash_tbl_bench.cmj test/raw_output_test.cmi test/raw_output_test.cmj test/raw_pure_test.cmi test/raw_pure_test.cmj test/rbset.cmi test/rbset.cmj test/react.cmi test/react.cmj test/reactDOMRe.cmi test/reactDOMRe.cmj test/reactDOMServerRe.cmi test/reactDOMServerRe.cmj test/reactEvent.cmi test/reactEvent.cmj test/reactTestUtils.cmi test/reactTestUtils.cmj test/reasonReact.cmi test/reasonReact.cmj test/reasonReactCompat.cmi test/reasonReactCompat.cmj test/reasonReactOptimizedCreateClass.cmi test/reasonReactOptimizedCreateClass.cmj test/reasonReactRouter.cmi test/reasonReactRouter.cmj test/rebind_module.cmi test/rebind_module.cmj test/rebind_module_test.cmi test/rebind_module_test.cmj test/rec_array_test.cmi test/rec_array_test.cmj test/rec_fun_test.cmi test/rec_fun_test.cmj test/rec_module_opt.cmi test/rec_module_opt.cmj test/rec_module_test.cmi test/rec_module_test.cmj test/recmodule.cmi test/recmodule.cmj test/record_debug_test.cmi test/record_debug_test.cmj test/record_extension_test.cmi test/record_extension_test.cmj test/record_name_test.cmi test/record_name_test.cmj test/record_regression.cmi test/record_regression.cmj test/record_type_spread.cmi test/record_type_spread.cmj test/record_with_test.cmi test/record_with_test.cmj test/recursive_module.cmi test/recursive_module.cmj test/recursive_module_test.cmi test/recursive_module_test.cmj test/recursive_react_component.cmi test/recursive_react_component.cmj test/recursive_records_test.cmi test/recursive_records_test.cmj test/recursive_unbound_module_test.cmi test/recursive_unbound_module_test.cmj test/regression_print.cmi test/regression_print.cmj test/relative_path.cmi test/relative_path.cmj test/res_debug.cmi test/res_debug.cmj test/return_check.cmi test/return_check.cmj test/runtime_encoding_test.cmi test/runtime_encoding_test.cmj test/set_annotation.cmi test/set_annotation.cmj test/set_gen.cmi test/set_gen.cmj test/sexp.cmi test/sexp.cmj test/sexpm.cmi test/sexpm.cmj test/sexpm_test.cmi test/sexpm_test.cmj test/side_effect.cmi test/side_effect.cmj test/side_effect2.cmi test/side_effect2.cmj test/side_effect_free.cmi test/side_effect_free.cmj test/simple_derive_test.cmi test/simple_derive_test.cmj test/simple_derive_use.cmi test/simple_derive_use.cmj test/simplify_lambda_632o.cmi test/simplify_lambda_632o.cmj test/single_module_alias.cmi test/single_module_alias.cmj test/singular_unit_test.cmi test/singular_unit_test.cmj test/small_inline_test.cmi test/small_inline_test.cmj test/splice_test.cmi test/splice_test.cmj test/stack_comp_test.cmi test/stack_comp_test.cmj test/stack_test.cmi test/stack_test.cmj test/stream_parser_test.cmi test/stream_parser_test.cmj test/string_bound_get_test.cmi test/string_bound_get_test.cmj test/string_constant_compare.cmi test/string_constant_compare.cmj test/string_get_set_test.cmi test/string_get_set_test.cmj test/string_runtime_test.cmi test/string_runtime_test.cmj test/string_set.cmi test/string_set.cmj test/string_set_test.cmi test/string_set_test.cmj test/string_test.cmi test/string_test.cmj test/string_unicode_test.cmi test/string_unicode_test.cmj test/stringmatch_test.cmi test/stringmatch_test.cmj test/submodule.cmi test/submodule.cmj test/submodule_call.cmi test/submodule_call.cmj test/switch_case_test.cmi test/switch_case_test.cmj test/switch_string.cmi test/switch_string.cmj test/tailcall_inline_test.cmi test/tailcall_inline_test.cmj test/template.cmi test/template.cmj test/test.cmi test/test.cmj test/test2.cmi test/test2.cmj test/test_alias.cmi test/test_alias.cmj test/test_ari.cmi test/test_ari.cmj test/test_array.cmi test/test_array.cmj test/test_array_append.cmi test/test_array_append.cmj test/test_array_primitive.cmi test/test_array_primitive.cmj test/test_bool_equal.cmi test/test_bool_equal.cmj test/test_bs_this.cmi test/test_bs_this.cmj test/test_bug.cmi test/test_bug.cmj test/test_bytes.cmi test/test_bytes.cmj test/test_case_opt_collision.cmi test/test_case_opt_collision.cmj test/test_case_set.cmi test/test_case_set.cmj test/test_char.cmi test/test_char.cmj test/test_closure.cmi test/test_closure.cmj test/test_common.cmi test/test_common.cmj test/test_const_elim.cmi test/test_const_elim.cmj test/test_const_propogate.cmi test/test_const_propogate.cmj test/test_cpp.cmi test/test_cpp.cmj test/test_cps.cmi test/test_cps.cmj test/test_demo.cmi test/test_demo.cmj test/test_dup_param.cmi test/test_dup_param.cmj test/test_eq.cmi test/test_eq.cmj test/test_exception.cmi test/test_exception.cmj test/test_exception_escape.cmi test/test_exception_escape.cmj test/test_export2.cmi test/test_export2.cmj test/test_external.cmi test/test_external.cmj test/test_external_unit.cmi test/test_external_unit.cmj test/test_ffi.cmi test/test_ffi.cmj test/test_fib.cmi test/test_fib.cmj test/test_filename.cmi test/test_filename.cmj test/test_for_loop.cmi test/test_for_loop.cmj test/test_for_map.cmi test/test_for_map.cmj test/test_for_map2.cmi test/test_for_map2.cmj test/test_format.cmi test/test_format.cmj test/test_formatter.cmi test/test_formatter.cmj test/test_functor_dead_code.cmi test/test_functor_dead_code.cmj test/test_generative_module.cmi test/test_generative_module.cmj test/test_global_print.cmi test/test_global_print.cmj test/test_google_closure.cmi test/test_google_closure.cmj test/test_include.cmi test/test_include.cmj test/test_incomplete.cmi test/test_incomplete.cmj test/test_incr_ref.cmi test/test_incr_ref.cmj test/test_int_map_find.cmi test/test_int_map_find.cmj test/test_internalOO.cmi test/test_internalOO.cmj test/test_is_js.cmi test/test_is_js.cmj test/test_js_ffi.cmi test/test_js_ffi.cmj test/test_let.cmi test/test_let.cmj test/test_list.cmi test/test_list.cmj test/test_literal.cmi test/test_literal.cmj test/test_literals.cmi test/test_literals.cmj test/test_match_exception.cmi test/test_match_exception.cmj test/test_mutliple.cmi test/test_mutliple.cmj test/test_nat64.cmi test/test_nat64.cmj test/test_nested_let.cmi test/test_nested_let.cmj test/test_nested_print.cmi test/test_nested_print.cmj test/test_non_export.cmi test/test_non_export.cmj test/test_nullary.cmi test/test_nullary.cmj test/test_obj.cmi test/test_obj.cmj test/test_order.cmi test/test_order.cmj test/test_order_tailcall.cmi test/test_order_tailcall.cmj test/test_other_exn.cmi test/test_other_exn.cmj test/test_pack.cmi test/test_pack.cmj test/test_per.cmi test/test_per.cmj test/test_pervasive.cmi test/test_pervasive.cmj test/test_pervasives2.cmi test/test_pervasives2.cmj test/test_pervasives3.cmi test/test_pervasives3.cmj test/test_primitive.cmi test/test_primitive.cmj test/test_ramification.cmi test/test_ramification.cmj test/test_react.cmi test/test_react.cmj test/test_react_case.cmi test/test_react_case.cmj test/test_regex.cmi test/test_regex.cmj test/test_runtime_encoding.cmi test/test_runtime_encoding.cmj test/test_scope.cmi test/test_scope.cmj test/test_seq.cmi test/test_seq.cmj test/test_set.cmi test/test_set.cmj test/test_side_effect_functor.cmi test/test_side_effect_functor.cmj test/test_simple_include.cmi test/test_simple_include.cmj test/test_simple_pattern_match.cmi test/test_simple_pattern_match.cmj test/test_simple_ref.cmi test/test_simple_ref.cmj test/test_simple_tailcall.cmi test/test_simple_tailcall.cmj test/test_small.cmi test/test_small.cmj test/test_sprintf.cmi test/test_sprintf.cmj test/test_stack.cmi test/test_stack.cmj test/test_static_catch_ident.cmi test/test_static_catch_ident.cmj test/test_string.cmi test/test_string.cmj test/test_string_case.cmi test/test_string_case.cmj test/test_string_const.cmi test/test_string_const.cmj test/test_string_map.cmi test/test_string_map.cmj test/test_string_switch.cmi test/test_string_switch.cmj test/test_switch.cmi test/test_switch.cmj test/test_trywith.cmi test/test_trywith.cmj test/test_tuple.cmi test/test_tuple.cmj test/test_tuple_destructring.cmi test/test_tuple_destructring.cmj test/test_type_based_arity.cmi test/test_type_based_arity.cmj test/test_u.cmi test/test_u.cmj test/test_unknown.cmi test/test_unknown.cmj test/test_unsafe_cmp.cmi test/test_unsafe_cmp.cmj test/test_unsafe_obj_ffi.cmi test/test_unsafe_obj_ffi.cmj test/test_unsafe_obj_ffi_ppx.cmi test/test_unsafe_obj_ffi_ppx.cmj test/test_unsupported_primitive.cmi test/test_unsupported_primitive.cmj test/test_while_closure.cmi test/test_while_closure.cmj test/test_while_side_effect.cmi test/test_while_side_effect.cmj test/test_zero_nullable.cmi test/test_zero_nullable.cmj test/then_mangle_test.cmi test/then_mangle_test.cmj test/ticker.cmi test/ticker.cmj test/to_string_test.cmi test/to_string_test.cmj test/topsort_test.cmi test/topsort_test.cmj test/tramp_fib.cmi test/tramp_fib.cmj test/tuple_alloc.cmi test/tuple_alloc.cmj test/type_disambiguate.cmi test/type_disambiguate.cmj test/typeof_test.cmi test/typeof_test.cmj test/unboxed_attribute.cmi test/unboxed_attribute.cmj test/unboxed_attribute_test.cmi test/unboxed_attribute_test.cmj test/unboxed_crash.cmi test/unboxed_crash.cmj test/unboxed_use_case.cmi test/unboxed_use_case.cmj test/uncurried_cast.cmi test/uncurried_cast.cmj test/uncurried_default.args.cmi test/uncurried_default.args.cmj test/uncurried_pipe.cmi test/uncurried_pipe.cmj test/uncurry_external_test.cmi test/uncurry_external_test.cmj test/uncurry_glob_test.cmi test/uncurry_glob_test.cmj test/uncurry_test.cmi test/uncurry_test.cmj test/undef_regression2_test.cmi test/undef_regression2_test.cmj test/undef_regression_test.cmi test/undef_regression_test.cmj test/undefine_conditional.cmi test/undefine_conditional.cmj test/unicode_type_error.cmi test/unicode_type_error.cmj test/unit_undefined_test.cmi test/unit_undefined_test.cmj test/unitest_string.cmi test/unitest_string.cmj test/unsafe_full_apply_primitive.cmi test/unsafe_full_apply_primitive.cmj test/unsafe_ppx_test.cmi test/unsafe_ppx_test.cmj test/update_record_test.cmi test/update_record_test.cmj test/variant.cmi test/variant.cmj test/variantsMatching.cmi test/variantsMatching.cmj test/webpack_config.cmi test/webpack_config.cmj +o test : phony test/406_primitive_test.cmi test/406_primitive_test.cmj test/AsInUncurriedExternals.cmi test/AsInUncurriedExternals.cmj test/Coercion.cmi test/Coercion.cmj test/DotDotDot.cmi test/DotDotDot.cmj test/EmptyRecord.cmi test/EmptyRecord.cmj test/FFI.cmi test/FFI.cmj test/Import.cmi test/Import.cmj test/RecordCoercion.cmi test/RecordCoercion.cmj test/RecordOrObject.cmi test/RecordOrObject.cmj test/SafePromises.cmi test/SafePromises.cmj test/UncurriedAlways.cmi test/UncurriedAlways.cmj test/UncurriedExternals.cmi test/UncurriedExternals.cmj test/UncurriedPervasives.cmi test/UncurriedPervasives.cmj test/UntaggedVariants.cmi test/UntaggedVariants.cmj test/VariantCoercion.cmi test/VariantCoercion.cmj test/VariantSpreads.cmi test/VariantSpreads.cmj test/a.cmi test/a.cmj test/a_filename_test.cmi test/a_filename_test.cmj test/a_list_test.cmi test/a_list_test.cmj test/a_recursive_type.cmi test/a_recursive_type.cmj test/a_scope_bug.cmi test/a_scope_bug.cmj test/a_string_test.cmi test/a_string_test.cmj test/abstract_type.cmi test/abstract_type.cmj test/adt_optimize_test.cmi test/adt_optimize_test.cmj test/alias_default_value_test.cmi test/alias_default_value_test.cmj test/alias_test.cmi test/alias_test.cmj test/and_or_tailcall_test.cmi test/and_or_tailcall_test.cmj test/argv_test.cmi test/argv_test.cmj test/ari_regress_test.cmi test/ari_regress_test.cmj test/arith_lexer.cmi test/arith_lexer.cmj test/arith_parser.cmi test/arith_parser.cmj test/arith_syntax.cmi test/arith_syntax.cmj test/arity.cmi test/arity.cmj test/arity_deopt.cmi test/arity_deopt.cmj test/arity_infer.cmi test/arity_infer.cmj test/array_data_util.cmi test/array_data_util.cmj test/array_safe_get.cmi test/array_safe_get.cmj test/array_subtle_test.cmi test/array_subtle_test.cmj test/array_test.cmi test/array_test.cmj test/as_inline_record_test.cmi test/as_inline_record_test.cmj test/ast_abstract_test.cmi test/ast_abstract_test.cmj test/ast_mapper_unused_warning_test.cmi test/ast_mapper_unused_warning_test.cmj test/async_await.cmi test/async_await.cmj test/async_ideas.cmi test/async_ideas.cmj test/async_inline.cmi test/async_inline.cmj test/async_inside_loop.cmi test/async_inside_loop.cmj test/attr_test.cmi test/attr_test.cmj test/b.cmi test/b.cmj test/bal_set_mini.cmi test/bal_set_mini.cmj test/bang_primitive.cmi test/bang_primitive.cmj test/basic_module_test.cmi test/basic_module_test.cmj test/bb.cmi test/bb.cmj test/bdd.cmi test/bdd.cmj test/belt_internal_test.cmi test/belt_internal_test.cmj test/belt_result_alias_test.cmi test/belt_result_alias_test.cmj test/bench.cmi test/bench.cmj test/big_enum.cmi test/big_enum.cmj test/big_polyvar_test.cmi test/big_polyvar_test.cmj test/block_alias_test.cmi test/block_alias_test.cmj test/boolean_test.cmi test/boolean_test.cmj test/bs_MapInt_test.cmi test/bs_MapInt_test.cmj test/bs_abstract_test.cmi test/bs_abstract_test.cmj test/bs_array_test.cmi test/bs_array_test.cmj test/bs_auto_uncurry.cmi test/bs_auto_uncurry.cmj test/bs_auto_uncurry_test.cmi test/bs_auto_uncurry_test.cmj test/bs_float_test.cmi test/bs_float_test.cmj test/bs_hashmap_test.cmi test/bs_hashmap_test.cmj test/bs_hashset_int_test.cmi test/bs_hashset_int_test.cmj test/bs_hashtbl_string_test.cmi test/bs_hashtbl_string_test.cmj test/bs_ignore_effect.cmi test/bs_ignore_effect.cmj test/bs_ignore_test.cmi test/bs_ignore_test.cmj test/bs_int_test.cmi test/bs_int_test.cmj test/bs_list_test.cmi test/bs_list_test.cmj test/bs_map_set_dict_test.cmi test/bs_map_set_dict_test.cmj test/bs_map_test.cmi test/bs_map_test.cmj test/bs_min_max_test.cmi test/bs_min_max_test.cmj test/bs_mutable_set_test.cmi test/bs_mutable_set_test.cmj test/bs_poly_map_test.cmi test/bs_poly_map_test.cmj test/bs_poly_mutable_map_test.cmi test/bs_poly_mutable_map_test.cmj test/bs_poly_mutable_set_test.cmi test/bs_poly_mutable_set_test.cmj test/bs_poly_set_test.cmi test/bs_poly_set_test.cmj test/bs_qualified.cmi test/bs_qualified.cmj test/bs_queue_test.cmi test/bs_queue_test.cmj test/bs_rbset_int_bench.cmi test/bs_rbset_int_bench.cmj test/bs_rest_test.cmi test/bs_rest_test.cmj test/bs_set_bench.cmi test/bs_set_bench.cmj test/bs_set_int_test.cmi test/bs_set_int_test.cmj test/bs_sort_test.cmi test/bs_sort_test.cmj test/bs_splice_partial.cmi test/bs_splice_partial.cmj test/bs_stack_test.cmi test/bs_stack_test.cmj test/bs_string_test.cmi test/bs_string_test.cmj test/bs_unwrap_test.cmi test/bs_unwrap_test.cmj test/buffer_test.cmi test/buffer_test.cmj test/bytes_split_gpr_743_test.cmi test/bytes_split_gpr_743_test.cmj test/caml_compare_bigint_test.cmi test/caml_compare_bigint_test.cmj test/caml_compare_test.cmi test/caml_compare_test.cmj test/caml_format_test.cmi test/caml_format_test.cmj test/chain_code_test.cmi test/chain_code_test.cmj test/chn_test.cmi test/chn_test.cmj test/class_type_ffi_test.cmi test/class_type_ffi_test.cmj test/coercion_module_alias_test.cmi test/coercion_module_alias_test.cmj test/compare_test.cmi test/compare_test.cmj test/complete_parmatch_test.cmi test/complete_parmatch_test.cmj test/complex_if_test.cmi test/complex_if_test.cmj test/complex_test.cmi test/complex_test.cmj test/complex_while_loop.cmi test/complex_while_loop.cmj test/condition_compilation_test.cmi test/condition_compilation_test.cmj test/config1_test.cmi test/config1_test.cmj test/console_log_test.cmi test/console_log_test.cmj test/const_block_test.cmi test/const_block_test.cmj test/const_defs.cmi test/const_defs.cmj test/const_defs_test.cmi test/const_defs_test.cmj test/const_test.cmi test/const_test.cmj test/cont_int_fold_test.cmi test/cont_int_fold_test.cmj test/cps_test.cmi test/cps_test.cmj test/cross_module_inline_test.cmi test/cross_module_inline_test.cmj test/custom_error_test.cmi test/custom_error_test.cmj test/debug_keep_test.cmi test/debug_keep_test.cmj test/debug_mode_value.cmi test/debug_mode_value.cmj test/debug_tmp.cmi test/debug_tmp.cmj test/debugger_test.cmi test/debugger_test.cmj test/default_export_test.cmi test/default_export_test.cmj test/defunctor_make_test.cmi test/defunctor_make_test.cmj test/demo_int_map.cmi test/demo_int_map.cmj test/demo_page.cmi test/demo_page.cmj test/demo_pipe.cmi test/demo_pipe.cmj test/derive_dyntype.cmi test/derive_dyntype.cmj test/derive_projector_test.cmi test/derive_projector_test.cmj test/derive_type_test.cmi test/derive_type_test.cmj test/digest_test.cmi test/digest_test.cmj test/directives.cmi test/directives.cmj test/div_by_zero_test.cmi test/div_by_zero_test.cmj test/dollar_escape_test.cmi test/dollar_escape_test.cmj test/earger_curry_test.cmi test/earger_curry_test.cmj test/effect.cmi test/effect.cmj test/epsilon_test.cmi test/epsilon_test.cmj test/equal_box_test.cmi test/equal_box_test.cmj test/equal_exception_test.cmi test/equal_exception_test.cmj test/equal_test.cmi test/equal_test.cmj test/es6_export.cmi test/es6_export.cmj test/es6_import.cmi test/es6_import.cmj test/es6_module_test.cmi test/es6_module_test.cmj test/escape_esmodule.cmi test/escape_esmodule.cmj test/esmodule_ref.cmi test/esmodule_ref.cmj test/event_ffi.cmi test/event_ffi.cmj test/exception_alias.cmi test/exception_alias.cmj test/exception_raise_test.cmi test/exception_raise_test.cmj test/exception_rebound_err_test.cmi test/exception_rebound_err_test.cmj test/exception_value_test.cmi test/exception_value_test.cmj test/exponentiation_precedence_test.cmi test/exponentiation_precedence_test.cmj test/export_keyword.cmi test/export_keyword.cmj test/ext_array_test.cmi test/ext_array_test.cmj test/ext_bytes_test.cmi test/ext_bytes_test.cmj test/ext_filename_test.cmi test/ext_filename_test.cmj test/ext_list_test.cmi test/ext_list_test.cmj test/ext_pervasives_test.cmi test/ext_pervasives_test.cmj test/ext_string_test.cmi test/ext_string_test.cmj test/ext_sys_test.cmi test/ext_sys_test.cmj test/extensible_variant_test.cmi test/extensible_variant_test.cmj test/external_polyfill_test.cmi test/external_polyfill_test.cmj test/external_ppx.cmi test/external_ppx.cmj test/external_ppx2.cmi test/external_ppx2.cmj test/fail_comp.cmi test/fail_comp.cmj test/ffi_arity_test.cmi test/ffi_arity_test.cmj test/ffi_array_test.cmi test/ffi_array_test.cmj test/ffi_js_test.cmi test/ffi_js_test.cmj test/ffi_splice_test.cmi test/ffi_splice_test.cmj test/ffi_test.cmi test/ffi_test.cmj test/fib.cmi test/fib.cmj test/flattern_order_test.cmi test/flattern_order_test.cmj test/flexible_array_test.cmi test/flexible_array_test.cmj test/float_array.cmi test/float_array.cmj test/float_of_bits_test.cmi test/float_of_bits_test.cmj test/float_record.cmi test/float_record.cmj test/float_test.cmi test/float_test.cmj test/floatarray_test.cmi test/floatarray_test.cmj test/for_loop_test.cmi test/for_loop_test.cmj test/for_side_effect_test.cmi test/for_side_effect_test.cmj test/format_regression.cmi test/format_regression.cmj test/format_test.cmi test/format_test.cmj test/fun_pattern_match.cmi test/fun_pattern_match.cmj test/functor_app_test.cmi test/functor_app_test.cmj test/functor_def.cmi test/functor_def.cmj test/functor_ffi.cmi test/functor_ffi.cmj test/functor_inst.cmi test/functor_inst.cmj test/functors.cmi test/functors.cmj test/gbk.cmi test/gbk.cmj test/genlex_test.cmi test/genlex_test.cmj test/gentTypeReTest.cmi test/gentTypeReTest.cmj test/global_exception_regression_test.cmi test/global_exception_regression_test.cmj test/global_mangles.cmi test/global_mangles.cmj test/global_module_alias_test.cmi test/global_module_alias_test.cmj test/google_closure_test.cmi test/google_closure_test.cmj test/gpr496_test.cmi test/gpr496_test.cmj test/gpr_1072.cmi test/gpr_1072.cmj test/gpr_1072_reg.cmi test/gpr_1072_reg.cmj test/gpr_1150.cmi test/gpr_1150.cmj test/gpr_1154_test.cmi test/gpr_1154_test.cmj test/gpr_1170.cmi test/gpr_1170.cmj test/gpr_1240_missing_unbox.cmi test/gpr_1240_missing_unbox.cmj test/gpr_1245_test.cmi test/gpr_1245_test.cmj test/gpr_1268.cmi test/gpr_1268.cmj test/gpr_1409_test.cmi test/gpr_1409_test.cmj test/gpr_1423_app_test.cmi test/gpr_1423_app_test.cmj test/gpr_1423_nav.cmi test/gpr_1423_nav.cmj test/gpr_1438.cmi test/gpr_1438.cmj test/gpr_1481.cmi test/gpr_1481.cmj test/gpr_1484.cmi test/gpr_1484.cmj test/gpr_1503_test.cmi test/gpr_1503_test.cmj test/gpr_1539_test.cmi test/gpr_1539_test.cmj test/gpr_1658_test.cmi test/gpr_1658_test.cmj test/gpr_1667_test.cmi test/gpr_1667_test.cmj test/gpr_1692_test.cmi test/gpr_1692_test.cmj test/gpr_1698_test.cmi test/gpr_1698_test.cmj test/gpr_1701_test.cmi test/gpr_1701_test.cmj test/gpr_1716_test.cmi test/gpr_1716_test.cmj test/gpr_1717_test.cmi test/gpr_1717_test.cmj test/gpr_1728_test.cmi test/gpr_1728_test.cmj test/gpr_1749_test.cmi test/gpr_1749_test.cmj test/gpr_1759_test.cmi test/gpr_1759_test.cmj test/gpr_1760_test.cmi test/gpr_1760_test.cmj test/gpr_1762_test.cmi test/gpr_1762_test.cmj test/gpr_1817_test.cmi test/gpr_1817_test.cmj test/gpr_1822_test.cmi test/gpr_1822_test.cmj test/gpr_1891_test.cmi test/gpr_1891_test.cmj test/gpr_1943_test.cmi test/gpr_1943_test.cmj test/gpr_1946_test.cmi test/gpr_1946_test.cmj test/gpr_2316_test.cmi test/gpr_2316_test.cmj test/gpr_2352_test.cmi test/gpr_2352_test.cmj test/gpr_2413_test.cmi test/gpr_2413_test.cmj test/gpr_2474.cmi test/gpr_2474.cmj test/gpr_2487.cmi test/gpr_2487.cmj test/gpr_2503_test.cmi test/gpr_2503_test.cmj test/gpr_2608_test.cmi test/gpr_2608_test.cmj test/gpr_2614_test.cmi test/gpr_2614_test.cmj test/gpr_2633_test.cmi test/gpr_2633_test.cmj test/gpr_2642_test.cmi test/gpr_2642_test.cmj test/gpr_2682_test.cmi test/gpr_2682_test.cmj test/gpr_2700_test.cmi test/gpr_2700_test.cmj test/gpr_2731_test.cmi test/gpr_2731_test.cmj test/gpr_2789_test.cmi test/gpr_2789_test.cmj test/gpr_2931_test.cmi test/gpr_2931_test.cmj test/gpr_3142_test.cmi test/gpr_3142_test.cmj test/gpr_3154_test.cmi test/gpr_3154_test.cmj test/gpr_3209_test.cmi test/gpr_3209_test.cmj test/gpr_3492_test.cmi test/gpr_3492_test.cmj test/gpr_3519_jsx_test.cmi test/gpr_3519_jsx_test.cmj test/gpr_3519_test.cmi test/gpr_3519_test.cmj test/gpr_3536_test.cmi test/gpr_3536_test.cmj test/gpr_3546_test.cmi test/gpr_3546_test.cmj test/gpr_3548_test.cmi test/gpr_3548_test.cmj test/gpr_3549_test.cmi test/gpr_3549_test.cmj test/gpr_3566_drive_test.cmi test/gpr_3566_drive_test.cmj test/gpr_3566_test.cmi test/gpr_3566_test.cmj test/gpr_3595_test.cmi test/gpr_3595_test.cmj test/gpr_3609_test.cmi test/gpr_3609_test.cmj test/gpr_3697_test.cmi test/gpr_3697_test.cmj test/gpr_373_test.cmi test/gpr_373_test.cmj test/gpr_3770_test.cmi test/gpr_3770_test.cmj test/gpr_3852_alias.cmi test/gpr_3852_alias.cmj test/gpr_3852_alias_reify.cmi test/gpr_3852_alias_reify.cmj test/gpr_3852_effect.cmi test/gpr_3852_effect.cmj test/gpr_3865.cmi test/gpr_3865.cmj test/gpr_3865_bar.cmi test/gpr_3865_bar.cmj test/gpr_3865_foo.cmi test/gpr_3865_foo.cmj test/gpr_3875_test.cmi test/gpr_3875_test.cmj test/gpr_3877_test.cmi test/gpr_3877_test.cmj test/gpr_3895_test.cmi test/gpr_3895_test.cmj test/gpr_3897_test.cmi test/gpr_3897_test.cmj test/gpr_3931_test.cmi test/gpr_3931_test.cmj test/gpr_3980_test.cmi test/gpr_3980_test.cmj test/gpr_4025_test.cmi test/gpr_4025_test.cmj test/gpr_405_test.cmi test/gpr_405_test.cmj test/gpr_4069_test.cmi test/gpr_4069_test.cmj test/gpr_4265_test.cmi test/gpr_4265_test.cmj test/gpr_4274_test.cmi test/gpr_4274_test.cmj test/gpr_4280_test.cmi test/gpr_4280_test.cmj test/gpr_4407_test.cmi test/gpr_4407_test.cmj test/gpr_441.cmi test/gpr_441.cmj test/gpr_4442_test.cmi test/gpr_4442_test.cmj test/gpr_4491_test.cmi test/gpr_4491_test.cmj test/gpr_4494_test.cmi test/gpr_4494_test.cmj test/gpr_4519_test.cmi test/gpr_4519_test.cmj test/gpr_459_test.cmi test/gpr_459_test.cmj test/gpr_4632.cmi test/gpr_4632.cmj test/gpr_4639_test.cmi test/gpr_4639_test.cmj test/gpr_4900_test.cmi test/gpr_4900_test.cmj test/gpr_4924_test.cmi test/gpr_4924_test.cmj test/gpr_4931.cmi test/gpr_4931.cmj test/gpr_4931_allow.cmi test/gpr_4931_allow.cmj test/gpr_5071_test.cmi test/gpr_5071_test.cmj test/gpr_5169_test.cmi test/gpr_5169_test.cmj test/gpr_5218_test.cmi test/gpr_5218_test.cmj test/gpr_5280_optimize_test.cmi test/gpr_5280_optimize_test.cmj test/gpr_5312.cmi test/gpr_5312.cmj test/gpr_5557.cmi test/gpr_5557.cmj test/gpr_5753.cmi test/gpr_5753.cmj test/gpr_658.cmi test/gpr_658.cmj test/gpr_858_test.cmi test/gpr_858_test.cmj test/gpr_858_unit2_test.cmi test/gpr_858_unit2_test.cmj test/gpr_904_test.cmi test/gpr_904_test.cmj test/gpr_974_test.cmi test/gpr_974_test.cmj test/gpr_977_test.cmi test/gpr_977_test.cmj test/gpr_return_type_unused_attribute.cmi test/gpr_return_type_unused_attribute.cmj test/gray_code_test.cmi test/gray_code_test.cmj test/guide_for_ext.cmi test/guide_for_ext.cmj test/hamming_test.cmi test/hamming_test.cmj test/hash_collision_test.cmi test/hash_collision_test.cmj test/hash_sugar_desugar.cmi test/hash_sugar_desugar.cmj test/hash_test.cmi test/hash_test.cmj test/hashtbl_test.cmi test/hashtbl_test.cmj test/hello.foo.cmi test/hello.foo.cmj test/hello_res.cmi test/hello_res.cmj test/ignore_test.cmi test/ignore_test.cmj test/imm_map_bench.cmi test/imm_map_bench.cmj test/import_side_effect.cmi test/import_side_effect.cmj test/import_side_effect_free.cmi test/import_side_effect_free.cmj test/include_side_effect.cmi test/include_side_effect.cmj test/include_side_effect_free.cmi test/include_side_effect_free.cmj test/incomplete_toplevel_test.cmi test/incomplete_toplevel_test.cmj test/infer_type_test.cmi test/infer_type_test.cmj test/inline_condition_with_pattern_matching.cmi test/inline_condition_with_pattern_matching.cmj test/inline_const.cmi test/inline_const.cmj test/inline_const_test.cmi test/inline_const_test.cmj test/inline_edge_cases.cmi test/inline_edge_cases.cmj test/inline_map2_test.cmi test/inline_map2_test.cmj test/inline_map_demo.cmi test/inline_map_demo.cmj test/inline_map_test.cmi test/inline_map_test.cmj test/inline_record_test.cmi test/inline_record_test.cmj test/inline_regression_test.cmi test/inline_regression_test.cmj test/inline_string_test.cmi test/inline_string_test.cmj test/inner_call.cmi test/inner_call.cmj test/inner_define.cmi test/inner_define.cmj test/inner_unused.cmi test/inner_unused.cmj test/installation_test.cmi test/installation_test.cmj test/int32_test.cmi test/int32_test.cmj test/int64_mul_div_test.cmi test/int64_mul_div_test.cmj test/int64_string_bench.cmi test/int64_string_bench.cmj test/int64_string_test.cmi test/int64_string_test.cmj test/int64_test.cmi test/int64_test.cmj test/int_hashtbl_test.cmi test/int_hashtbl_test.cmj test/int_map.cmi test/int_map.cmj test/int_overflow_test.cmi test/int_overflow_test.cmj test/int_poly_var.cmi test/int_poly_var.cmj test/int_switch_test.cmi test/int_switch_test.cmj test/internal_unused_test.cmi test/internal_unused_test.cmj test/io_test.cmi test/io_test.cmj test/js_array_test.cmi test/js_array_test.cmj test/js_bool_test.cmi test/js_bool_test.cmj test/js_cast_test.cmi test/js_cast_test.cmj test/js_date_test.cmi test/js_date_test.cmj test/js_dict_test.cmi test/js_dict_test.cmj test/js_exception_catch_test.cmi test/js_exception_catch_test.cmj test/js_float_test.cmi test/js_float_test.cmj test/js_global_test.cmi test/js_global_test.cmj test/js_int_test.cmi test/js_int_test.cmj test/js_json_test.cmi test/js_json_test.cmj test/js_list_test.cmi test/js_list_test.cmj test/js_math_test.cmi test/js_math_test.cmj test/js_null_test.cmi test/js_null_test.cmj test/js_null_undefined_test.cmi test/js_null_undefined_test.cmj test/js_nullable_test.cmi test/js_nullable_test.cmj test/js_obj_test.cmi test/js_obj_test.cmj test/js_option_test.cmi test/js_option_test.cmj test/js_re_test.cmi test/js_re_test.cmj test/js_string_test.cmi test/js_string_test.cmj test/js_typed_array_test.cmi test/js_typed_array_test.cmj test/js_undefined_test.cmi test/js_undefined_test.cmj test/js_val.cmi test/js_val.cmj test/jsoo_400_test.cmi test/jsoo_400_test.cmj test/jsoo_485_test.cmi test/jsoo_485_test.cmj test/jsxv4_newtype.cmi test/jsxv4_newtype.cmj test/key_word_property.cmi test/key_word_property.cmj test/key_word_property2.cmi test/key_word_property2.cmj test/key_word_property_plus_test.cmi test/key_word_property_plus_test.cmj test/label_uncurry.cmi test/label_uncurry.cmj test/large_integer_pat.cmi test/large_integer_pat.cmj test/large_record_duplication_test.cmi test/large_record_duplication_test.cmj test/largest_int_flow.cmi test/largest_int_flow.cmj test/lazy_demo.cmi test/lazy_demo.cmj test/lazy_test.cmi test/lazy_test.cmj test/lib_js_test.cmi test/lib_js_test.cmj test/libarg_test.cmi test/libarg_test.cmj test/libqueue_test.cmi test/libqueue_test.cmj test/limits_test.cmi test/limits_test.cmj test/list_stack.cmi test/list_stack.cmj test/list_test.cmi test/list_test.cmj test/local_exception_test.cmi test/local_exception_test.cmj test/loop_regression_test.cmi test/loop_regression_test.cmj test/loop_suites_test.cmi test/loop_suites_test.cmj test/map_find_test.cmi test/map_find_test.cmj test/map_test.cmi test/map_test.cmj test/mario_game.cmi test/mario_game.cmj test/marshal.cmi test/marshal.cmj test/meth_annotation.cmi test/meth_annotation.cmj test/method_name_test.cmi test/method_name_test.cmj test/method_string_name.cmi test/method_string_name.cmj test/minimal_test.cmi test/minimal_test.cmj test/miss_colon_test.cmi test/miss_colon_test.cmj test/mock_mt.cmi test/mock_mt.cmj test/module_alias_test.cmi test/module_alias_test.cmj test/module_as_class_ffi.cmi test/module_as_class_ffi.cmj test/module_as_function.cmi test/module_as_function.cmj test/module_missing_conversion.cmi test/module_missing_conversion.cmj test/module_parameter_test.cmi test/module_parameter_test.cmj test/module_splice_test.cmi test/module_splice_test.cmj test/more_poly_variant_test.cmi test/more_poly_variant_test.cmj test/more_uncurry.cmi test/more_uncurry.cmj test/mpr_6033_test.cmi test/mpr_6033_test.cmj test/mt.cmi test/mt.cmj test/mt_global.cmi test/mt_global.cmj test/mutable_obj_test.cmi test/mutable_obj_test.cmj test/mutable_uncurry_test.cmi test/mutable_uncurry_test.cmj test/mutual_non_recursive_type.cmi test/mutual_non_recursive_type.cmj test/name_mangle_test.cmi test/name_mangle_test.cmj test/nested_include.cmi test/nested_include.cmj test/nested_module_alias.cmi test/nested_module_alias.cmj test/nested_obj_literal.cmi test/nested_obj_literal.cmj test/nested_obj_test.cmi test/nested_obj_test.cmj test/nested_pattern_match_test.cmi test/nested_pattern_match_test.cmj test/noassert.cmi test/noassert.cmj test/node_path_test.cmi test/node_path_test.cmj test/null_list_test.cmi test/null_list_test.cmj test/number_lexer.cmi test/number_lexer.cmj test/obj_literal_ppx.cmi test/obj_literal_ppx.cmj test/obj_literal_ppx_test.cmi test/obj_literal_ppx_test.cmj test/obj_magic_test.cmi test/obj_magic_test.cmj test/obj_type_test.cmi test/obj_type_test.cmj test/ocaml_re_test.cmi test/ocaml_re_test.cmj test/of_string_test.cmi test/of_string_test.cmj test/offset.cmi test/offset.cmj test/option_encoding_test.cmi test/option_encoding_test.cmj test/option_record_none_test.cmi test/option_record_none_test.cmj test/option_repr_test.cmi test/option_repr_test.cmj test/optional_ffi_test.cmi test/optional_ffi_test.cmj test/optional_regression_test.cmi test/optional_regression_test.cmj test/pipe_send_readline.cmi test/pipe_send_readline.cmj test/pipe_syntax.cmi test/pipe_syntax.cmj test/poly_empty_array.cmi test/poly_empty_array.cmj test/poly_variant_test.cmi test/poly_variant_test.cmj test/polymorphic_raw_test.cmi test/polymorphic_raw_test.cmj test/polymorphism_test.cmi test/polymorphism_test.cmj test/polyvar_convert.cmi test/polyvar_convert.cmj test/polyvar_test.cmi test/polyvar_test.cmj test/ppx_apply_test.cmi test/ppx_apply_test.cmj test/pq_test.cmi test/pq_test.cmj test/pr6726.cmi test/pr6726.cmj test/pr_regression_test.cmi test/pr_regression_test.cmj test/prepend_data_ffi.cmi test/prepend_data_ffi.cmj test/primitive_reg_test.cmi test/primitive_reg_test.cmj test/print_alpha_test.cmi test/print_alpha_test.cmj test/queue_402.cmi test/queue_402.cmj test/queue_test.cmi test/queue_test.cmj test/random_test.cmi test/random_test.cmj test/raw_hash_tbl_bench.cmi test/raw_hash_tbl_bench.cmj test/raw_output_test.cmi test/raw_output_test.cmj test/raw_pure_test.cmi test/raw_pure_test.cmj test/rbset.cmi test/rbset.cmj test/react.cmi test/react.cmj test/reactDOMRe.cmi test/reactDOMRe.cmj test/reactDOMServerRe.cmi test/reactDOMServerRe.cmj test/reactEvent.cmi test/reactEvent.cmj test/reactTestUtils.cmi test/reactTestUtils.cmj test/reasonReact.cmi test/reasonReact.cmj test/reasonReactCompat.cmi test/reasonReactCompat.cmj test/reasonReactOptimizedCreateClass.cmi test/reasonReactOptimizedCreateClass.cmj test/reasonReactRouter.cmi test/reasonReactRouter.cmj test/rebind_module.cmi test/rebind_module.cmj test/rebind_module_test.cmi test/rebind_module_test.cmj test/rec_array_test.cmi test/rec_array_test.cmj test/rec_fun_test.cmi test/rec_fun_test.cmj test/rec_module_opt.cmi test/rec_module_opt.cmj test/rec_module_test.cmi test/rec_module_test.cmj test/recmodule.cmi test/recmodule.cmj test/record_debug_test.cmi test/record_debug_test.cmj test/record_extension_test.cmi test/record_extension_test.cmj test/record_name_test.cmi test/record_name_test.cmj test/record_regression.cmi test/record_regression.cmj test/record_type_spread.cmi test/record_type_spread.cmj test/record_with_test.cmi test/record_with_test.cmj test/recursive_module.cmi test/recursive_module.cmj test/recursive_module_test.cmi test/recursive_module_test.cmj test/recursive_react_component.cmi test/recursive_react_component.cmj test/recursive_records_test.cmi test/recursive_records_test.cmj test/recursive_unbound_module_test.cmi test/recursive_unbound_module_test.cmj test/regression_print.cmi test/regression_print.cmj test/relative_path.cmi test/relative_path.cmj test/res_debug.cmi test/res_debug.cmj test/return_check.cmi test/return_check.cmj test/runtime_encoding_test.cmi test/runtime_encoding_test.cmj test/set_annotation.cmi test/set_annotation.cmj test/set_gen.cmi test/set_gen.cmj test/sexp.cmi test/sexp.cmj test/sexpm.cmi test/sexpm.cmj test/sexpm_test.cmi test/sexpm_test.cmj test/side_effect.cmi test/side_effect.cmj test/side_effect2.cmi test/side_effect2.cmj test/side_effect_free.cmi test/side_effect_free.cmj test/simple_derive_test.cmi test/simple_derive_test.cmj test/simple_derive_use.cmi test/simple_derive_use.cmj test/simplify_lambda_632o.cmi test/simplify_lambda_632o.cmj test/single_module_alias.cmi test/single_module_alias.cmj test/singular_unit_test.cmi test/singular_unit_test.cmj test/small_inline_test.cmi test/small_inline_test.cmj test/splice_test.cmi test/splice_test.cmj test/stack_comp_test.cmi test/stack_comp_test.cmj test/stack_test.cmi test/stack_test.cmj test/stream_parser_test.cmi test/stream_parser_test.cmj test/string_bound_get_test.cmi test/string_bound_get_test.cmj test/string_constant_compare.cmi test/string_constant_compare.cmj test/string_get_set_test.cmi test/string_get_set_test.cmj test/string_runtime_test.cmi test/string_runtime_test.cmj test/string_set.cmi test/string_set.cmj test/string_set_test.cmi test/string_set_test.cmj test/string_test.cmi test/string_test.cmj test/string_unicode_test.cmi test/string_unicode_test.cmj test/stringmatch_test.cmi test/stringmatch_test.cmj test/submodule.cmi test/submodule.cmj test/submodule_call.cmi test/submodule_call.cmj test/switch_case_test.cmi test/switch_case_test.cmj test/switch_string.cmi test/switch_string.cmj test/tagged_template_test.cmi test/tagged_template_test.cmj test/tailcall_inline_test.cmi test/tailcall_inline_test.cmj test/template.cmi test/template.cmj test/test.cmi test/test.cmj test/test2.cmi test/test2.cmj test/test_alias.cmi test/test_alias.cmj test/test_ari.cmi test/test_ari.cmj test/test_array.cmi test/test_array.cmj test/test_array_append.cmi test/test_array_append.cmj test/test_array_primitive.cmi test/test_array_primitive.cmj test/test_bool_equal.cmi test/test_bool_equal.cmj test/test_bs_this.cmi test/test_bs_this.cmj test/test_bug.cmi test/test_bug.cmj test/test_bytes.cmi test/test_bytes.cmj test/test_case_opt_collision.cmi test/test_case_opt_collision.cmj test/test_case_set.cmi test/test_case_set.cmj test/test_char.cmi test/test_char.cmj test/test_closure.cmi test/test_closure.cmj test/test_common.cmi test/test_common.cmj test/test_const_elim.cmi test/test_const_elim.cmj test/test_const_propogate.cmi test/test_const_propogate.cmj test/test_cpp.cmi test/test_cpp.cmj test/test_cps.cmi test/test_cps.cmj test/test_demo.cmi test/test_demo.cmj test/test_dup_param.cmi test/test_dup_param.cmj test/test_eq.cmi test/test_eq.cmj test/test_exception.cmi test/test_exception.cmj test/test_exception_escape.cmi test/test_exception_escape.cmj test/test_export2.cmi test/test_export2.cmj test/test_external.cmi test/test_external.cmj test/test_external_unit.cmi test/test_external_unit.cmj test/test_ffi.cmi test/test_ffi.cmj test/test_fib.cmi test/test_fib.cmj test/test_filename.cmi test/test_filename.cmj test/test_for_loop.cmi test/test_for_loop.cmj test/test_for_map.cmi test/test_for_map.cmj test/test_for_map2.cmi test/test_for_map2.cmj test/test_format.cmi test/test_format.cmj test/test_formatter.cmi test/test_formatter.cmj test/test_functor_dead_code.cmi test/test_functor_dead_code.cmj test/test_generative_module.cmi test/test_generative_module.cmj test/test_global_print.cmi test/test_global_print.cmj test/test_google_closure.cmi test/test_google_closure.cmj test/test_include.cmi test/test_include.cmj test/test_incomplete.cmi test/test_incomplete.cmj test/test_incr_ref.cmi test/test_incr_ref.cmj test/test_int_map_find.cmi test/test_int_map_find.cmj test/test_internalOO.cmi test/test_internalOO.cmj test/test_is_js.cmi test/test_is_js.cmj test/test_js_ffi.cmi test/test_js_ffi.cmj test/test_let.cmi test/test_let.cmj test/test_list.cmi test/test_list.cmj test/test_literal.cmi test/test_literal.cmj test/test_literals.cmi test/test_literals.cmj test/test_match_exception.cmi test/test_match_exception.cmj test/test_mutliple.cmi test/test_mutliple.cmj test/test_nat64.cmi test/test_nat64.cmj test/test_nested_let.cmi test/test_nested_let.cmj test/test_nested_print.cmi test/test_nested_print.cmj test/test_non_export.cmi test/test_non_export.cmj test/test_nullary.cmi test/test_nullary.cmj test/test_obj.cmi test/test_obj.cmj test/test_order.cmi test/test_order.cmj test/test_order_tailcall.cmi test/test_order_tailcall.cmj test/test_other_exn.cmi test/test_other_exn.cmj test/test_pack.cmi test/test_pack.cmj test/test_per.cmi test/test_per.cmj test/test_pervasive.cmi test/test_pervasive.cmj test/test_pervasives2.cmi test/test_pervasives2.cmj test/test_pervasives3.cmi test/test_pervasives3.cmj test/test_primitive.cmi test/test_primitive.cmj test/test_ramification.cmi test/test_ramification.cmj test/test_react.cmi test/test_react.cmj test/test_react_case.cmi test/test_react_case.cmj test/test_regex.cmi test/test_regex.cmj test/test_runtime_encoding.cmi test/test_runtime_encoding.cmj test/test_scope.cmi test/test_scope.cmj test/test_seq.cmi test/test_seq.cmj test/test_set.cmi test/test_set.cmj test/test_side_effect_functor.cmi test/test_side_effect_functor.cmj test/test_simple_include.cmi test/test_simple_include.cmj test/test_simple_pattern_match.cmi test/test_simple_pattern_match.cmj test/test_simple_ref.cmi test/test_simple_ref.cmj test/test_simple_tailcall.cmi test/test_simple_tailcall.cmj test/test_small.cmi test/test_small.cmj test/test_sprintf.cmi test/test_sprintf.cmj test/test_stack.cmi test/test_stack.cmj test/test_static_catch_ident.cmi test/test_static_catch_ident.cmj test/test_string.cmi test/test_string.cmj test/test_string_case.cmi test/test_string_case.cmj test/test_string_const.cmi test/test_string_const.cmj test/test_string_map.cmi test/test_string_map.cmj test/test_string_switch.cmi test/test_string_switch.cmj test/test_switch.cmi test/test_switch.cmj test/test_trywith.cmi test/test_trywith.cmj test/test_tuple.cmi test/test_tuple.cmj test/test_tuple_destructring.cmi test/test_tuple_destructring.cmj test/test_type_based_arity.cmi test/test_type_based_arity.cmj test/test_u.cmi test/test_u.cmj test/test_unknown.cmi test/test_unknown.cmj test/test_unsafe_cmp.cmi test/test_unsafe_cmp.cmj test/test_unsafe_obj_ffi.cmi test/test_unsafe_obj_ffi.cmj test/test_unsafe_obj_ffi_ppx.cmi test/test_unsafe_obj_ffi_ppx.cmj test/test_unsupported_primitive.cmi test/test_unsupported_primitive.cmj test/test_while_closure.cmi test/test_while_closure.cmj test/test_while_side_effect.cmi test/test_while_side_effect.cmj test/test_zero_nullable.cmi test/test_zero_nullable.cmj test/then_mangle_test.cmi test/then_mangle_test.cmj test/ticker.cmi test/ticker.cmj test/to_string_test.cmi test/to_string_test.cmj test/topsort_test.cmi test/topsort_test.cmj test/tramp_fib.cmi test/tramp_fib.cmj test/tuple_alloc.cmi test/tuple_alloc.cmj test/type_disambiguate.cmi test/type_disambiguate.cmj test/typeof_test.cmi test/typeof_test.cmj test/unboxed_attribute.cmi test/unboxed_attribute.cmj test/unboxed_attribute_test.cmi test/unboxed_attribute_test.cmj test/unboxed_crash.cmi test/unboxed_crash.cmj test/unboxed_use_case.cmi test/unboxed_use_case.cmj test/uncurried_cast.cmi test/uncurried_cast.cmj test/uncurried_default.args.cmi test/uncurried_default.args.cmj test/uncurried_pipe.cmi test/uncurried_pipe.cmj test/uncurry_external_test.cmi test/uncurry_external_test.cmj test/uncurry_glob_test.cmi test/uncurry_glob_test.cmj test/uncurry_test.cmi test/uncurry_test.cmj test/undef_regression2_test.cmi test/undef_regression2_test.cmj test/undef_regression_test.cmi test/undef_regression_test.cmj test/undefine_conditional.cmi test/undefine_conditional.cmj test/unicode_type_error.cmi test/unicode_type_error.cmj test/unit_undefined_test.cmi test/unit_undefined_test.cmj test/unitest_string.cmi test/unitest_string.cmj test/unsafe_full_apply_primitive.cmi test/unsafe_full_apply_primitive.cmj test/unsafe_ppx_test.cmi test/unsafe_ppx_test.cmj test/update_record_test.cmi test/update_record_test.cmj test/variant.cmi test/variant.cmj test/variantsMatching.cmi test/variantsMatching.cmj test/webpack_config.cmi test/webpack_config.cmj diff --git a/jscomp/test/tagged_template_test.js b/jscomp/test/tagged_template_test.js index b0ff14b1da..1e77efc27e 100644 --- a/jscomp/test/tagged_template_test.js +++ b/jscomp/test/tagged_template_test.js @@ -1,3 +1,4 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; var Mt = require("./mt.js"); @@ -22,7 +23,7 @@ Mt.from_pair_suites("tagged template", { "it should return a string with the correct interpolations", (function (param) { return { - TAG: /* Eq */0, + TAG: "Eq", _0: query, _1: "SELECT * FROM users WHERE id = 5" }; @@ -35,4 +36,4 @@ exports.sql = sql; exports.table = table; exports.id = id; exports.query = query; -/* query Not a pure module */ \ No newline at end of file +/* query Not a pure module */ From 1eb180f4f20c5670d392a2d71e0ca355693df4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 15:55:46 +0200 Subject: [PATCH 03/22] add more tests for tagged templates --- jscomp/test/build.ninja | 3 +- jscomp/test/tagged_template_test.js | 59 +++++++++++++++++++-------- jscomp/test/tagged_template_test.res | 34 ++++++++++++--- jscomp/test/tagged_template_test.resi | 0 4 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 jscomp/test/tagged_template_test.resi diff --git a/jscomp/test/build.ninja b/jscomp/test/build.ninja index ea1a6d613c..024a7fab23 100644 --- a/jscomp/test/build.ninja +++ b/jscomp/test/build.ninja @@ -575,7 +575,8 @@ o test/submodule.cmi test/submodule.cmj : cc test/submodule.res | $bsc $stdlib r o test/submodule_call.cmi test/submodule_call.cmj : cc test/submodule_call.res | test/submodule.cmj $bsc $stdlib runtime o test/switch_case_test.cmi test/switch_case_test.cmj : cc test/switch_case_test.res | test/mt.cmj $bsc $stdlib runtime o test/switch_string.cmi test/switch_string.cmj : cc test/switch_string.res | $bsc $stdlib runtime -o test/tagged_template_test.cmi test/tagged_template_test.cmj : cc test/tagged_template_test.res | test/mt.cmj $bsc $stdlib runtime +o test/tagged_template_test.cmj : cc_cmi test/tagged_template_test.res | test/mt.cmj test/tagged_template_test.cmi $bsc $stdlib runtime +o test/tagged_template_test.cmi : cc test/tagged_template_test.resi | $bsc $stdlib runtime o test/tailcall_inline_test.cmi test/tailcall_inline_test.cmj : cc test/tailcall_inline_test.res | test/mt.cmj $bsc $stdlib runtime o test/template.cmi test/template.cmj : cc test/template.res | $bsc $stdlib runtime o test/test.cmi test/test.cmj : cc test/test.res | $bsc $stdlib runtime diff --git a/jscomp/test/tagged_template_test.js b/jscomp/test/tagged_template_test.js index 1e77efc27e..2fdcbb28b9 100644 --- a/jscomp/test/tagged_template_test.js +++ b/jscomp/test/tagged_template_test.js @@ -2,25 +2,28 @@ 'use strict'; var Mt = require("./mt.js"); -var Caml_splice_call = require("../../lib/js/caml_splice_call.js"); +var Caml_array = require("../../lib/js/caml_array.js"); var Tagged_template_libJs = require("./tagged_template_lib.js"); -function sql(prim0, prim1) { - return Caml_splice_call.spliceApply(Tagged_template_libJs.sql, [ - prim0, - prim1 - ]); -} - -var table = "users"; +var query = Tagged_template_libJs.sql`SELECT * FROM users WHERE id = 5`; -var id = "5"; +function foo(strings, values) { + var res = ""; + var valueCount = values.length; + for(var i = 0; i < valueCount; ++i){ + res = res + Caml_array.get(strings, i) + String(Math.imul(Caml_array.get(values, i), 10)); + } + return res + Caml_array.get(strings, valueCount); +} -var query = Tagged_template_libJs.sql`SELECT * FROM ${table} WHERE id = ${id}`; +var res = foo([ + "| 5 * 10 = ", + " |" + ], [5]); -Mt.from_pair_suites("tagged template", { +Mt.from_pair_suites("tagged templates", { hd: [ - "it should return a string with the correct interpolations", + "with externals, it should return a string with the correct interpolations", (function (param) { return { TAG: "Eq", @@ -29,11 +32,31 @@ Mt.from_pair_suites("tagged template", { }; }) ], - tl: /* [] */0 + tl: { + hd: [ + "with rescript function, it should return a string with the correct interpolations", + (function (param) { + return { + TAG: "Eq", + _0: res, + _1: "| 5 * 10 = 50 |" + }; + }) + ], + tl: { + hd: [ + "a template literal tagged with json should generate a regular string interpolation for now", + (function (param) { + return { + TAG: "Eq", + _0: "some random " + "string", + _1: "some random string" + }; + }) + ], + tl: /* [] */0 + } + } }); -exports.sql = sql; -exports.table = table; -exports.id = id; -exports.query = query; /* query Not a pure module */ diff --git a/jscomp/test/tagged_template_test.res b/jscomp/test/tagged_template_test.res index 09ec5e22a5..5302ec777a 100644 --- a/jscomp/test/tagged_template_test.res +++ b/jscomp/test/tagged_template_test.res @@ -1,14 +1,36 @@ -@module("./tagged_template_lib.js") @variadic external sql: (array, array) => string = "sql" +@module("./tagged_template_lib.js") @variadic +external sql: (array, array) => string = "sql" let table = "users" let id = "5" let query = sql`SELECT * FROM ${table} WHERE id = ${id}` +let foo = (strings, values) => { + let res = ref("") + let valueCount = Array.length(values) + for i in 0 to valueCount - 1 { + res := res.contents ++ strings[i] ++ string_of_int(values[i] * 10) + } + res.contents ++ strings[valueCount] +} + +let res = foo`| 5 * 10 = ${5} |` + Mt.from_pair_suites( - "tagged template", - list{ - ("it should return a string with the correct interpolations", () => - Eq(query, "SELECT * FROM users WHERE id = 5")), - } + "tagged templates", + list{ + ( + "with externals, it should return a string with the correct interpolations", + () => Eq(query, "SELECT * FROM users WHERE id = 5"), + ), + ( + "with rescript function, it should return a string with the correct interpolations", + () => Eq(res, "| 5 * 10 = 50 |"), + ), + ( + "a template literal tagged with json should generate a regular string interpolation for now", + () => Eq(json`some random ${"string"}`, "some random string"), + ), + }, ) \ No newline at end of file diff --git a/jscomp/test/tagged_template_test.resi b/jscomp/test/tagged_template_test.resi new file mode 100644 index 0000000000..e69de29bb2 From 05618df993bea52ecdc95207b97ec16f9a78be04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 16:01:37 +0200 Subject: [PATCH 04/22] fix side effect detection for tagged templates --- jscomp/core/js_analyzer.ml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/jscomp/core/js_analyzer.ml b/jscomp/core/js_analyzer.ml index 68edf5677d..38845ea586 100644 --- a/jscomp/core/js_analyzer.ml +++ b/jscomp/core/js_analyzer.ml @@ -103,12 +103,7 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = | String_append (a, b) | Seq (a, b) -> no_side_effect a && no_side_effect b | Length (e, _) | Caml_block_tag (e, _) | Typeof e -> no_side_effect e | Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b - (* - TODO: we should check look at each of the expressions in the 'values' list/array - to determine if any of them have side-effects. For now we'll just return false - to make the compiler happy. - *) - | Tagged_template _ -> false + | Tagged_template (_call_expr, _strings, values) -> Ext_list.for_all values no_side_effect | Js_not _ | Cond _ | FlatCall _ | Call _ | New _ | Raw_js_code _ (* actually true? *) -> false From 8a9f1ce9c7e05d46f12818758ef8c6bee36b3d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 16:15:38 +0200 Subject: [PATCH 05/22] fix expression_desc for tagged templates --- jscomp/core/js_record_fold.ml | 6 ++++-- jscomp/core/js_record_iter.ml | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/jscomp/core/js_record_fold.ml b/jscomp/core/js_record_fold.ml index b4a41bc177..b92ca551ad 100644 --- a/jscomp/core/js_record_fold.ml +++ b/jscomp/core/js_record_fold.ml @@ -130,8 +130,10 @@ let expression_desc : 'a. ('a, expression_desc) fn = let st = _self.expression _self st _x0 in let st = list _self.expression _self st _x1 in st - | Tagged_template (_, _, _) -> - (* TODO: implement this *) + | Tagged_template (_xo, _x1, _x2) -> + let st = _self.expression _self st _xo in + let st = list _self.expression _self st _x1 in + let st = list _self.expression _self st _x2 in st | String_index (_x0, _x1) -> let st = _self.expression _self st _x0 in diff --git a/jscomp/core/js_record_iter.ml b/jscomp/core/js_record_iter.ml index ff55592c02..cbbc9f41e2 100644 --- a/jscomp/core/js_record_iter.ml +++ b/jscomp/core/js_record_iter.ml @@ -107,9 +107,10 @@ let expression_desc : expression_desc fn = | Call (_x0, _x1, _x2) -> _self.expression _self _x0; list _self.expression _self _x1 - | Tagged_template (exprCall, _, _) -> - (* TODO: implement this *) - _self.expression _self exprCall; + | Tagged_template (_x0, _x1, _x2) -> + _self.expression _self _x0; + list _self.expression _self _x1; + list _self.expression _self _x2 | String_index (_x0, _x1) -> _self.expression _self _x0; _self.expression _self _x1 From f8511eecadc38be745f831ffd9cd196c2bc6cb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 16:38:12 +0200 Subject: [PATCH 06/22] move logic to lam_compile_external_call --- jscomp/core/lam_compile_external_call.ml | 16 ++++++++++++++++ jscomp/core/lam_compile_external_call.mli | 10 +++++----- jscomp/core/lam_compile_primitive.ml | 16 +--------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/jscomp/core/lam_compile_external_call.ml b/jscomp/core/lam_compile_external_call.ml index fea98b5b6b..fa2b53f017 100644 --- a/jscomp/core/lam_compile_external_call.ml +++ b/jscomp/core/lam_compile_external_call.ml @@ -381,3 +381,19 @@ let translate_ffi (cxt : Lam_compile_context.t) arg_types | [ obj; v; value ] -> Js_arr.set_array (translate_scoped_access scopes obj) v value | _ -> assert false) + +let translate_tagged_template (cxt : Lam_compile_context.t) + (ffi : External_ffi_types.external_spec) (args : J.expression list) = + let fn = match ffi with + | Js_call { external_module_name; name; scopes; _ } -> + translate_scoped_module_val external_module_name name scopes + | _ -> assert false + in + match args with + | [ stringArgs; valueArgs ] -> ( + match (stringArgs, valueArgs) with + | ({expression_desc = Array (strings, _); _}, {expression_desc = Array (values, _); _}) -> + E.tagged_template fn strings values + | _ -> assert false + ) + | _ -> assert false \ No newline at end of file diff --git a/jscomp/core/lam_compile_external_call.mli b/jscomp/core/lam_compile_external_call.mli index 7fef8470ca..b9d5d74ee5 100644 --- a/jscomp/core/lam_compile_external_call.mli +++ b/jscomp/core/lam_compile_external_call.mli @@ -36,11 +36,11 @@ val translate_ffi : J.expression list -> J.expression -val translate_scoped_module_val : - External_ffi_types.external_module_name option -> - string -> - string list -> - J.expression +val translate_tagged_template : + Lam_compile_context.t -> + External_ffi_types.external_spec -> + J.expression list -> + J.expression (** TODO: document supported attributes Attributes starting with `js` are reserved diff --git a/jscomp/core/lam_compile_primitive.ml b/jscomp/core/lam_compile_primitive.ml index 44f6d2f57b..9a487fa875 100644 --- a/jscomp/core/lam_compile_primitive.ml +++ b/jscomp/core/lam_compile_primitive.ml @@ -339,21 +339,7 @@ let translate output_prefix loc (cxt : Lam_compile_context.t) | Pjs_object_create _ -> assert false | Pjs_call { arg_types; ffi } -> Lam_compile_external_call.translate_ffi cxt arg_types ffi args - | Pjs_tagged_template { ffi } -> ( - (* TODO: extract this into lam_compile_external_call.ml *) - let fn = match ffi with - | Js_call { external_module_name; name; scopes } -> - Lam_compile_external_call.translate_scoped_module_val external_module_name name scopes - | _ -> assert false - in - match args with - | [ stringArgs; valueArgs ] -> ( - match (stringArgs, valueArgs) with - | ({expression_desc = Array (strings, _)}, {expression_desc = Array (values, _)}) -> - E.tagged_template fn strings values - | _ -> assert false - ) - | _ -> assert false) + | Pjs_tagged_template { ffi } -> Lam_compile_external_call.translate_tagged_template cxt ffi args (* FIXME, this can be removed later *) | Pisint -> E.is_type_number (Ext_list.singleton_exn args) | Pis_poly_var_block -> E.is_type_object (Ext_list.singleton_exn args) From 3a07888b447ed48117a08492015ffbbc614bba2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 17:14:34 +0200 Subject: [PATCH 07/22] improve side effect detection for tagged templates --- jscomp/core/js_analyzer.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jscomp/core/js_analyzer.ml b/jscomp/core/js_analyzer.ml index 38845ea586..233050d0d9 100644 --- a/jscomp/core/js_analyzer.ml +++ b/jscomp/core/js_analyzer.ml @@ -103,7 +103,8 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) = | String_append (a, b) | Seq (a, b) -> no_side_effect a && no_side_effect b | Length (e, _) | Caml_block_tag (e, _) | Typeof e -> no_side_effect e | Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b - | Tagged_template (_call_expr, _strings, values) -> Ext_list.for_all values no_side_effect + | Tagged_template (call_expr, strings, values) -> no_side_effect call_expr && + Ext_list.for_all strings no_side_effect && Ext_list.for_all values no_side_effect | Js_not _ | Cond _ | FlatCall _ | Call _ | New _ | Raw_js_code _ (* actually true? *) -> false From 483ccd21908176e46b0ee7c7564cdab213ece465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 10 May 2023 17:20:33 +0200 Subject: [PATCH 08/22] make the test slightly more complex the goal is to test abusive inlining of the resulting string --- jscomp/test/tagged_template_lib.js | 2 +- jscomp/test/tagged_template_test.js | 2 +- jscomp/test/tagged_template_test.res | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jscomp/test/tagged_template_lib.js b/jscomp/test/tagged_template_lib.js index 4708f45e8d..6a087a4762 100644 --- a/jscomp/test/tagged_template_lib.js +++ b/jscomp/test/tagged_template_lib.js @@ -1,7 +1,7 @@ exports.sql = (strings, ...values) => { let result = ""; for (let i = 0; i < values.length; i++) { - result += strings[i] + values[i]; + result += strings[i] + "'" + values[i] + "'"; } result += strings[values.length]; return result; diff --git a/jscomp/test/tagged_template_test.js b/jscomp/test/tagged_template_test.js index 2fdcbb28b9..923819a1e8 100644 --- a/jscomp/test/tagged_template_test.js +++ b/jscomp/test/tagged_template_test.js @@ -28,7 +28,7 @@ Mt.from_pair_suites("tagged templates", { return { TAG: "Eq", _0: query, - _1: "SELECT * FROM users WHERE id = 5" + _1: "SELECT * FROM 'users' WHERE id = '5'" }; }) ], diff --git a/jscomp/test/tagged_template_test.res b/jscomp/test/tagged_template_test.res index 5302ec777a..fb7941cba8 100644 --- a/jscomp/test/tagged_template_test.res +++ b/jscomp/test/tagged_template_test.res @@ -22,7 +22,7 @@ Mt.from_pair_suites( list{ ( "with externals, it should return a string with the correct interpolations", - () => Eq(query, "SELECT * FROM users WHERE id = 5"), + () => Eq(query, "SELECT * FROM 'users' WHERE id = '5'"), ), ( "with rescript function, it should return a string with the correct interpolations", From b8caf783995e7fe871c4943226c2bdda4f47bf65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Mon, 15 Jan 2024 15:58:03 +0100 Subject: [PATCH 09/22] put [@local] back --- jscomp/core/lam_pass_remove_alias.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jscomp/core/lam_pass_remove_alias.ml b/jscomp/core/lam_pass_remove_alias.ml index afd294fd73..979137184c 100644 --- a/jscomp/core/lam_pass_remove_alias.ml +++ b/jscomp/core/lam_pass_remove_alias.ml @@ -67,7 +67,7 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = | Lprim { primitive = Pfull_apply; args = Lvar v :: ap_args as args; loc } -> ( (* Inline uncurried application when safe *) - let normal () = + let[@local] normal () = Lam.prim ~primitive:Pfull_apply ~args:(Ext_list.map args simpl) loc in let ap_args = Ext_list.map ap_args simpl in From 39e68aab2cadd5d1ae1965516f21dd3e93e302b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 16 Jan 2024 10:51:54 +0100 Subject: [PATCH 10/22] fix wrong inlining --- jscomp/core/js_dump.ml | 15 +++++---------- jscomp/test/tagged_template_test.js | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/jscomp/core/js_dump.ml b/jscomp/core/js_dump.ml index 269fb8ab59..597e70eeaa 100644 --- a/jscomp/core/js_dump.ml +++ b/jscomp/core/js_dump.ml @@ -603,19 +603,14 @@ and expression_desc cxt ~(level : int) f x : cxt = P.string f "`"; let rec aux cxt xs ys = match xs, ys with | [], [] -> () - | x_head :: x_rest, ys -> - let cxt = (match x_head with - | {J.expression_desc = Str { txt; _ }} -> + | [{J.expression_desc = Str { txt; _ }}], [] -> + P.string f txt + | {J.expression_desc = Str { txt; _ }} :: x_rest, y :: y_rest -> P.string f txt; - cxt - | _ -> P.string f "${"; - let cxt = expression cxt ~level f x_head in + let cxt = expression cxt ~level f y in P.string f "}"; - cxt - ) - in - aux cxt ys x_rest + aux cxt x_rest y_rest | _ -> assert false in aux cxt stringArgs valueArgs; diff --git a/jscomp/test/tagged_template_test.js b/jscomp/test/tagged_template_test.js index 923819a1e8..5bfde0e376 100644 --- a/jscomp/test/tagged_template_test.js +++ b/jscomp/test/tagged_template_test.js @@ -5,7 +5,7 @@ var Mt = require("./mt.js"); var Caml_array = require("../../lib/js/caml_array.js"); var Tagged_template_libJs = require("./tagged_template_lib.js"); -var query = Tagged_template_libJs.sql`SELECT * FROM users WHERE id = 5`; +var query = Tagged_template_libJs.sql`SELECT * FROM ${"users"} WHERE id = ${"5"}`; function foo(strings, values) { var res = ""; From 7327f9cc47dccbedf56bc3b9be85c49d3832ef5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 16 Jan 2024 11:04:37 +0100 Subject: [PATCH 11/22] add test for external tagged template not returning a string --- jscomp/test/tagged_template_lib.js | 6 +++++- jscomp/test/tagged_template_test.js | 28 +++++++++++++++++++++------- jscomp/test/tagged_template_test.res | 10 ++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/jscomp/test/tagged_template_lib.js b/jscomp/test/tagged_template_lib.js index 6a087a4762..5b4a6ed8af 100644 --- a/jscomp/test/tagged_template_lib.js +++ b/jscomp/test/tagged_template_lib.js @@ -5,4 +5,8 @@ exports.sql = (strings, ...values) => { } result += strings[values.length]; return result; -}; \ No newline at end of file +}; + +exports.length = (strings, ...values) => + strings.reduce((acc, curr) => acc + curr.length, 0) + + values.reduce((acc, curr) => acc + curr, 0); diff --git a/jscomp/test/tagged_template_test.js b/jscomp/test/tagged_template_test.js index 5bfde0e376..c0a4687743 100644 --- a/jscomp/test/tagged_template_test.js +++ b/jscomp/test/tagged_template_test.js @@ -7,6 +7,8 @@ var Tagged_template_libJs = require("./tagged_template_lib.js"); var query = Tagged_template_libJs.sql`SELECT * FROM ${"users"} WHERE id = ${"5"}`; +var length = Tagged_template_libJs.length`hello ${10} what's the total length? Is it ${3}?`; + function foo(strings, values) { var res = ""; var valueCount = values.length; @@ -34,27 +36,39 @@ Mt.from_pair_suites("tagged templates", { ], tl: { hd: [ - "with rescript function, it should return a string with the correct interpolations", + "with externals, it should return the result of the function", (function (param) { return { TAG: "Eq", - _0: res, - _1: "| 5 * 10 = 50 |" + _0: length, + _1: 52 }; }) ], tl: { hd: [ - "a template literal tagged with json should generate a regular string interpolation for now", + "with rescript function, it should return a string with the correct interpolations", (function (param) { return { TAG: "Eq", - _0: "some random " + "string", - _1: "some random string" + _0: res, + _1: "| 5 * 10 = 50 |" }; }) ], - tl: /* [] */0 + tl: { + hd: [ + "a template literal tagged with json should generate a regular string interpolation for now", + (function (param) { + return { + TAG: "Eq", + _0: "some random " + "string", + _1: "some random string" + }; + }) + ], + tl: /* [] */0 + } } } }); diff --git a/jscomp/test/tagged_template_test.res b/jscomp/test/tagged_template_test.res index fb7941cba8..28df98a593 100644 --- a/jscomp/test/tagged_template_test.res +++ b/jscomp/test/tagged_template_test.res @@ -6,6 +6,12 @@ let id = "5" let query = sql`SELECT * FROM ${table} WHERE id = ${id}` +@module("./tagged_template_lib.js") @variadic +external length: (array, array) => int = "length" + +let extraLength = 10 +let length = length`hello ${extraLength} what's the total length? Is it ${3}?` + let foo = (strings, values) => { let res = ref("") let valueCount = Array.length(values) @@ -23,6 +29,10 @@ Mt.from_pair_suites( ( "with externals, it should return a string with the correct interpolations", () => Eq(query, "SELECT * FROM 'users' WHERE id = '5'"), + ), + ( + "with externals, it should return the result of the function", + () => Eq(length, 52), ), ( "with rescript function, it should return a string with the correct interpolations", From 3bdefa00a40c41d5acedfb0880887b1567c0803e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 16 Jan 2024 11:17:25 +0100 Subject: [PATCH 12/22] merge ocamlString with string --- .../printer/other/expected/string.res.txt | 2 ++ .../tests/printer/other/ocamlString.res | 25 ------------------- jscomp/syntax/tests/printer/other/string.res | 2 ++ 3 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 jscomp/syntax/tests/printer/other/ocamlString.res diff --git a/jscomp/syntax/tests/printer/other/expected/string.res.txt b/jscomp/syntax/tests/printer/other/expected/string.res.txt index e05128e865..a0b671b08a 100644 --- a/jscomp/syntax/tests/printer/other/expected/string.res.txt +++ b/jscomp/syntax/tests/printer/other/expected/string.res.txt @@ -15,3 +15,5 @@ let s = "unknown escape \m111 as passed through" let heart = "\u2665" let smile = "emoji: \u{1F600}" + +let taggedTemplate = sql`select * from ${table} where id = ${id}` diff --git a/jscomp/syntax/tests/printer/other/ocamlString.res b/jscomp/syntax/tests/printer/other/ocamlString.res deleted file mode 100644 index 085aed7777..0000000000 --- a/jscomp/syntax/tests/printer/other/ocamlString.res +++ /dev/null @@ -1,25 +0,0 @@ -let x = "\132\149\166" - -let s = "\123 \o111 \xA0" - -let x = "foo\010bar" -let x = "foo\x0Abar" -let x = "foo\o012bar" - -let x = "😁 this works now 😆" -let x = `😁 this works now 😆` - - -// The `//` should not result into an extra comment -let x = `https://www.apple.com` -let x = js`https://www.apple.com` -let x = `https://www.apple.com` -let x = sql`https://www.apple.com` - -// /* */ should not result in an extra comments -let x = `/* https://www.apple.com*/` -let x = js`/*https://www.apple.com*/` -let x = `/*https://www.apple.com*/` -let x = sql`/*https://www.apple.com*/` - -let x = `\`https://${appleWebsite}\`` \ No newline at end of file diff --git a/jscomp/syntax/tests/printer/other/string.res b/jscomp/syntax/tests/printer/other/string.res index e05128e865..8b6e7b234c 100644 --- a/jscomp/syntax/tests/printer/other/string.res +++ b/jscomp/syntax/tests/printer/other/string.res @@ -15,3 +15,5 @@ let s = "unknown escape \m111 as passed through" let heart = "\u2665" let smile = "emoji: \u{1F600}" + +let taggedTemplate = sql`select * from ${table} where id = ${id}` \ No newline at end of file From 20b9599577d6733823edb7552e697c2a2db6d15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 16 Jan 2024 11:20:24 +0100 Subject: [PATCH 13/22] remove todo for exp_need_paren for tagged templates --- jscomp/core/js_dump.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jscomp/core/js_dump.ml b/jscomp/core/js_dump.ml index 597e70eeaa..09514211bc 100644 --- a/jscomp/core/js_dump.ml +++ b/jscomp/core/js_dump.ml @@ -147,8 +147,6 @@ let exp_need_paren (e : J.expression) = match e.expression_desc with (* | Caml_uninitialized_obj _ *) | Call ({ expression_desc = Fun _ | Raw_js_code _ }, _, _) -> true - (* TODO: implement this *) - | Tagged_template _ -> false | Raw_js_code { code_info = Exp _ } | Fun _ | Caml_block @@ -167,6 +165,7 @@ let exp_need_paren (e : J.expression) = | Js_not _ | Bool _ | New _ -> false | Await _ -> false + | Tagged_template _ -> false let comma_idents (cxt : cxt) f ls = iter_lst cxt f ls Ext_pp_scope.ident comma From 309c1706dee57e3e2876b72f9466d781715cbb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 16 Jan 2024 11:31:09 +0100 Subject: [PATCH 14/22] implement js_record_map expression_desc for tagged templates --- jscomp/core/js_record_map.ml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jscomp/core/js_record_map.ml b/jscomp/core/js_record_map.ml index 8680c4fcdd..c7d0cdfa62 100644 --- a/jscomp/core/js_record_map.ml +++ b/jscomp/core/js_record_map.ml @@ -130,9 +130,11 @@ let expression_desc : expression_desc fn = let _x0 = _self.expression _self _x0 in let _x1 = list _self.expression _self _x1 in Call (_x0, _x1, _x2) - | Tagged_template (callExpr, stringsArray, valuesArray) -> - (* TODO: implement this *) - Tagged_template (callExpr, stringsArray, valuesArray) + | Tagged_template (_x0, _x1, _x2) -> + let _x0 = _self.expression _self _x0 in + let _x1 = list _self.expression _self _x1 in + let _x2 = list _self.expression _self _x2 in + Tagged_template (_x0, _x1, _x2) | String_index (_x0, _x1) -> let _x0 = _self.expression _self _x0 in let _x1 = _self.expression _self _x1 in From ae7c8b66086f50d0c37570df7f2d49744dc6c3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Tue, 16 Jan 2024 16:52:01 +0100 Subject: [PATCH 15/22] get rid of duplicate filter_map --- jscomp/syntax/src/res_core.ml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index 157f9591a3..1d466efd50 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -17,16 +17,6 @@ end let mkLoc startLoc endLoc = Location.{loc_start = startLoc; loc_end = endLoc; loc_ghost = false} -let filter_map (f : 'a -> 'b option) xs = - let rec aux acc = function - | [] -> List.rev acc - | y :: ys -> ( - match f y with - | None -> aux acc ys - | Some z -> aux (z :: acc) ys) - in - aux [] xs - module Recover = struct let defaultExpr () = let id = Location.mknoloc "rescript.exprhole" in @@ -2305,7 +2295,7 @@ and parseTemplateExpr ?(prefix = "js") p = in let parts = parseParts p in let strings = List.map fst parts in - let values = filter_map snd parts in + let values = Ext_list.filter_map parts snd in let endPos = p.Parser.endPos in let genTaggedTemplateCall () = From dc2aef6e58d57e25be6012ea4f66a744097df2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 24 Jan 2024 15:27:09 +0100 Subject: [PATCH 16/22] implement expression_desc for Tagged_template --- jscomp/core/js_fold.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jscomp/core/js_fold.ml b/jscomp/core/js_fold.ml index 4708f1b10f..506b6d5a44 100644 --- a/jscomp/core/js_fold.ml +++ b/jscomp/core/js_fold.ml @@ -124,7 +124,10 @@ class fold = let _self = _self#expression _x0 in let _self = list (fun _self -> _self#expression) _self _x1 in _self - | Tagged_template (_, _, _) -> + | Tagged_template (_x0, _x1, _x2) -> + let _self = _self#expression _x0 in + let _self = list (fun _self -> _self#expression) _self _x1 in + let _self = list (fun _self -> _self#expression) _self _x2 in _self | String_index (_x0, _x1) -> let _self = _self#expression _x0 in From 83e36ee4f649d037400da7015311534ceaafdfdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 24 Jan 2024 15:27:21 +0100 Subject: [PATCH 17/22] remove useless comment --- jscomp/ml/translcore.ml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/jscomp/ml/translcore.ml b/jscomp/ml/translcore.ml index 342b460456..5b12480742 100644 --- a/jscomp/ml/translcore.ml +++ b/jscomp/ml/translcore.ml @@ -762,20 +762,6 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = wrap (Lprim (prim, argl, e.exp_loc)) )) | Texp_apply (funct, oargs) -> - (* let () = print_string "#2 attrs = " in *) - (* let () = ( - List.iter ( - function ({txt = attrName}, _) -> print_string (attrName ^ "\n") - ) e.exp_attributes - ) in - let isTaggedTemplate = List.exists ( - function ({txt = attrName}, _) -> attrName = "res.taggedTemplate" - ) e.exp_attributes in - let () = if isTaggedTemplate then - (print_string "isTaggedTemplate\n") - else - (print_string "not isTaggedTemplate\n") - in *) let inlined, funct = Translattribute.get_and_remove_inlined_attribute funct in From f7a72dcda49d451aa5d45f5578253f0e69e0d7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 24 Jan 2024 15:27:58 +0100 Subject: [PATCH 18/22] remove useless comment --- jscomp/core/lam_pass_remove_alias.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jscomp/core/lam_pass_remove_alias.ml b/jscomp/core/lam_pass_remove_alias.ml index 979137184c..3a87258cbb 100644 --- a/jscomp/core/lam_pass_remove_alias.ml +++ b/jscomp/core/lam_pass_remove_alias.ml @@ -67,7 +67,7 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = | Lprim { primitive = Pfull_apply; args = Lvar v :: ap_args as args; loc } -> ( (* Inline uncurried application when safe *) - let[@local] normal () = + let normal () = Lam.prim ~primitive:Pfull_apply ~args:(Ext_list.map args simpl) loc in let ap_args = Ext_list.map ap_args simpl in @@ -198,7 +198,6 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = (* Ext_log.dwarn __LOC__ "%s/%d" v.name v.stamp; *) let ap_args = Ext_list.map ap_args simpl in - (* todo bring back local inlining *) let normal () = Lam.apply (simpl fn) ap_args ap_info in match Hash_ident.find_opt meta.ident_tbl v with | Some From 0f23f76b4ed503ff5d3f6b21239c6345bcbe7090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Wed, 24 Jan 2024 16:29:21 +0100 Subject: [PATCH 19/22] document special template literal prefixes --- jscomp/syntax/src/res_core.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index 1d466efd50..d4fb3c4288 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -2259,6 +2259,8 @@ and parseBinaryExpr ?(context = OrdinaryExpr) ?a p prec = and parseTemplateExpr ?(prefix = "js") p = let partPrefix = + (* we could stop treating js and j prefix as something special + for json, we would first need to remove @as(json`true`) feature *) match prefix with | "js" | "j" | "json" -> Some prefix | _ -> None From d086f5bb0dac5bcb8607573f08cdb592ad0172f4 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Fri, 12 Jan 2024 08:45:55 +0100 Subject: [PATCH 20/22] Set version to 11.1.0 --- CHANGELOG.md | 2 +- jscomp/common/bs_version.ml | 2 +- package-lock.json | 4 ++-- package.json | 2 +- packages/std/package.json | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34920d3ea2..b59d81a1d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ > - :house: [Internal] > - :nail_care: [Polish] -# 11.0.2 (Unreleased) +# 11.1.0 (Unreleased) # 11.0.1 diff --git a/jscomp/common/bs_version.ml b/jscomp/common/bs_version.ml index 05f0560905..a7dba66da6 100644 --- a/jscomp/common/bs_version.ml +++ b/jscomp/common/bs_version.ml @@ -21,6 +21,6 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -let version = "11.0.2" +let version = "11.1.0" let header = "// Generated by ReScript, PLEASE EDIT WITH CARE" let package_name = ref "rescript" diff --git a/package-lock.json b/package-lock.json index d3bdfba9a3..0dce2c204d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rescript", - "version": "11.0.2", + "version": "11.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "rescript", - "version": "11.0.2", + "version": "11.1.0", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", "bin": { diff --git a/package.json b/package.json index fcfd6a96fd..b7c5ca3c7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rescript", - "version": "11.0.2", + "version": "11.1.0", "devDependencies": { "mocha": "10.1.0", "nyc": "15.0.0", diff --git a/packages/std/package.json b/packages/std/package.json index a6e203c130..6d1d5a7ccd 100644 --- a/packages/std/package.json +++ b/packages/std/package.json @@ -1,6 +1,6 @@ { "name": "@rescript/std", - "version": "11.0.2", + "version": "11.1.0", "keywords": [ "rescript", "stdlib", From d7f48c7daa7115f657abb50cff8f8acc968090c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Thu, 25 Jan 2024 10:17:10 +0100 Subject: [PATCH 21/22] add tagged templates to changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b59d81a1d2..a8e2b13544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ # 11.1.0 (Unreleased) +#### :rocket: New Feature + +- experimental support of tagged template literals, eg ```sql`select * from ${table}```. https://github.com/rescript-lang/rescript-compiler/pull/6250 + # 11.0.1 #### :bug: Bug Fix From 949af10246f22a14cedecb5a53f468d0d8235d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Tsnobiladz=C3=A9?= Date: Thu, 25 Jan 2024 12:37:04 +0100 Subject: [PATCH 22/22] use @taggedTemplate annotation in ffi instead --- jscomp/core/lam.ml | 1 - jscomp/core/lam.mli | 1 - jscomp/core/lam_analysis.ml | 2 +- jscomp/core/lam_compile.ml | 1 - jscomp/core/lam_compile_external_call.ml | 28 +++++++++-------------- jscomp/core/lam_compile_external_call.mli | 6 ----- jscomp/core/lam_compile_primitive.ml | 1 - jscomp/core/lam_convert.ml | 6 ++--- jscomp/core/lam_eta_conversion.ml | 2 +- jscomp/core/lam_pass_remove_alias.ml | 16 ++----------- jscomp/core/lam_primitive.ml | 9 -------- jscomp/core/lam_primitive.mli | 4 ---- jscomp/core/lam_print.ml | 6 ++--- jscomp/frontend/ast_external_process.ml | 23 ++++++++++++++++--- jscomp/frontend/external_ffi_types.ml | 5 +++- jscomp/frontend/external_ffi_types.mli | 1 + jscomp/ml/lambda.ml | 6 ++--- jscomp/ml/lambda.mli | 1 - jscomp/ml/matching.ml | 8 +------ jscomp/ml/translattribute.ml | 13 ----------- jscomp/ml/translattribute.mli | 3 --- jscomp/ml/translcore.ml | 18 +++++---------- jscomp/ml/translmod.ml | 2 -- jscomp/test/tagged_template_test.res | 4 ++-- 24 files changed, 55 insertions(+), 112 deletions(-) diff --git a/jscomp/core/lam.ml b/jscomp/core/lam.ml index 5e59730151..7eb7881d44 100644 --- a/jscomp/core/lam.ml +++ b/jscomp/core/lam.ml @@ -28,7 +28,6 @@ type apply_status = App_na | App_infer_full | App_uncurry type ap_info = { ap_loc : Location.t; ap_inlined : Lambda.inline_attribute; - ap_tagged_template : bool; ap_status : apply_status; } diff --git a/jscomp/core/lam.mli b/jscomp/core/lam.mli index af9621ad4e..d57bdcb316 100644 --- a/jscomp/core/lam.mli +++ b/jscomp/core/lam.mli @@ -27,7 +27,6 @@ type apply_status = App_na | App_infer_full | App_uncurry type ap_info = { ap_loc : Location.t; ap_inlined : Lambda.inline_attribute; - ap_tagged_template : bool; ap_status : apply_status; } diff --git a/jscomp/core/lam_analysis.ml b/jscomp/core/lam_analysis.ml index ff1002fc95..eacfe0a872 100644 --- a/jscomp/core/lam_analysis.ml +++ b/jscomp/core/lam_analysis.ml @@ -98,7 +98,7 @@ let rec no_side_effects (lam : Lam.t) : bool = true | Pjs_apply | Pjs_runtime_apply | Pjs_call _ | Pinit_mod | Pupdate_mod | Pjs_unsafe_downgrade _ | Pdebugger | Pvoid_run | Pfull_apply - | Pjs_fn_method | Pjs_tagged_template _ + | Pjs_fn_method (* TODO *) | Praw_js_code _ | Pbytessetu | Pbytessets (* Operations on boxed integers (Nativeint.t, Int32.t, Int64.t) *) diff --git a/jscomp/core/lam_compile.ml b/jscomp/core/lam_compile.ml index 3579e5a090..7361a1e22d 100644 --- a/jscomp/core/lam_compile.ml +++ b/jscomp/core/lam_compile.ml @@ -1599,7 +1599,6 @@ and compile_prim (prim_info : Lam.prim_info) { ap_loc = loc; ap_inlined = Default_inline; - ap_tagged_template = false; ap_status = App_uncurry; }) (*FIXME: should pass info down: `f a [@bs][@inlined]`*) diff --git a/jscomp/core/lam_compile_external_call.ml b/jscomp/core/lam_compile_external_call.ml index fa2b53f017..6d288e0212 100644 --- a/jscomp/core/lam_compile_external_call.ml +++ b/jscomp/core/lam_compile_external_call.ml @@ -252,7 +252,17 @@ let translate_scoped_access scopes obj = let translate_ffi (cxt : Lam_compile_context.t) arg_types (ffi : External_ffi_types.external_spec) (args : J.expression list) = match ffi with - | Js_call { external_module_name = module_name; name = fn; splice; scopes } -> + | Js_call { external_module_name; name; splice; scopes; tagged_template = true } -> + let fn = translate_scoped_module_val external_module_name name scopes in + (match args with + | [ stringArgs; valueArgs ] -> ( + match (stringArgs, valueArgs) with + | ({expression_desc = Array (strings, _); _}, {expression_desc = Array (values, _); _}) -> + E.tagged_template fn strings values + | _ -> assert false + ) + | _ -> assert false) + | Js_call { external_module_name = module_name; name = fn; splice; scopes; tagged_template = false } -> let fn = translate_scoped_module_val module_name fn scopes in if splice then let args, eff, dynamic = assemble_args_has_splice arg_types args in @@ -381,19 +391,3 @@ let translate_ffi (cxt : Lam_compile_context.t) arg_types | [ obj; v; value ] -> Js_arr.set_array (translate_scoped_access scopes obj) v value | _ -> assert false) - -let translate_tagged_template (cxt : Lam_compile_context.t) - (ffi : External_ffi_types.external_spec) (args : J.expression list) = - let fn = match ffi with - | Js_call { external_module_name; name; scopes; _ } -> - translate_scoped_module_val external_module_name name scopes - | _ -> assert false - in - match args with - | [ stringArgs; valueArgs ] -> ( - match (stringArgs, valueArgs) with - | ({expression_desc = Array (strings, _); _}, {expression_desc = Array (values, _); _}) -> - E.tagged_template fn strings values - | _ -> assert false - ) - | _ -> assert false \ No newline at end of file diff --git a/jscomp/core/lam_compile_external_call.mli b/jscomp/core/lam_compile_external_call.mli index b9d5d74ee5..51d50fbcc9 100644 --- a/jscomp/core/lam_compile_external_call.mli +++ b/jscomp/core/lam_compile_external_call.mli @@ -36,12 +36,6 @@ val translate_ffi : J.expression list -> J.expression -val translate_tagged_template : - Lam_compile_context.t -> - External_ffi_types.external_spec -> - J.expression list -> - J.expression - (** TODO: document supported attributes Attributes starting with `js` are reserved examples: "variadic" diff --git a/jscomp/core/lam_compile_primitive.ml b/jscomp/core/lam_compile_primitive.ml index 9a487fa875..b25269aaec 100644 --- a/jscomp/core/lam_compile_primitive.ml +++ b/jscomp/core/lam_compile_primitive.ml @@ -339,7 +339,6 @@ let translate output_prefix loc (cxt : Lam_compile_context.t) | Pjs_object_create _ -> assert false | Pjs_call { arg_types; ffi } -> Lam_compile_external_call.translate_ffi cxt arg_types ffi args - | Pjs_tagged_template { ffi } -> Lam_compile_external_call.translate_tagged_template cxt ffi args (* FIXME, this can be removed later *) | Pisint -> E.is_type_number (Ext_list.singleton_exn args) | Pis_poly_var_block -> E.is_type_object (Ext_list.singleton_exn args) diff --git a/jscomp/core/lam_convert.ml b/jscomp/core/lam_convert.ml index 95c48bd3c0..922184e3a1 100644 --- a/jscomp/core/lam_convert.ml +++ b/jscomp/core/lam_convert.ml @@ -512,11 +512,11 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : match lam with | Lvar x -> Lam.var (Hash_ident.find_default alias_tbl x x) | Lconst x -> Lam.const (Lam_constant_convert.convert_constant x) - | Lapply { ap_func = fn; ap_args = args; ap_loc = loc; ap_inlined; ap_tagged_template } -> + | Lapply { ap_func = fn; ap_args = args; ap_loc = loc; ap_inlined } -> (* we need do this eargly in case [aux fn] add some wrapper *) Lam.apply (convert_aux fn) (Ext_list.map args convert_aux) - { ap_loc = loc; ap_inlined; ap_tagged_template; ap_status = App_na } + { ap_loc = loc; ap_inlined; ap_status = App_na } | Lfunction { params; body; attr } -> let new_map, body = rename_optional_parameters Map_ident.empty params body @@ -685,7 +685,6 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : { ap_loc = outer_loc; ap_inlined = ap_info.ap_inlined; - ap_tagged_template = ap_info.ap_tagged_template; ap_status = App_na; } | _ -> @@ -693,7 +692,6 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : { ap_loc = outer_loc; ap_inlined = Default_inline; - ap_tagged_template = false; ap_status = App_na; } and convert_switch (e : Lambda.lambda) (s : Lambda.lambda_switch) = diff --git a/jscomp/core/lam_eta_conversion.ml b/jscomp/core/lam_eta_conversion.ml index 71f7d894f8..a92639f1f2 100644 --- a/jscomp/core/lam_eta_conversion.ml +++ b/jscomp/core/lam_eta_conversion.ml @@ -111,7 +111,7 @@ let transform_under_supply n ap_info fn args = let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : Lam.t = let ap_info : Lam.ap_info = - { ap_loc = loc; ap_inlined = Default_inline; ap_tagged_template = false; ap_status = App_na } + { ap_loc = loc; ap_inlined = Default_inline; ap_status = App_na } in let is_async_fn = match fn with | Lfunction { attr = {async}} -> async diff --git a/jscomp/core/lam_pass_remove_alias.ml b/jscomp/core/lam_pass_remove_alias.ml index 3a87258cbb..4889d1c268 100644 --- a/jscomp/core/lam_pass_remove_alias.ml +++ b/jscomp/core/lam_pass_remove_alias.ml @@ -198,7 +198,7 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = (* Ext_log.dwarn __LOC__ "%s/%d" v.name v.stamp; *) let ap_args = Ext_list.map ap_args simpl in - let normal () = Lam.apply (simpl fn) ap_args ap_info in + let[@local] normal () = Lam.apply (simpl fn) ap_args ap_info in match Hash_ident.find_opt meta.ident_tbl v with | Some (FunctionId @@ -238,7 +238,7 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = Lam_closure.is_closed_with_map meta.export_idents params body in let is_export_id = Set_ident.mem meta.export_idents v in - let result = match (is_export_id, param_map) with + match (is_export_id, param_map) with | false, (_, param_map) | true, (true, param_map) -> ( match rec_flag with | Lam_rec -> @@ -256,18 +256,6 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = (Lam_beta_reduce.propagate_beta_reduce_with_map meta param_map params body ap_args)) | _ -> normal () - in - let result = (match result with - | Lprim {primitive; args; loc} -> (match primitive with - (* Converts Pjs_calls to Pjs_tagged_templates if ap_tagged_template is true *) - | Pjs_call {prim_name; ffi} when ap_info.ap_tagged_template -> - let prim = Lam_primitive.Pjs_tagged_template {prim_name; ffi} in - Lam.prim ~primitive:prim ~args loc - | _ -> result - ) - | _ -> result) - in - result else normal () else normal () | Some _ | None -> normal ()) diff --git a/jscomp/core/lam_primitive.ml b/jscomp/core/lam_primitive.ml index 362ef09d9d..26a9f998b2 100644 --- a/jscomp/core/lam_primitive.ml +++ b/jscomp/core/lam_primitive.ml @@ -49,10 +49,6 @@ type t = arg_types : External_arg_spec.params; ffi : External_ffi_types.external_spec; } - | Pjs_tagged_template of { - prim_name : string; - ffi : External_ffi_types.external_spec; - } | Pjs_object_create of External_arg_spec.obj_params (* Exceptions *) | Praise @@ -263,11 +259,6 @@ let eq_primitive_approx (lhs : t) (rhs : t) = match rhs with | Pjs_object_create obj_create1 -> obj_create = obj_create1 | _ -> false) - | Pjs_tagged_template { prim_name; ffi } -> ( - match rhs with - | Pjs_tagged_template rhs -> - prim_name = rhs.prim_name && ffi = rhs.ffi - | _ -> false) | Pintcomp comparison -> ( match rhs with | Pintcomp comparison1 -> Lam_compat.eq_comparison comparison comparison1 diff --git a/jscomp/core/lam_primitive.mli b/jscomp/core/lam_primitive.mli index b491468650..d78dd25e64 100644 --- a/jscomp/core/lam_primitive.mli +++ b/jscomp/core/lam_primitive.mli @@ -44,10 +44,6 @@ type t = arg_types : External_arg_spec.params; ffi : External_ffi_types.external_spec; } - | Pjs_tagged_template of { - prim_name : string; - ffi : External_ffi_types.external_spec; - } | Pjs_object_create of External_arg_spec.obj_params | Praise | Psequand diff --git a/jscomp/core/lam_print.ml b/jscomp/core/lam_print.ml index 0dbc51172b..f7390234c5 100644 --- a/jscomp/core/lam_print.ml +++ b/jscomp/core/lam_print.ml @@ -93,7 +93,6 @@ let primitive ppf (prim : Lam_primitive.t) = | Plazyforce -> fprintf ppf "force" | Pccall p -> fprintf ppf "%s" p.prim_name | Pjs_call { prim_name } -> fprintf ppf "%s[js]" prim_name - | Pjs_tagged_template { prim_name } -> fprintf ppf "%s[js.tagged_template]" prim_name | Pjs_object_create _ -> fprintf ppf "[js.obj]" | Praise -> fprintf ppf "raise" | Psequand -> fprintf ppf "&&" @@ -264,13 +263,12 @@ let lambda ppf v = | Lvar id -> Ident.print ppf id | Lglobal_module (id, dynamic_import) -> fprintf ppf (if dynamic_import then "dynamic global %a" else "global %a") Ident.print id | Lconst cst -> struct_const ppf cst - | Lapply { ap_func; ap_args; ap_info = { ap_inlined; ap_tagged_template } } -> + | Lapply { ap_func; ap_args; ap_info = { ap_inlined } } -> let lams ppf args = List.iter (fun l -> fprintf ppf "@ %a" lam l) args in - fprintf ppf "@[<2>(apply%s%s@ %a%a)@]" + fprintf ppf "@[<2>(apply%s@ %a%a)@]" (match ap_inlined with Always_inline -> "%inlned" | _ -> "") - (match ap_tagged_template with true -> "%tagged_template" | _ -> "") lam ap_func lams ap_args | Lfunction { params; body; _ } -> let pr_params ppf params = diff --git a/jscomp/frontend/ast_external_process.ml b/jscomp/frontend/ast_external_process.ml index b122b56cfc..a678d05098 100644 --- a/jscomp/frontend/ast_external_process.ml +++ b/jscomp/frontend/ast_external_process.ml @@ -184,6 +184,7 @@ type external_desc = { get_name: bundle_source option; mk_obj: bool; return_wrapper: External_ffi_types.return_wrapper; + tagged_template: bool; } let init_st = @@ -202,6 +203,7 @@ let init_st = get_name = None; mk_obj = false; return_wrapper = Return_unset; + tagged_template = false; } let return_wrapper loc (txt : string) : External_ffi_types.return_wrapper = @@ -291,6 +293,7 @@ let parse_external_attributes (no_arguments : bool) (prim_name_check : string) between unset/set *) | scopes -> {st with scopes}) + | "taggedTemplate" -> {st with splice = true; tagged_template = true} | "bs.splice" | "bs.variadic" | "variadic" -> {st with splice = true} | "bs.send" | "send" -> {st with val_send = Some (name_from_payload_or_prim ~loc payload)} @@ -366,6 +369,7 @@ let process_obj (loc : Location.t) (st : external_desc) (prim_name : string) get_name = None; get_index = false; return_wrapper = Return_unset; + tagged_template = _; set_index = false; mk_obj = _; scopes = @@ -564,6 +568,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) get_name = None; return_wrapper = _; mk_obj = _; + tagged_template = _; } -> if arg_type_specs_length = 3 then Js_set_index {js_set_index_scopes = scopes} @@ -588,6 +593,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) set_index = false; mk_obj = _; return_wrapper = _; + tagged_template = _; } -> if arg_type_specs_length = 2 then Js_get_index {js_get_index_scopes = scopes} @@ -614,6 +620,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) set_index = false; return_wrapper = _; mk_obj = _; + tagged_template = _; } -> ( match (arg_types_ty, new_name, val_name) with | [], None, _ -> Js_module_as_var external_module_name @@ -655,6 +662,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) mk_obj = _; (* mk_obj is always false *) return_wrapper = _; + tagged_template; } -> let name = prim_name_or_pval_prim.name in if arg_type_specs_length = 0 then @@ -665,7 +673,9 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) FIXME: splice is not supported here *) Js_var {name; external_module_name = None; scopes} - else Js_call {splice; name; external_module_name = None; scopes} + else + Js_call + {splice; name; external_module_name = None; scopes; tagged_template} | { call_name = Some {name; source = _}; splice; @@ -681,6 +691,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) get_name = None; mk_obj = _; return_wrapper = _; + tagged_template; } -> if arg_type_specs_length = 0 then (* @@ -690,7 +701,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) *) Js_var {name; external_module_name; scopes} (*FIXME: splice is not supported here *) - else Js_call {splice; name; external_module_name; scopes} + else Js_call {splice; name; external_module_name; scopes; tagged_template} | {call_name = Some _; _} -> Bs_syntaxerr.err loc (Conflict_ffi_attribute "Attribute found that conflicts with %@val") @@ -709,6 +720,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) return_wrapper = _; splice = false; scopes; + tagged_template = _; } -> (* if no_arguments --> @@ -735,6 +747,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) get_name = None; mk_obj = _; return_wrapper = _; + tagged_template; } -> let name = prim_name_or_pval_prim.name in if arg_type_specs_length = 0 then @@ -744,7 +757,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) ]} *) Js_var {name; external_module_name; scopes} - else Js_call {splice; name; external_module_name; scopes} + else Js_call {splice; name; external_module_name; scopes; tagged_template} | { val_send = Some {name; source = _}; splice; @@ -760,6 +773,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) external_module_name = None; mk_obj = _; return_wrapper = _; + tagged_template = _; } -> ( (* PR #2162 - since when we assemble arguments the first argument in [@@send] is ignored @@ -791,6 +805,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) scopes; mk_obj = _; return_wrapper = _; + tagged_template = _; } -> Js_new {name; external_module_name; splice; scopes} | {new_name = Some _; _} -> @@ -811,6 +826,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) mk_obj = _; return_wrapper = _; scopes; + tagged_template = _; } -> if arg_type_specs_length = 2 then Js_set {js_set_scopes = scopes; js_set_name = name} @@ -834,6 +850,7 @@ let external_desc_of_non_obj (loc : Location.t) (st : external_desc) mk_obj = _; return_wrapper = _; scopes; + tagged_template = _; } -> if arg_type_specs_length = 1 then Js_get {js_get_name = name; js_get_scopes = scopes} diff --git a/jscomp/frontend/external_ffi_types.ml b/jscomp/frontend/external_ffi_types.ml index 04ae5a170c..d9696cbec0 100644 --- a/jscomp/frontend/external_ffi_types.ml +++ b/jscomp/frontend/external_ffi_types.ml @@ -53,6 +53,7 @@ type external_spec = external_module_name: external_module_name option; splice: bool; scopes: string list; + tagged_template: bool; } | Js_send of {name: string; splice: bool; js_send_scopes: string list} (* we know it is a js send, but what will happen if you pass an ocaml objct *) @@ -188,7 +189,9 @@ let check_ffi ?loc ffi : bool = upgrade (is_package_relative_path external_module_name.bundle); check_external_module_name external_module_name | Js_new {external_module_name; name; splice = _; scopes = _} - | Js_call {external_module_name; name; splice = _; scopes = _} -> + | Js_call + {external_module_name; name; splice = _; scopes = _; tagged_template = _} + -> Ext_option.iter external_module_name (fun external_module_name -> upgrade (is_package_relative_path external_module_name.bundle)); Ext_option.iter external_module_name (fun name -> diff --git a/jscomp/frontend/external_ffi_types.mli b/jscomp/frontend/external_ffi_types.mli index a6e1202577..4c0d1c0b19 100644 --- a/jscomp/frontend/external_ffi_types.mli +++ b/jscomp/frontend/external_ffi_types.mli @@ -50,6 +50,7 @@ type external_spec = external_module_name: external_module_name option; splice: bool; scopes: string list; + tagged_template: bool; } | Js_send of {name: string; splice: bool; js_send_scopes: string list} (* we know it is a js send, but what will happen if you pass an ocaml objct *) diff --git a/jscomp/ml/lambda.ml b/jscomp/ml/lambda.ml index ceaa79a64a..337dd10e9e 100644 --- a/jscomp/ml/lambda.ml +++ b/jscomp/ml/lambda.ml @@ -354,7 +354,6 @@ and lambda_apply = ap_args : lambda list; ap_loc : Location.t; ap_inlined : inline_attribute; - ap_tagged_template : bool; } and lambda_switch = @@ -689,13 +688,12 @@ let rec map f lam = | Lvar _ -> lam | Lconst _ -> lam | Lapply { ap_func; ap_args; ap_loc; - ap_inlined; ap_tagged_template; } -> + ap_inlined; } -> Lapply { ap_func = map f ap_func; ap_args = List.map (map f) ap_args; ap_loc; - ap_inlined; - ap_tagged_template ; + ap_inlined; } | Lfunction { params; body; attr; loc; } -> Lfunction { params; body = map f body; attr; loc; } diff --git a/jscomp/ml/lambda.mli b/jscomp/ml/lambda.mli index b5103919fe..3a9b847c9c 100644 --- a/jscomp/ml/lambda.mli +++ b/jscomp/ml/lambda.mli @@ -325,7 +325,6 @@ and lambda_apply = ap_args : lambda list; ap_loc : Location.t; ap_inlined : inline_attribute; (* specified with the [@inlined] attribute *) - ap_tagged_template : bool; } and lambda_switch = diff --git a/jscomp/ml/matching.ml b/jscomp/ml/matching.ml index b7aa805365..30fa8efb72 100644 --- a/jscomp/ml/matching.ml +++ b/jscomp/ml/matching.ml @@ -1514,13 +1514,7 @@ let code_force = let inline_lazy_force arg loc = - Lapply { - ap_func = Lazy.force code_force; - ap_inlined = Default_inline; - ap_tagged_template = false; - ap_args = [arg]; - ap_loc = loc; - } + Lapply { ap_func = Lazy.force code_force; ap_inlined = Default_inline; ap_args = [arg]; ap_loc = loc} let make_lazy_matching def = function [] -> fatal_error "Matching.make_lazy_matching" | (arg,_mut) :: argl -> diff --git a/jscomp/ml/translattribute.ml b/jscomp/ml/translattribute.ml index 5a03caab94..4f7eca2b3d 100644 --- a/jscomp/ml/translattribute.ml +++ b/jscomp/ml/translattribute.ml @@ -21,9 +21,6 @@ let is_inline_attribute (attr : t) = let is_inlined_attribute (attr : t) = match attr with { txt = "inlined" }, _ -> true | _ -> false -let is_tagged_template_attribute (attr : t) = - match attr with { txt = "res.taggedTemplate" }, _ -> true | _ -> false - let find_attribute p (attributes : t list) = let inline_attribute, other_attributes = List.partition p attributes in let attr = @@ -96,16 +93,6 @@ let get_and_remove_inlined_attribute (e : Typedtree.expression) = let inlined = parse_inline_attribute attr in (inlined, { e with exp_attributes }) -let get_and_remove_tagged_template_attribute (e : Typedtree.expression) = - let attr, exp_attributes = - find_attribute is_tagged_template_attribute e.exp_attributes - in - let tagged_template = match attr with - | Some(_) -> true - | None -> false - in - (tagged_template, { e with exp_attributes }) - let get_and_remove_inlined_attribute_on_module (e : Typedtree.module_expr) = let attr, mod_attributes = find_attribute is_inlined_attribute e.mod_attributes diff --git a/jscomp/ml/translattribute.mli b/jscomp/ml/translattribute.mli index 749f58904c..03115eb0ee 100644 --- a/jscomp/ml/translattribute.mli +++ b/jscomp/ml/translattribute.mli @@ -26,8 +26,5 @@ val get_inline_attribute : Parsetree.attributes -> Lambda.inline_attribute val get_and_remove_inlined_attribute : Typedtree.expression -> Lambda.inline_attribute * Typedtree.expression -val get_and_remove_tagged_template_attribute : - Typedtree.expression -> bool * Typedtree.expression - val get_and_remove_inlined_attribute_on_module : Typedtree.module_expr -> Lambda.inline_attribute * Typedtree.module_expr diff --git a/jscomp/ml/translcore.ml b/jscomp/ml/translcore.ml index 5b12480742..7033cd5405 100644 --- a/jscomp/ml/translcore.ml +++ b/jscomp/ml/translcore.ml @@ -724,13 +724,10 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = let wrap f = if args' = [] then f else - let inlined, funct = + let inlined, _ = Translattribute.get_and_remove_inlined_attribute funct in - let is_tagged_template, _ = - Translattribute.get_and_remove_tagged_template_attribute funct - in - transl_apply ~inlined ~is_tagged_template f args' e.exp_loc + transl_apply ~inlined f args' e.exp_loc in let args = List.map (function _, Some x -> x | _ -> assert false) args @@ -772,10 +769,7 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = arity_opt else None in - let is_tagged_template, _ = - Translattribute.get_and_remove_tagged_template_attribute e - in - transl_apply ~inlined ~uncurried_partial_application ~is_tagged_template (transl_exp funct) oargs e.exp_loc + transl_apply ~inlined ~uncurried_partial_application (transl_exp funct) oargs e.exp_loc | Texp_match (arg, pat_expr_list, exn_pat_expr_list, partial) -> transl_match e arg pat_expr_list exn_pat_expr_list partial | Texp_try (body, pat_expr_list) -> @@ -991,14 +985,14 @@ and transl_cases_try cases = in List.map transl_case_try cases -and transl_apply ?(inlined = Default_inline) ?(is_tagged_template=false) ?(uncurried_partial_application=None) lam sargs loc = +and transl_apply ?(inlined = Default_inline) ?(uncurried_partial_application=None) lam sargs loc = let lapply funct args = match funct with (* Attention: This may not be what we need to change the application arity*) | Lapply ap -> Lapply { ap with ap_args = ap.ap_args @ args; ap_loc = loc } | lexp -> Lapply - { ap_loc = loc; ap_func = lexp; ap_args = args; ap_inlined = inlined; ap_tagged_template = is_tagged_template } + { ap_loc = loc; ap_func = lexp; ap_args = args; ap_inlined = inlined } in let rec build_apply lam args = function | (None, optional) :: l -> @@ -1057,7 +1051,7 @@ and transl_apply ?(inlined = Default_inline) ?(is_tagged_template=false) ?(uncur let extra_ids = Array.init extra_arity (fun _ -> Ident.create "extra") |> Array.to_list in let extra_args = Ext_list.map extra_ids (fun id -> Lvar id) in let ap_args = args @ extra_args in - let l0 = Lapply { ap_func = lam; ap_args; ap_inlined = inlined; ap_loc = loc; ap_tagged_template = is_tagged_template } in + let l0 = Lapply { ap_func = lam; ap_args; ap_inlined = inlined; ap_loc = loc } in Lfunction { params = List.rev_append !none_ids extra_ids ; diff --git a/jscomp/ml/translmod.ml b/jscomp/ml/translmod.ml index fa8fd6dd15..8815209779 100644 --- a/jscomp/ml/translmod.ml +++ b/jscomp/ml/translmod.ml @@ -109,7 +109,6 @@ and apply_coercion_result loc strict funct params args cc_res = ap_func = Lvar id; ap_args = List.rev args; ap_inlined = Default_inline; - ap_tagged_template = false; }); }) @@ -309,7 +308,6 @@ and transl_module cc rootpath mexp = ap_func = transl_module Tcoerce_none None funct; ap_args = [ transl_module ccarg None arg ]; ap_inlined = inlined_attribute; - ap_tagged_template = false; }) | Tmod_constraint (arg, _, _, ccarg) -> transl_module (compose_coercions cc ccarg) rootpath arg diff --git a/jscomp/test/tagged_template_test.res b/jscomp/test/tagged_template_test.res index 28df98a593..72bd021790 100644 --- a/jscomp/test/tagged_template_test.res +++ b/jscomp/test/tagged_template_test.res @@ -1,4 +1,4 @@ -@module("./tagged_template_lib.js") @variadic +@module("./tagged_template_lib.js") @taggedTemplate external sql: (array, array) => string = "sql" let table = "users" @@ -6,7 +6,7 @@ let id = "5" let query = sql`SELECT * FROM ${table} WHERE id = ${id}` -@module("./tagged_template_lib.js") @variadic +@module("./tagged_template_lib.js") @taggedTemplate external length: (array, array) => int = "length" let extraLength = 10