From e140ce935adfe31ea4998b334e450c250a3f7300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Wed, 4 Mar 2020 11:54:44 +0000 Subject: [PATCH] bring back breaking changes --- lib/ast.js | 274 +++++++++++++++++++++++++++++++++++++----- lib/compress/index.js | 186 ++++++++++++++-------------- lib/mozilla-ast.js | 6 +- lib/output.js | 28 ++--- lib/parse.js | 6 +- lib/propmangle.js | 1 - lib/scope.js | 25 ++-- package.json | 6 + 8 files changed, 371 insertions(+), 161 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index c6c2f8de1..9450ccd09 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -122,7 +122,8 @@ var AST_Node = DEFNODE("Node", "start end", { }, walk: function(visitor) { return this._walk(visitor); // not sure the indirection will be any help - } + }, + _children_backwards: () => {} }, null); AST_Node.warn_function = null; @@ -158,6 +159,9 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { return visitor._visit(this, function() { this.body._walk(visitor); }); + }, + _children_backwards(push) { + push(this.body); } }, AST_Statement); @@ -191,6 +195,10 @@ var AST_Block = DEFNODE("Block", "body block_scope", { walk_body(this, visitor); }); }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + }, clone: clone_block_scope }, AST_Statement); @@ -220,6 +228,10 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { this.body._walk(visitor); }); }, + _children_backwards(push) { + push(this.body); + push(this.label); + }, clone: function(deep) { var node = this._clone(deep); if (deep) { @@ -259,6 +271,10 @@ var AST_Do = DEFNODE("Do", null, { this.body._walk(visitor); this.condition._walk(visitor); }); + }, + _children_backwards(push) { + push(this.condition); + push(this.body); } }, AST_DWLoop); @@ -269,7 +285,11 @@ var AST_While = DEFNODE("While", null, { this.condition._walk(visitor); this.body._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.body); + push(this.condition); + }, }, AST_DWLoop); var AST_For = DEFNODE("For", "init condition step", { @@ -286,7 +306,13 @@ var AST_For = DEFNODE("For", "init condition step", { if (this.step) this.step._walk(visitor); this.body._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.body); + if (this.step) push(this.step); + if (this.condition) push(this.condition); + if (this.init) push(this.init); + }, }, AST_IterationStatement); var AST_ForIn = DEFNODE("ForIn", "init object", { @@ -301,7 +327,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", { this.object._walk(visitor); this.body._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.body); + if (this.object) push(this.object); + if (this.init) push(this.init); + }, }, AST_IterationStatement); var AST_ForOf = DEFNODE("ForOf", "await", { @@ -318,7 +349,11 @@ var AST_With = DEFNODE("With", "expression", { this.expression._walk(visitor); this.body._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.body); + push(this.expression); + }, }, AST_StatementWithBody); /* -----[ scope and functions ]----- */ @@ -394,11 +429,13 @@ var AST_Expansion = DEFNODE("Expansion", "expression", { expression: "[AST_Node] the thing to be expanded" }, _walk: function(visitor) { - var self = this; return visitor._visit(this, function() { - self.expression.walk(visitor); + this.expression.walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.expression); + }, }); var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator async", { @@ -430,7 +467,16 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator as } walk_body(this, visitor); }); - } + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + + i = this.argnames.length; + while (i--) push(this.argnames[i]); + + if (this.name) push(this.name); + }, }, AST_Scope); var AST_Accessor = DEFNODE("Accessor", null, { @@ -463,6 +509,10 @@ var AST_Destructuring = DEFNODE("Destructuring", "names is_array", { }); }); }, + _children_backwards(push) { + let i = this.names.length; + while (i--) push(this.names[i]); + }, all_symbols: function() { var out = []; this.walk(new TreeWalker(function (node) { @@ -481,9 +531,15 @@ var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_str prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`." }, _walk: function(visitor) { - this.prefix._walk(visitor); - this.template_string._walk(visitor); - } + return visitor._visit(this, function () { + this.prefix._walk(visitor); + this.template_string._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.template_string); + push(this.prefix); + }, }); var AST_TemplateString = DEFNODE("TemplateString", "segments", { @@ -497,6 +553,10 @@ var AST_TemplateString = DEFNODE("TemplateString", "segments", { seg._walk(visitor); }); }); + }, + _children_backwards(push) { + let i = this.segments.length; + while (i--) push(this.segments[i]); } }); @@ -523,7 +583,10 @@ var AST_Exit = DEFNODE("Exit", "value", { return visitor._visit(this, this.value && function() { this.value._walk(visitor); }); - } + }, + _children_backwards(push) { + if (this.value) push(this.value); + }, }, AST_Jump); var AST_Return = DEFNODE("Return", null, { @@ -543,7 +606,10 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", { return visitor._visit(this, this.label && function() { this.label._walk(visitor); }); - } + }, + _children_backwards(push) { + if (this.label) push(this.label); + }, }, AST_Jump); var AST_Break = DEFNODE("Break", null, { @@ -568,6 +634,13 @@ var AST_If = DEFNODE("If", "condition alternative", { this.body._walk(visitor); if (this.alternative) this.alternative._walk(visitor); }); + }, + _children_backwards(push) { + if (this.alternative) { + push(this.alternative); + } + push(this.body); + push(this.condition); } }, AST_StatementWithBody); @@ -583,6 +656,11 @@ var AST_Switch = DEFNODE("Switch", "expression", { this.expression._walk(visitor); walk_body(this, visitor); }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + push(this.expression); } }, AST_Block); @@ -604,7 +682,12 @@ var AST_Case = DEFNODE("Case", "expression", { this.expression._walk(visitor); walk_body(this, visitor); }); - } + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + push(this.expression); + }, }, AST_SwitchBranch); /* -----[ EXCEPTIONS ]----- */ @@ -621,7 +704,13 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", { if (this.bcatch) this.bcatch._walk(visitor); if (this.bfinally) this.bfinally._walk(visitor); }); - } + }, + _children_backwards(push) { + if (this.bfinally) push(this.bfinally); + if (this.bcatch) push(this.bcatch); + let i = this.body.length; + while (i--) push(this.body[i]); + }, }, AST_Block); var AST_Catch = DEFNODE("Catch", "argname", { @@ -634,7 +723,12 @@ var AST_Catch = DEFNODE("Catch", "argname", { if (this.argname) this.argname._walk(visitor); walk_body(this, visitor); }); - } + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + if (this.argname) push(this.argname); + }, }, AST_Block); var AST_Finally = DEFNODE("Finally", null, { @@ -655,7 +749,11 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", { definitions[i]._walk(visitor); } }); - } + }, + _children_backwards(push) { + let i = this.definitions.length; + while (i--) push(this.definitions[i]); + }, }, AST_Statement); var AST_Var = DEFNODE("Var", null, { @@ -681,7 +779,11 @@ var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", { this.foreign_name._walk(visitor); this.name._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.name); + push(this.foreign_name); + }, }); var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", { @@ -703,7 +805,15 @@ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", { } this.module_name._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.module_name); + if (this.imported_names) { + let i = this.imported_names.length; + while (i--) push(this.imported_names[i]); + } + if (this.imported_name) push(this.imported_name); + }, }); var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", { @@ -716,7 +826,7 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul is_default: "[Boolean] Whether this is the default exported value of this module" }, _walk: function (visitor) { - visitor._visit(this, function () { + return visitor._visit(this, function () { if (this.exported_definition) { this.exported_definition._walk(visitor); } @@ -732,6 +842,15 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul this.module_name._walk(visitor); } }); + }, + _children_backwards(push) { + if (this.module_name) push(this.module_name); + if (this.exported_names) { + let i = this.exported_names.length; + while (i--) push(this.exported_names[i]); + } + if (this.exported_value) push(this.exported_value); + if (this.exported_definition) push(this.exported_definition); } }, AST_Statement); @@ -746,7 +865,11 @@ var AST_VarDef = DEFNODE("VarDef", "name value", { this.name._walk(visitor); if (this.value) this.value._walk(visitor); }); - } + }, + _children_backwards(push) { + if (this.value) push(this.value); + push(this.name); + }, }); /* -----[ OTHER ]----- */ @@ -769,7 +892,12 @@ var AST_Call = DEFNODE("Call", "expression args _annotations", { } this.expression._walk(visitor); }); - } + }, + _children_backwards(push) { + let i = this.args.length; + while (i--) push(this.args[i]); + push(this.expression); + }, }); var AST_New = DEFNODE("New", null, { @@ -787,7 +915,11 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", { node._walk(visitor); }); }); - } + }, + _children_backwards(push) { + let i = this.expressions.length; + while (i--) push(this.expressions[i]); + }, }); var AST_PropAccess = DEFNODE("PropAccess", "expression property", { @@ -807,7 +939,10 @@ var AST_Dot = DEFNODE("Dot", "quote", { return visitor._visit(this, function() { this.expression._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.expression); + }, }, AST_PropAccess); var AST_Sub = DEFNODE("Sub", null, { @@ -817,7 +952,11 @@ var AST_Sub = DEFNODE("Sub", null, { this.expression._walk(visitor); this.property._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.property); + push(this.expression); + }, }, AST_PropAccess); var AST_Unary = DEFNODE("Unary", "operator expression", { @@ -830,7 +969,10 @@ var AST_Unary = DEFNODE("Unary", "operator expression", { return visitor._visit(this, function() { this.expression._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.expression); + }, }); var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { @@ -853,7 +995,11 @@ var AST_Binary = DEFNODE("Binary", "operator left right", { this.left._walk(visitor); this.right._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.right); + push(this.left); + }, }); var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { @@ -869,7 +1015,12 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", this.consequent._walk(visitor); this.alternative._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.alternative); + push(this.consequent); + push(this.condition); + }, }); var AST_Assign = DEFNODE("Assign", null, { @@ -894,7 +1045,11 @@ var AST_Array = DEFNODE("Array", "elements", { elements[i]._walk(visitor); } }); - } + }, + _children_backwards(push) { + let i = this.elements.length; + while (i--) push(this.elements[i]); + }, }); var AST_Object = DEFNODE("Object", "properties", { @@ -909,7 +1064,11 @@ var AST_Object = DEFNODE("Object", "properties", { properties[i]._walk(visitor); } }); - } + }, + _children_backwards(push) { + let i = this.properties.length; + while (i--) push(this.properties[i]); + }, }); var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { @@ -924,6 +1083,10 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { this.key._walk(visitor); this.value._walk(visitor); }); + }, + _children_backwards(push) { + push(this.value); + if (this.key instanceof AST_Node) push(this.key); } }); @@ -978,6 +1141,12 @@ var AST_Class = DEFNODE("Class", "name extends properties", { this.properties.forEach((prop) => prop._walk(visitor)); }); }, + _children_backwards(push) { + let i = this.properties.length; + while (i--) push(this.properties[i]); + if (this.extends) push(this.extends); + if (this.name) push(this.name); + }, }, AST_Scope /* TODO a class might have a scope but it's not a scope */); var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", { @@ -993,7 +1162,11 @@ var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", { if (this.value instanceof AST_Node) this.value._walk(visitor); }); - } + }, + _children_backwards(push) { + if (this.value instanceof AST_Node) push(this.value); + if (this.key instanceof AST_Node) push(this.key); + }, }, AST_ObjectProperty); var AST_DefClass = DEFNODE("DefClass", null, { @@ -1201,7 +1374,10 @@ var AST_Await = DEFNODE("Await", "expression", { return visitor._visit(this, function() { this.expression._walk(visitor); }); - } + }, + _children_backwards(push) { + push(this.expression); + }, }); var AST_Yield = DEFNODE("Yield", "expression is_star", { @@ -1214,9 +1390,39 @@ var AST_Yield = DEFNODE("Yield", "expression is_star", { return visitor._visit(this, this.expression && function() { this.expression._walk(visitor); }); + }, + _children_backwards(push) { + if (this.expression) push(this.expression); } }); +/* -----[ Walk function ]---- */ + +/** + * Walk nodes in depth-first search fashion. + * Callback can return `walk_abort` symbol to stop iteration. + * It can also return `true` to stop iteration just for child nodes. + * Iteration can be stopped and continued by passing the `to_visit` argument, + * which is given to the callback in the second argument. + **/ +function walk(node, cb, to_visit = [node]) { + const push = to_visit.push.bind(to_visit); + while (to_visit.length) { + const node = to_visit.pop(); + const ret = cb(node, to_visit); + + if (ret) { + if (ret === walk_abort) return true; + continue; + } + + node._children_backwards(push); + } + return false; +} + +const walk_abort = Symbol("abort walk"); + /* -----[ TreeWalker ]----- */ class TreeWalker { @@ -1437,6 +1643,8 @@ export { AST_Yield, TreeTransformer, TreeWalker, + walk, + walk_abort, walk_body, _INLINE, _NOINLINE, diff --git a/lib/compress/index.js b/lib/compress/index.js index f52479b51..d475d08e3 100644 --- a/lib/compress/index.js +++ b/lib/compress/index.js @@ -168,11 +168,14 @@ import { AST_Yield, TreeTransformer, TreeWalker, + walk, + walk_abort, walk_body, _INLINE, _NOINLINE, _PURE } from "../ast.js"; +import { equivalent_to } from "../equivalent-to.js"; import { is_identifier_string, JS_Parse_Error, @@ -372,9 +375,7 @@ class Compressor extends TreeWalker { toplevel = toplevel.transform(this); if (passes > 1) { let count = 0; - toplevel.walk(new TreeWalker(function() { - count++; - })); + walk(toplevel, () => { count++; }); this.info("pass " + pass + ": last_count: " + min_count + ", count: " + count); if (count < min_count) { min_count = count; @@ -413,7 +414,7 @@ class Compressor extends TreeWalker { this.warnings_produced = {}; } - before(node, descend, in_list) { + before(node, descend) { if (has_flag(node, SQUEEZED)) return node; var was_scope = false; if (node instanceof AST_Scope) { @@ -454,7 +455,7 @@ function def_optimize(node, optimizer) { }); } -def_optimize(AST_Node, function(self, compressor) { +def_optimize(AST_Node, function(self) { return self; }); @@ -476,7 +477,7 @@ AST_Toplevel.DEFMETHOD("drop_console", function() { }); AST_Node.DEFMETHOD("equivalent_to", function(node) { - return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string(); + return equivalent_to(this, node); }); AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) { @@ -709,7 +710,7 @@ function is_modified(compressor, tw, node, value, level, immutable) { d.direct_access = true; } - var suppressor = new TreeWalker(function(node) { + const suppress = node => walk(node, node => { if (!(node instanceof AST_Symbol)) return; var d = node.definition(); if (!d) return; @@ -726,7 +727,7 @@ function is_modified(compressor, tw, node, value, level, immutable) { def_reduce_vars(AST_Assign, function(tw, descend, compressor) { var node = this; if (node.left instanceof AST_Destructuring) { - node.left.walk(suppressor); + suppress(node.left); return; } var sym = node.left; @@ -879,7 +880,7 @@ function is_modified(compressor, tw, node, value, level, immutable) { }); def_reduce_vars(AST_ForIn, function(tw, descend, compressor) { reset_block_variables(compressor, this); - this.init.walk(suppressor); + suppress(this.init); this.object.walk(tw); const saved_loop = tw.in_loop; tw.in_loop = this; @@ -970,7 +971,7 @@ function is_modified(compressor, tw, node, value, level, immutable) { if (this.bfinally) this.bfinally.walk(tw); return true; }); - def_reduce_vars(AST_Unary, function(tw, descend) { + def_reduce_vars(AST_Unary, function(tw) { var node = this; if (node.operator !== "++" && node.operator !== "--") return; var exp = node.expression; @@ -1001,7 +1002,7 @@ function is_modified(compressor, tw, node, value, level, immutable) { def_reduce_vars(AST_VarDef, function(tw, descend) { var node = this; if (node.name instanceof AST_Destructuring) { - node.name.walk(suppressor); + suppress(node.name); return; } var d = node.name.definition(); @@ -1305,7 +1306,7 @@ function tighten_body(statements, compressor) { var args; var candidates = []; var stat_index = statements.length; - var scanner = new TreeTransformer(function(node, descend) { + var scanner = new TreeTransformer(function(node) { if (abort) return node; // Skip nodes before `candidate` as quickly as possible if (!hit) { @@ -1774,7 +1775,7 @@ function tighten_body(statements, compressor) { function get_lvalues(expr) { var lvalues = new Map(); if (expr instanceof AST_Unary) return lvalues; - var tw = new TreeWalker(function(node, descend) { + var tw = new TreeWalker(function(node) { var sym = node; while (sym instanceof AST_PropAccess) sym = sym.expression; if (sym instanceof AST_SymbolRef || sym instanceof AST_This) { @@ -2191,14 +2192,15 @@ function tighten_body(statements, compressor) { stat.value = cons_seq(stat.value || make_node(AST_Undefined, stat).transform(compressor)); } else if (stat instanceof AST_For) { if (!(stat.init instanceof AST_Definitions)) { - var abort = false; - prev.body.walk(new TreeWalker(function(node) { - if (abort || node instanceof AST_Scope) return true; - if (node instanceof AST_Binary && node.operator == "in") { - abort = true; - return true; + const abort = walk(prev.body, node => { + if (node instanceof AST_Scope) return true; + if ( + node instanceof AST_Binary + && node.operator === "in" + ) { + return walk_abort; } - })); + }); if (!abort) { if (stat.init) stat.init = cons_seq(stat.init); else { @@ -2382,14 +2384,17 @@ function extract_declarations_from_unreachable_code(compressor, stat, target) { if (!(stat instanceof AST_Defun)) { compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start); } - stat.walk(new TreeWalker(function(node) { + walk(stat, node => { if (node instanceof AST_Var) { compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start); node.remove_initializers(); target.push(node); return true; } - if (node instanceof AST_Defun && (node === stat || !compressor.has_directive("use strict"))) { + if ( + node instanceof AST_Defun + && (node === stat || !compressor.has_directive("use strict")) + ) { target.push(node === stat ? node : make_node(AST_Var, node, { definitions: [ make_node(AST_VarDef, node, { @@ -2403,7 +2408,7 @@ function extract_declarations_from_unreachable_code(compressor, stat, target) { if (node instanceof AST_Scope) { return true; } - })); + }); } function get_value(key) { @@ -3320,7 +3325,7 @@ const pure_prop_access_globals = new Set([ def_has_side_effects(AST_Definitions, function(compressor) { return any(this.definitions, compressor); }); - def_has_side_effects(AST_VarDef, function(compressor) { + def_has_side_effects(AST_VarDef, function() { return this.value; }); def_has_side_effects(AST_TemplateSegment, return_false); @@ -3457,34 +3462,35 @@ const pure_prop_access_globals = new Set([ // determine if expression is constant (function(def_is_constant_expression) { function all_refs_local(scope) { - var self = this; - var result = true; - self.walk(new TreeWalker(function(node) { - if (!result) return true; + let result = true; + walk(this, node => { if (node instanceof AST_SymbolRef) { - if (has_flag(self, INLINED)) { + if (has_flag(this, INLINED)) { result = false; - return true; + return walk_abort; } var def = node.definition(); - if (member(def, self.enclosed) - && !self.variables.has(def.name)) { + if ( + member(def, this.enclosed) + && !this.variables.has(def.name) + ) { if (scope) { var scope_def = scope.find_variable(node); if (def.undeclared ? !scope_def : scope_def === def) { result = "f"; - return true; + return walk_abort; } } result = false; + return walk_abort; } return true; } - if (node instanceof AST_This && self instanceof AST_Arrow) { + if (node instanceof AST_This && this instanceof AST_Arrow) { result = false; - return true; + return walk_abort; } - })); + }); return result; } @@ -3635,7 +3641,6 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) { } var var_defs_by_id = new Map(); var initializations = new Map(); - var destructuring_value = null; // pass 1: find out which symbols are directly used in // this scope (not in nested scopes). var scope = this; @@ -3677,14 +3682,17 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) { map_add(var_defs_by_id, def.name.definition().id, def); } if (in_export || !drop_vars) { - def.name.walk(new TreeWalker(function(node) { + walk(def.name, node => { if (node instanceof AST_SymbolDeclaration) { - var def = node.definition(); - if ((in_export || def.global) && !in_use_ids.has(def.id)) { + const def = node.definition(); + if ( + (in_export || def.global) + && !in_use_ids.has(def.id) + ) { in_use_ids.set(def.id, def); } } - })); + }); } if (def.value) { if (def.name instanceof AST_Destructuring) { @@ -4002,14 +4010,14 @@ AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) { var vars = new Map(), vars_found = 0, var_decl = 0; // let's count var_decl first, we seem to waste a lot of // space if we hoist `var` when there's only one. - self.walk(new TreeWalker(function(node) { + walk(self, node => { if (node instanceof AST_Scope && node !== self) return true; if (node instanceof AST_Var) { ++var_decl; return true; } - })); + }); hoist_vars = hoist_vars && var_decl > 1; var tt = new TreeTransformer( function before(node) { @@ -4835,14 +4843,16 @@ AST_Definitions.DEFMETHOD("remove_initializers", function() { if (def.name instanceof AST_SymbolDeclaration) { def.value = null; decls.push(def); - } else def.name.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolDeclaration) { - decls.push(make_node(AST_VarDef, def, { - name: node, - value: null - })); - } - })); + } else { + walk(def.name, node => { + if (node instanceof AST_SymbolDeclaration) { + decls.push(make_node(AST_VarDef, def, { + name: node, + value: null + })); + } + }); + } }); this.definitions = decls; }); @@ -4878,13 +4888,13 @@ AST_Definitions.DEFMETHOD("to_assignments", function(compressor) { return make_sequence(this, assignments); }); -def_optimize(AST_Definitions, function(self, compressor) { +def_optimize(AST_Definitions, function(self) { if (self.definitions.length == 0) return make_node(AST_EmptyStatement, self); return self; }); -def_optimize(AST_Import, function(self, compressor) { +def_optimize(AST_Import, function(self) { return self; }); @@ -5177,13 +5187,12 @@ def_optimize(AST_Call, function(self, compressor) { ast.compute_char_frequency(mangle); ast.mangle_names(mangle); var fun; - ast.walk(new TreeWalker(function(node) { - if (fun) return true; + walk(ast, node => { if (is_func_expr(node)) { fun = node; - return true; + return walk_abort; } - })); + }); var code = OutputStream(); AST_BlockStatement.prototype._codegen.call(fun, fun, code); self.args = [ @@ -5342,7 +5351,7 @@ def_optimize(AST_Call, function(self, compressor) { function can_inject_args_values() { var arg_vals_outer_refs = new Set(); - var value_walker = new TreeWalker(function(node) { + const value_walker = node => { if (node instanceof AST_Scope) { var scope_outer_refs = new Set(); node.enclosed.forEach(function(def) { @@ -5356,20 +5365,19 @@ def_optimize(AST_Call, function(self, compressor) { }); return true; } - return false; - }); - self.args.forEach(function(value) { - value.walk(value_walker); - }); + }; + for (let i = 0; i < self.args.length; i++) { + walk(self.args[i], value_walker); + } if (arg_vals_outer_refs.size == 0) return true; - for (var i = 0, len = fn.argnames.length; i < len; i++) { + for (let i = 0, len = fn.argnames.length; i < len; i++) { var arg = fn.argnames[i]; if (arg instanceof AST_DefaultAssign && has_flag(arg.left, UNUSED)) continue; if (arg instanceof AST_Expansion && has_flag(arg.expression, UNUSED)) continue; if (has_flag(arg, UNUSED)) continue; if (arg_vals_outer_refs.has(arg.name)) return false; } - for (var i = 0, len = fn.body.length; i < len; i++) { + for (let i = 0, len = fn.body.length; i < len; i++) { var stat = fn.body[i]; if (!(stat instanceof AST_Var)) continue; for (var j = stat.definitions.length; --j >= 0;) { @@ -6137,7 +6145,7 @@ def_optimize(AST_Binary, function(self, compressor) { return self; }); -def_optimize(AST_SymbolExport, function(self, compressor) { +def_optimize(AST_SymbolExport, function(self) { return self; }); @@ -6255,12 +6263,12 @@ def_optimize(AST_SymbolRef, function(self, compressor) { fixed.name = name; lambda_def = fixed.def_function(name); } - fixed.walk(new TreeWalker(function(node) { + walk(fixed, node => { if (node instanceof AST_SymbolRef && node.definition() === defun_def) { node.thedef = lambda_def; lambda_def.references.push(node); } - })); + }); } if (fixed instanceof AST_Lambda || fixed instanceof AST_Class) { find_scope(compressor, true).add_child_scope(fixed); @@ -6314,12 +6322,9 @@ def_optimize(AST_SymbolRef, function(self, compressor) { return self; function has_symbol_ref(value) { - var found; - value.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolRef) found = true; - if (found) return true; - })); - return found; + return walk(value, node => { + if (node instanceof AST_SymbolRef) return walk_abort; + }); } }); @@ -6918,14 +6923,16 @@ def_optimize(AST_Sub, function(self, compressor) { }); AST_Lambda.DEFMETHOD("contains_this", function() { - var result; - var self = this; - self.walk(new TreeWalker(function(node) { - if (result) return true; - if (node instanceof AST_This) return result = true; - if (node !== self && node instanceof AST_Scope && !(node instanceof AST_Arrow)) return true; - })); - return result; + return walk(this, node => { + if (node instanceof AST_This) return walk_abort; + if ( + node !== this + && node instanceof AST_Scope + && !(node instanceof AST_Arrow) + ) { + return true; + } + }); }); AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) { @@ -7104,20 +7111,15 @@ def_optimize(AST_Function, function(self, compressor) { && !self.is_generator && !self.uses_arguments && !self.pinned()) { - var has_special_symbol = false; - self.walk(new TreeWalker(function(node) { - if (has_special_symbol) return true; - if (node instanceof AST_This) { - has_special_symbol = true; - return true; - } - })); + const has_special_symbol = walk(self, node => { + if (node instanceof AST_This) return walk_abort; + }); if (!has_special_symbol) return make_node(AST_Arrow, self, self).optimize(compressor); } return self; }); -def_optimize(AST_Class, function(self, compressor) { +def_optimize(AST_Class, function(self) { // HACK to avoid compress failure. // AST_Class is not really an AST_Scope/AST_Block as it lacks a body. return self; @@ -7155,7 +7157,7 @@ def_optimize(AST_TemplateString, function(self, compressor) { return segments.length == 1 ? make_node(AST_String, self, segments[0]) : self; }); -def_optimize(AST_PrefixedTemplateString, function(self, compressor) { +def_optimize(AST_PrefixedTemplateString, function(self) { return self; }); diff --git a/lib/mozilla-ast.js b/lib/mozilla-ast.js index d13872dae..330c4b380 100644 --- a/lib/mozilla-ast.js +++ b/lib/mozilla-ast.js @@ -646,7 +646,7 @@ import { return to_moz_scope("Program", M); }); - def_to_moz(AST_Expansion, function To_Moz_Spread(M, parent) { + def_to_moz(AST_Expansion, function To_Moz_Spread(M) { return { type: to_moz_in_destructuring() ? "RestElement" : "SpreadElement", argument: to_moz(M.expression) @@ -994,7 +994,7 @@ import { }; }); - def_to_moz(AST_NewTarget, function To_Moz_MetaProperty(M) { + def_to_moz(AST_NewTarget, function To_Moz_MetaProperty() { return { type: "MetaProperty", meta: { @@ -1179,7 +1179,7 @@ import { return ast; }; - function set_moz_loc(mynode, moznode, myparent) { + function set_moz_loc(mynode, moznode) { var start = mynode.start; var end = mynode.end; if (!(start && end)) { diff --git a/lib/output.js b/lib/output.js index 09b7e3ec8..d5729f7c7 100644 --- a/lib/output.js +++ b/lib/output.js @@ -142,6 +142,8 @@ import { AST_With, AST_Yield, TreeWalker, + walk, + walk_abort } from "./ast.js"; import { get_full_char_code, @@ -994,15 +996,12 @@ function OutputStream(options) { // parens around it too, otherwise the call will be // interpreted as passing the arguments to the upper New // expression. - var parens = false; - this.walk(new TreeWalker(function(node) { - if (parens || node instanceof AST_Scope) return true; + return walk(this, node => { + if (node instanceof AST_Scope) return true; if (node instanceof AST_Call) { - parens = true; - return true; + return walk_abort; // makes walk() return true. } - })); - return parens; + }); } }); @@ -1678,13 +1677,14 @@ function OutputStream(options) { var parens = false; // need to take some precautions here: // https://github.com/mishoo/UglifyJS2/issues/60 - if (noin) node.walk(new TreeWalker(function(node) { - if (parens || node instanceof AST_Scope) return true; - if (node instanceof AST_Binary && node.operator == "in") { - parens = true; - return true; - } - })); + if (noin) { + parens = walk(node, node => { + if (node instanceof AST_Scope) return true; + if (node instanceof AST_Binary && node.operator == "in") { + return walk_abort; // makes walk() return true + } + }); + } node.print(output, parens); } diff --git a/lib/parse.js b/lib/parse.js index 1f89bec90..d4273b5b1 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -47,7 +47,6 @@ import { characters, defaults, - HOP, makePredicate, set_annotation, } from "./utils/index.js"; @@ -1464,8 +1463,6 @@ function parse($TEXT, options) { }; var function_ = function(ctor, is_generator_property, is_async, is_export_default) { - var start = S.token; - var in_statement = ctor === AST_Defun; var is_generator = is("operator", "*"); if (is_generator) { @@ -1556,7 +1553,6 @@ function parse($TEXT, options) { } function parameters(params) { - var start = S.token; var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict")); expect("("); @@ -2278,7 +2274,7 @@ function parse($TEXT, options) { unexpected(); }; - function template_string(tagged) { + function template_string() { var segments = [], start = S.token; segments.push(new AST_TemplateSegment({ diff --git a/lib/propmangle.js b/lib/propmangle.js index 269ef15cd..c92ecf97b 100644 --- a/lib/propmangle.js +++ b/lib/propmangle.js @@ -51,7 +51,6 @@ import { import { base54 } from "./scope"; import { AST_Call, - AST_ClassProperty, AST_Conditional, AST_Dot, AST_ObjectKeyVal, diff --git a/lib/scope.js b/lib/scope.js index e3ac076f9..3a55d9fed 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -46,7 +46,6 @@ import { defaults, keep_name, - member, mergeSort, push_uniq, return_false, @@ -103,6 +102,7 @@ import { AST_VarDef, AST_With, TreeWalker, + walk } from "./ast.js"; import { RESERVED_WORDS, @@ -201,13 +201,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { }); // pass 1: setup scope chaining and handle definitions - var self = this; - var scope = self.parent_scope = null; + var scope = this.parent_scope = null; var labels = new Map(); var defun = null; var in_destructuring = null; var for_scopes = []; - var tw = new TreeWalker(function(node, descend) { + var tw = new TreeWalker((node, descend) => { if (node.is_block_scope()) { const save_scope = scope; node.block_scope = scope = new AST_Scope(node); @@ -358,7 +357,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { ); } }); - self.walk(tw); + this.walk(tw); function mark_export(def, level) { if (in_destructuring) { @@ -377,8 +376,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { } // pass 2: find back references and eval - self.globals = new Map(); - var tw = new TreeWalker(function(node, descend) { + this.globals = new Map(); + var tw = new TreeWalker(node => { if (node instanceof AST_LoopControl && node.label) { node.label.thedef.references.push(node); return true; @@ -393,7 +392,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { var sym; if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name || !(sym = node.scope.find_variable(name))) { - sym = self.def_global(node); + sym = this.def_global(node); if (node instanceof AST_SymbolExport) sym.export = MASK_EXPORT_DONT_MANGLE; } else if (sym.scope instanceof AST_Lambda && name == "arguments") { sym.scope.uses_arguments = true; @@ -417,16 +416,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { } } }); - self.walk(tw); + this.walk(tw); // pass 3: work around IE8 and Safari catch scope bugs if (options.ie8 || options.safari10) { - self.walk(new TreeWalker(function(node, descend) { + walk(this, node => { if (node instanceof AST_SymbolCatch) { var name = node.name; var refs = node.thedef.references; var scope = node.scope.get_defun_scope(); - var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node); + var def = scope.find_variable(name) || this.globals.get(name) || scope.def_variable(node); refs.forEach(function(ref) { ref.thedef = def; ref.reference(options); @@ -435,7 +434,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { node.reference(options); return true; } - })); + }); } // pass 4: add symbol definitions to loop scopes @@ -567,7 +566,7 @@ AST_Arrow.DEFMETHOD("init_scope_vars", function() { this.uses_arguments = false; }); -AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { +AST_Symbol.DEFMETHOD("mark_enclosed", function() { var def = this.definition(); var s = this.scope; while (s) { diff --git a/package.json b/package.json index 8b7045dc8..5bf9b7940 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,12 @@ ], "no-debugger": "error", "no-undef": "error", + "no-unused-vars": [ + "error", + { + "varsIgnorePattern": "^_$" + } + ], "no-tabs": "error", "semi": [ "error",