From 8d080564bb0aa2f87d945c1ad72af23370d3ebf6 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Sun, 17 Mar 2024 22:27:15 +0100 Subject: [PATCH 1/6] Compiler: fix var renaming on obj bindings --- compiler/lib/js_traverse.ml | 28 ++++++++++++- compiler/lib/js_traverse.mli | 2 + compiler/tests-compiler/minify.ml | 66 +++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/compiler/lib/js_traverse.ml b/compiler/lib/js_traverse.ml index 9df2ce75e2..d98b4b9a7d 100644 --- a/compiler/lib/js_traverse.ml +++ b/compiler/lib/js_traverse.ml @@ -52,6 +52,8 @@ class type mapper = object -> Javascript.for_binding -> Javascript.for_binding + method binding_property : Javascript.binding_property -> Javascript.binding_property + method variable_declaration : Javascript.variable_declaration_kind -> Javascript.variable_declaration @@ -376,7 +378,7 @@ class map : mapper = | None -> None | Some (b, e) -> Some (m#binding b, m#initialiser_o e) - method private binding_property x = + method binding_property x = match x with | Prop_binding (i, e) -> Prop_binding (m#property_name i, m#binding_element e) | Prop_ident (i, e) -> Prop_ident (m#ident i, m#initialiser_o e) @@ -1340,6 +1342,12 @@ class rename_variable ~esm = let m' = m#update_state Lexical_block [] p in m'#statements p + method binding_property x = + match x, super#binding_property x with + | Prop_ident (S { name = old_name; _ }, _), Prop_ident (V v, e) -> + Prop_binding (PNI old_name, (BindingIdent (V v), e)) + | _, x -> x + method expression e = match e with | EFun (ident, (k, params, body, nid)) -> @@ -1351,6 +1359,24 @@ class rename_variable ~esm = | EClass (Some id, cl_decl) -> let m' = m#update_state Lexical_block [ id ] [] in EClass (Some (m'#ident id), m'#class_decl cl_decl) + | EAssignTarget (ObjectTarget l_old) -> + let l_new = + match super#expression e with + | EAssignTarget (ObjectTarget l_new) -> l_new + | _ -> assert false + in + let l_res = + List.map2 l_old l_new ~f:(fun a b -> + match a, b with + | ( TargetPropertyId (S { name = old_name; _ }, _) + , TargetPropertyId (V v, rhs) ) -> ( + match rhs with + | None -> TargetProperty (PNI old_name, EVar (V v)) + | Some (e, _) -> + TargetProperty (PNI old_name, EBin (Eq, EVar (V v), e))) + | _, b -> b) + in + EAssignTarget (ObjectTarget l_res) | _ -> super#expression e method statement s = diff --git a/compiler/lib/js_traverse.mli b/compiler/lib/js_traverse.mli index 275a3ac6ab..3209b6faa4 100644 --- a/compiler/lib/js_traverse.mli +++ b/compiler/lib/js_traverse.mli @@ -47,6 +47,8 @@ class type mapper = object -> Javascript.for_binding -> Javascript.for_binding + method binding_property : Javascript.binding_property -> Javascript.binding_property + method variable_declaration : Javascript.variable_declaration_kind -> Javascript.variable_declaration diff --git a/compiler/tests-compiler/minify.ml b/compiler/tests-compiler/minify.ml index 321acb375a..e23139e01c 100644 --- a/compiler/tests-compiler/minify.ml +++ b/compiler/tests-compiler/minify.ml @@ -417,3 +417,69 @@ test() 4: a(a,b=c.b){return a+b}console.log(a(1))}test(); |}]; print_endline (run_javascript js_min_file); [%expect {| 3 |}]) + +let%expect_test _ = + with_temp_dir ~f:(fun () -> + let js_prog = + {| +function f (x) { + let {toto} = x; + return toto; +} + +function g(x) { + var toto, test, tata; + for( { toto : tata = test } in x ) { + console.log(tata); + } +} + +function h(x) { + var toto; + for( { toto } in x ) { + console.log(toto); + } +} +|} + in + let js_file = + js_prog |> Filetype.js_text_of_string |> Filetype.write_js ~name:"test.js" + in + let js_min_file = + js_file |> jsoo_minify ~flags:[ "--enable"; "shortvar" ] ~pretty:false + in + print_file (Filetype.path_of_js_file js_file); + print_file (Filetype.path_of_js_file js_min_file); + [%expect + {| + $ cat "test.js" + 1: + 2: function f (x) { + 3: let {toto} = x; + 4: return toto; + 5: } + 6: + 7: function g(x) { + 8: var toto, test, tata; + 9: for( { toto : tata = test } in x ) { + 10: console.log(tata); + 11: } + 12: } + 13: + 14: function h(x) { + 15: var toto; + 16: for( { toto } in x ) { + 17: console.log(toto); + 18: } + 19: } + $ cat "test.min.js" + 1: function + 2: f(a){let{toto:b}=a;return b}function + 3: g(a){var + 4: d,c,b;for({toto:b=c}in + 5: a)console.log(b)}function + 6: h(a){var + 7: b;for({toto:b}in + 8: a)console.log(b)} |}]; + print_endline (run_javascript js_min_file); + [%expect {||}]) From 7db996c18fa3f70a32b43516581b8424f929d61a Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Sun, 17 Mar 2024 22:44:30 +0100 Subject: [PATCH 2/6] WIP --- compiler/lib/javascript.ml | 10 ++++++++-- compiler/lib/javascript.mli | 2 +- compiler/lib/js_output.ml | 13 ++++++++++++- compiler/lib/js_traverse.ml | 19 +++++++++---------- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/compiler/lib/javascript.ml b/compiler/lib/javascript.ml index 2ae7074880..a340b98944 100644 --- a/compiler/lib/javascript.ml +++ b/compiler/lib/javascript.ml @@ -425,7 +425,7 @@ and binding_pattern = and object_target_elt = | TargetPropertyId of ident * initialiser option - | TargetProperty of property_name * expression + | TargetProperty of property_name * expression * initialiser option | TargetPropertySpread of expression | TargetPropertyMethod of property_name * method_ @@ -589,7 +589,13 @@ let rec assignment_target_of_expr' x = List.map l ~f:(function | Property (PNI n, EVar (S { name = n'; _ } as id)) when Utf8_string.equal n n' -> TargetPropertyId (id, None) - | Property (n, e) -> TargetProperty (n, assignment_target_of_expr' e) + | Property (n, e) -> + let e, i = + match e with + | EBin (Eq, e, i) -> e, Some (i, N) + | _ -> e, None + in + TargetProperty (n, assignment_target_of_expr' e, i) | CoverInitializedName (_, i, (e, loc)) -> TargetPropertyId (i, Some (assignment_target_of_expr' e, loc)) | PropertySpread e -> TargetPropertySpread (assignment_target_of_expr' e) diff --git a/compiler/lib/javascript.mli b/compiler/lib/javascript.mli index 4c79039ce5..d371661afa 100644 --- a/compiler/lib/javascript.mli +++ b/compiler/lib/javascript.mli @@ -343,7 +343,7 @@ and binding_pattern = and object_target_elt = | TargetPropertyId of ident * initialiser option - | TargetProperty of property_name * expression + | TargetProperty of property_name * expression * initialiser option | TargetPropertySpread of expression | TargetPropertyMethod of property_name * method_ diff --git a/compiler/lib/js_output.ml b/compiler/lib/js_output.ml index f3532f017d..2024e0fb20 100644 --- a/compiler/lib/js_output.ml +++ b/compiler/lib/js_output.ml @@ -747,13 +747,24 @@ struct PP.string f "="; PP.space f; expression AssignementExpression f e - | TargetProperty (pn, e) -> + | TargetProperty (pn, e, None) -> PP.start_group f 0; property_name f pn; PP.string f ":"; PP.space f; expression AssignementExpression f e; PP.end_group f + | TargetProperty (pn, e, Some (ini, _)) -> + PP.start_group f 0; + property_name f pn; + PP.string f ":"; + PP.space f; + expression AssignementExpression f e; + PP.space f; + PP.string f "="; + PP.space f; + expression AssignementExpression f ini; + PP.end_group f | TargetPropertySpread e -> PP.string f "..."; expression AssignementExpression f e diff --git a/compiler/lib/js_traverse.ml b/compiler/lib/js_traverse.ml index d98b4b9a7d..5b33b372a2 100644 --- a/compiler/lib/js_traverse.ml +++ b/compiler/lib/js_traverse.ml @@ -299,8 +299,9 @@ class map : mapper = (List.map l ~f:(function | TargetPropertyId (i, e) -> TargetPropertyId (m#ident i, m#initialiser_o e) - | TargetProperty (i, e) -> - TargetProperty (m#property_name i, m#expression e) + | TargetProperty (n, e, i) -> + TargetProperty + (m#property_name n, m#expression e, m#initialiser_o i) | TargetPropertyMethod (n, x) -> TargetPropertyMethod (m#property_name n, m#method_ x) | TargetPropertySpread e -> TargetPropertySpread (m#expression e)))) @@ -646,9 +647,10 @@ class iter : iterator = | TargetPropertyId (i, e) -> m#ident i; m#initialiser_o e - | TargetProperty (i, e) -> - m#property_name i; - m#expression e + | TargetProperty (n, e, i) -> + m#property_name n; + m#expression e; + m#initialiser_o i | TargetPropertyMethod (n, x) -> m#property_name n; m#method_ x @@ -1369,11 +1371,8 @@ class rename_variable ~esm = List.map2 l_old l_new ~f:(fun a b -> match a, b with | ( TargetPropertyId (S { name = old_name; _ }, _) - , TargetPropertyId (V v, rhs) ) -> ( - match rhs with - | None -> TargetProperty (PNI old_name, EVar (V v)) - | Some (e, _) -> - TargetProperty (PNI old_name, EBin (Eq, EVar (V v), e))) + , TargetPropertyId (V v, rhs) ) -> + TargetProperty (PNI old_name, EVar (V v), rhs) | _, b -> b) in EAssignTarget (ObjectTarget l_res) From 232792efe28a910dfecd1f617577cffb3ae7d7fe Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Tue, 19 Mar 2024 09:31:50 +0100 Subject: [PATCH 3/6] WIP --- compiler/lib/javascript.ml | 19 ++++++++-------- compiler/lib/javascript.mli | 12 +++++----- compiler/lib/js_output.ml | 8 +++---- compiler/lib/js_parser.mly | 2 +- compiler/lib/js_traverse.ml | 44 ++++++++++++++++++------------------- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/compiler/lib/javascript.ml b/compiler/lib/javascript.ml index a340b98944..e77d176190 100644 --- a/compiler/lib/javascript.ml +++ b/compiler/lib/javascript.ml @@ -367,7 +367,7 @@ and block = statement_list and statement_list = (statement * location) list and variable_declaration = - | DeclIdent of binding_ident * initialiser option + | DeclIdent of ident * initialiser option | DeclPattern of binding_pattern * initialiser and variable_declaration_kind = @@ -416,15 +416,15 @@ and for_binding = binding and binding_element = binding * initialiser option and binding = - | BindingIdent of binding_ident + | BindingIdent of ident | BindingPattern of binding_pattern and binding_pattern = - | ObjectBinding of (binding_property, binding_ident) list_with_rest + | ObjectBinding of (binding_property, ident) list_with_rest | ArrayBinding of (binding_element option, binding) list_with_rest and object_target_elt = - | TargetPropertyId of ident * initialiser option + | TargetPropertyId of ident_prop * initialiser option | TargetProperty of property_name * expression * initialiser option | TargetPropertySpread of expression | TargetPropertyMethod of property_name * method_ @@ -439,11 +439,11 @@ and assignment_target = | ObjectTarget of object_target_elt list | ArrayTarget of array_target_elt list -and binding_ident = ident +and ident_prop = Prop_and_ident of ident and binding_property = | Prop_binding of property_name * binding_element - | Prop_ident of binding_ident * initialiser option + | Prop_ident of ident_prop * initialiser option and function_body = statement_list @@ -530,7 +530,7 @@ and bound_idents_of_pattern p = match p with | ObjectBinding { list; rest } -> ( List.concat_map list ~f:(function - | Prop_ident (i, _) -> [ i ] + | Prop_ident (Prop_and_ident i, _) -> [ i ] | Prop_binding (_, e) -> bound_idents_of_element e) @ match rest with @@ -588,7 +588,7 @@ let rec assignment_target_of_expr' x = let list = List.map l ~f:(function | Property (PNI n, EVar (S { name = n'; _ } as id)) - when Utf8_string.equal n n' -> TargetPropertyId (id, None) + when Utf8_string.equal n n' -> TargetPropertyId (Prop_and_ident id, None) | Property (n, e) -> let e, i = match e with @@ -597,7 +597,8 @@ let rec assignment_target_of_expr' x = in TargetProperty (n, assignment_target_of_expr' e, i) | CoverInitializedName (_, i, (e, loc)) -> - TargetPropertyId (i, Some (assignment_target_of_expr' e, loc)) + TargetPropertyId + (Prop_and_ident i, Some (assignment_target_of_expr' e, loc)) | PropertySpread e -> TargetPropertySpread (assignment_target_of_expr' e) | PropertyMethod (n, m) -> TargetPropertyMethod (n, m)) in diff --git a/compiler/lib/javascript.mli b/compiler/lib/javascript.mli index d371661afa..2ad6e2e182 100644 --- a/compiler/lib/javascript.mli +++ b/compiler/lib/javascript.mli @@ -285,7 +285,7 @@ and block = statement_list and statement_list = (statement * location) list and variable_declaration = - | DeclIdent of binding_ident * initialiser option + | DeclIdent of ident * initialiser option | DeclPattern of binding_pattern * initialiser and variable_declaration_kind = @@ -334,15 +334,15 @@ and for_binding = binding and binding_element = binding * initialiser option and binding = - | BindingIdent of binding_ident + | BindingIdent of ident | BindingPattern of binding_pattern and binding_pattern = - | ObjectBinding of (binding_property, binding_ident) list_with_rest + | ObjectBinding of (binding_property, ident) list_with_rest | ArrayBinding of (binding_element option, binding) list_with_rest and object_target_elt = - | TargetPropertyId of ident * initialiser option + | TargetPropertyId of ident_prop * initialiser option | TargetProperty of property_name * expression * initialiser option | TargetPropertySpread of expression | TargetPropertyMethod of property_name * method_ @@ -357,11 +357,11 @@ and assignment_target = | ObjectTarget of object_target_elt list | ArrayTarget of array_target_elt list -and binding_ident = ident +and ident_prop = Prop_and_ident of ident and binding_property = | Prop_binding of property_name * binding_element - | Prop_ident of binding_ident * initialiser option + | Prop_ident of ident_prop * initialiser option and function_body = statement_list diff --git a/compiler/lib/js_output.ml b/compiler/lib/js_output.ml index 2024e0fb20..33d49bb7da 100644 --- a/compiler/lib/js_output.ml +++ b/compiler/lib/js_output.ml @@ -740,8 +740,8 @@ struct | EAssignTarget t -> ( let property f p = match p with - | TargetPropertyId (id, None) -> ident f id - | TargetPropertyId (id, Some (e, _)) -> + | TargetPropertyId (Prop_and_ident id, None) -> ident f id + | TargetPropertyId (Prop_and_ident id, Some (e, _)) -> ident f id; PP.space f; PP.string f "="; @@ -1123,8 +1123,8 @@ struct PP.string f ":"; PP.space f; binding_element f e - | Prop_ident (i, None) -> ident f i - | Prop_ident (i, Some (e, loc)) -> + | Prop_ident (Prop_and_ident i, None) -> ident f i + | Prop_ident (Prop_and_ident i, Some (e, loc)) -> ident f i; PP.space f; PP.string f "="; diff --git a/compiler/lib/js_parser.mly b/compiler/lib/js_parser.mly index a9cde51b66..b649a8acd1 100644 --- a/compiler/lib/js_parser.mly +++ b/compiler/lib/js_parser.mly @@ -503,7 +503,7 @@ object_binding_pattern: { ObjectBinding {list=l;rest= Some r} } binding_property: - | i=ident e=initializer_? { Prop_ident (i, e) } + | i=ident e=initializer_? { Prop_ident (Prop_and_ident i, e) } | pn=property_name ":" e=binding_element { Prop_binding (pn, e) } binding_property_rest: diff --git a/compiler/lib/js_traverse.ml b/compiler/lib/js_traverse.ml index 5b33b372a2..eb62308b7e 100644 --- a/compiler/lib/js_traverse.ml +++ b/compiler/lib/js_traverse.ml @@ -297,8 +297,8 @@ class map : mapper = EAssignTarget (ObjectTarget (List.map l ~f:(function - | TargetPropertyId (i, e) -> - TargetPropertyId (m#ident i, m#initialiser_o e) + | TargetPropertyId (Prop_and_ident i, e) -> + TargetPropertyId (Prop_and_ident (m#ident i), m#initialiser_o e) | TargetProperty (n, e, i) -> TargetProperty (m#property_name n, m#expression e, m#initialiser_o i) @@ -382,7 +382,8 @@ class map : mapper = method binding_property x = match x with | Prop_binding (i, e) -> Prop_binding (m#property_name i, m#binding_element e) - | Prop_ident (i, e) -> Prop_ident (m#ident i, m#initialiser_o e) + | Prop_ident (Prop_and_ident i, e) -> + Prop_ident (Prop_and_ident (m#ident i), m#initialiser_o e) method expression_o x = match x with @@ -644,7 +645,7 @@ class iter : iterator = | TargetElementSpread e -> m#expression e) | ObjectTarget l -> List.iter l ~f:(function - | TargetPropertyId (i, e) -> + | TargetPropertyId (Prop_and_ident i, e) -> m#ident i; m#initialiser_o e | TargetProperty (n, e, i) -> @@ -740,7 +741,7 @@ class iter : iterator = method private binding_property x = match x with | Prop_binding ((_ : property_name), e) -> m#binding_element e - | Prop_ident (i, e) -> + | Prop_ident (Prop_and_ident i, e) -> m#ident i; m#initialiser_o e @@ -1345,10 +1346,12 @@ class rename_variable ~esm = m'#statements p method binding_property x = - match x, super#binding_property x with - | Prop_ident (S { name = old_name; _ }, _), Prop_ident (V v, e) -> - Prop_binding (PNI old_name, (BindingIdent (V v), e)) - | _, x -> x + match x with + | Prop_ident (Prop_and_ident (S { name = Utf8 name' as name; _ } as ident), e) + when StringMap.mem name' subst -> + let x = Prop_binding (PNI name, (BindingIdent ident, e)) in + super#binding_property x + | x -> x method expression e = match e with @@ -1361,21 +1364,16 @@ class rename_variable ~esm = | EClass (Some id, cl_decl) -> let m' = m#update_state Lexical_block [ id ] [] in EClass (Some (m'#ident id), m'#class_decl cl_decl) - | EAssignTarget (ObjectTarget l_old) -> - let l_new = - match super#expression e with - | EAssignTarget (ObjectTarget l_new) -> l_new - | _ -> assert false - in - let l_res = - List.map2 l_old l_new ~f:(fun a b -> - match a, b with - | ( TargetPropertyId (S { name = old_name; _ }, _) - , TargetPropertyId (V v, rhs) ) -> - TargetProperty (PNI old_name, EVar (V v), rhs) - | _, b -> b) + | EAssignTarget (ObjectTarget l) -> + let l = + List.map l ~f:(function + | TargetPropertyId + (Prop_and_ident (S { name = Utf8 name' as name; _ } as ident), rhs) + when StringMap.mem name' subst -> + TargetProperty (PNI name, EVar ident, rhs) + | b -> b) in - EAssignTarget (ObjectTarget l_res) + super#expression (EAssignTarget (ObjectTarget l)) | _ -> super#expression e method statement s = From d5f60d795b1e278b42a5bd10485e46e5f072723c Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Tue, 19 Mar 2024 09:55:17 +0100 Subject: [PATCH 4/6] WIP --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 70b4c4956f..d1ddd58d95 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,8 @@ ## Bug fixes +* Compiler: fix variable renaming for property binding and assignment target + # 5.7.1 (2024-03-05) - Lille ## Features/Changes From 8175682dbdb2545c4f4c247c7fe74039e27fe976 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Tue, 19 Mar 2024 09:59:45 +0100 Subject: [PATCH 5/6] WIP --- compiler/tests-compiler/minify.ml | 76 +++++++++++++------------------ 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/compiler/tests-compiler/minify.ml b/compiler/tests-compiler/minify.ml index e23139e01c..822b3dfe84 100644 --- a/compiler/tests-compiler/minify.ml +++ b/compiler/tests-compiler/minify.ml @@ -420,66 +420,52 @@ test() let%expect_test _ = with_temp_dir ~f:(fun () -> - let js_prog = - {| + let minify js_prog = + let js_file = + js_prog |> Filetype.js_text_of_string |> Filetype.write_js ~name:"test.js" + in + let js_min_file = + js_file |> jsoo_minify ~flags:[ "--enable"; "shortvar" ] ~pretty:false + in + print_file (Filetype.path_of_js_file js_min_file) + in + minify {| function f (x) { let {toto} = x; return toto; } - +|}; + [%expect {| + $ cat "test.min.js" + 1: function + 2: f(a){let{toto:b}=a;return b} |}]; + minify + {| function g(x) { var toto, test, tata; for( { toto : tata = test } in x ) { console.log(tata); } } - +|}; + [%expect {| + $ cat "test.min.js" + 1: function + 2: g(a){var + 3: d,c,b;for({toto:b=c}in + 4: a)console.log(b)} |}]; + minify + {| function h(x) { var toto; for( { toto } in x ) { console.log(toto); } } -|} - in - let js_file = - js_prog |> Filetype.js_text_of_string |> Filetype.write_js ~name:"test.js" - in - let js_min_file = - js_file |> jsoo_minify ~flags:[ "--enable"; "shortvar" ] ~pretty:false - in - print_file (Filetype.path_of_js_file js_file); - print_file (Filetype.path_of_js_file js_min_file); - [%expect - {| - $ cat "test.js" - 1: - 2: function f (x) { - 3: let {toto} = x; - 4: return toto; - 5: } - 6: - 7: function g(x) { - 8: var toto, test, tata; - 9: for( { toto : tata = test } in x ) { - 10: console.log(tata); - 11: } - 12: } - 13: - 14: function h(x) { - 15: var toto; - 16: for( { toto } in x ) { - 17: console.log(toto); - 18: } - 19: } +|}; + [%expect {| $ cat "test.min.js" 1: function - 2: f(a){let{toto:b}=a;return b}function - 3: g(a){var - 4: d,c,b;for({toto:b=c}in - 5: a)console.log(b)}function - 6: h(a){var - 7: b;for({toto:b}in - 8: a)console.log(b)} |}]; - print_endline (run_javascript js_min_file); - [%expect {||}]) + 2: h(a){var + 3: b;for({toto:b}in + 4: a)console.log(b)} |}]) From 2e971eb109a5b3fe780eb46641b3ec86f50db807 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Tue, 19 Mar 2024 10:53:49 +0100 Subject: [PATCH 6/6] WIP --- compiler/tests-compiler/minify.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/tests-compiler/minify.ml b/compiler/tests-compiler/minify.ml index 822b3dfe84..54424d3d29 100644 --- a/compiler/tests-compiler/minify.ml +++ b/compiler/tests-compiler/minify.ml @@ -435,7 +435,8 @@ function f (x) { return toto; } |}; - [%expect {| + [%expect + {| $ cat "test.min.js" 1: function 2: f(a){let{toto:b}=a;return b} |}]; @@ -448,7 +449,8 @@ function g(x) { } } |}; - [%expect {| + [%expect + {| $ cat "test.min.js" 1: function 2: g(a){var @@ -463,7 +465,8 @@ function h(x) { } } |}; - [%expect {| + [%expect + {| $ cat "test.min.js" 1: function 2: h(a){var