From 7dc61cdc895d055edfa9b1d82d17688ad3a57f1c Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 23 Aug 2020 21:39:38 +0100 Subject: [PATCH] tidy up various interfaces (#4066) --- lib/ast.js | 12 +-- lib/compress.js | 8 +- lib/output.js | 263 ++++++++++++++++++++++++---------------------- lib/propmangle.js | 2 - lib/scope.js | 48 ++++----- 5 files changed, 167 insertions(+), 166 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 2c27cbbe..b6d4ebb7 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -409,16 +409,16 @@ var AST_With = DEFNODE("With", "expression", { /* -----[ scope and functions ]----- */ -var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", { +var AST_Scope = DEFNODE("Scope", "cname enclosed uses_eval uses_with parent_scope functions variables make_def", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { - variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", - functions: "[Object/S] like `variables`, but only lists function declarations", - uses_with: "[boolean/S] tells whether this scope uses the `with` statement", + cname: "[integer/S] current index for mangling variables (used internally by the mangler)", + enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", + uses_with: "[boolean/S] tells whether this scope uses the `with` statement", parent_scope: "[AST_Scope?/S] link to the parent scope", - enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", - cname: "[integer/S] current index for mangling variables (used internally by the mangler)", + functions: "[Object/S] like `variables`, but only lists function declarations", + variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", }, clone: function(deep) { var node = this._clone(deep); diff --git a/lib/compress.js b/lib/compress.js index bcaecb8a..3291f167 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3152,11 +3152,11 @@ merge(Compressor.prototype, { return this.expression._find_defs(compressor, "." + this.property + suffix); }); def(AST_SymbolDeclaration, function(compressor) { - if (!this.global()) return; + if (!this.definition().global) return; if (HOP(compressor.option("global_defs"), this.name)) warn(this); }); def(AST_SymbolRef, function(compressor, suffix) { - if (!this.global()) return; + if (!this.definition().global) return; var defines = compressor.option("global_defs"); var name = this.name + suffix; if (HOP(defines, name)) return to_node(defines[name], this); @@ -4700,7 +4700,7 @@ merge(Compressor.prototype, { }); function log(sym, text, props) { - AST_Node[sym.unreferenced() ? "warn" : "info"](text, props); + AST_Node[sym.definition().references.length > 0 ? "info" : "warn"](text, props); } function template(sym) { @@ -6395,7 +6395,7 @@ merge(Compressor.prototype, { } })); var code = OutputStream(); - AST_BlockStatement.prototype._codegen.call(fun, fun, code); + AST_BlockStatement.prototype._codegen.call(fun, code); self.args = [ make_node(AST_String, self, { value: fun.argnames.map(function(arg) { diff --git a/lib/output.js b/lib/output.js index 19c37b29..82610fb6 100644 --- a/lib/output.js +++ b/lib/output.js @@ -630,13 +630,7 @@ function OutputStream(options) { var use_asm = false; AST_Node.DEFMETHOD("print", function(stream, force_parens) { - var self = this, generator = self._codegen; - function doit() { - stream.prepend_comments(self); - self.add_source_map(stream); - generator(self, stream); - stream.append_comments(self); - } + var self = this; stream.push_node(self); if (force_parens || self.needs_parens(stream)) { stream.with_parens(doit); @@ -644,9 +638,14 @@ function OutputStream(options) { doit(); } stream.pop_node(); - }); - AST_Node.DEFMETHOD("_print", AST_Node.prototype.print); + function doit() { + stream.prepend_comments(self); + self.add_source_map(stream); + self._codegen(stream); + stream.append_comments(self); + } + }); AST_Node.DEFMETHOD("print_to_string", function(options) { var s = OutputStream(options); this.print(s); @@ -813,9 +812,9 @@ function OutputStream(options) { /* -----[ PRINTERS ]----- */ - DEFPRINT(AST_Directive, function(self, output) { - var quote = self.quote; - var value = self.value; + DEFPRINT(AST_Directive, function(output) { + var quote = this.quote; + var value = this.value; switch (output.option("quote_style")) { case 0: case 2: @@ -828,7 +827,7 @@ function OutputStream(options) { output.print(quote + value + quote); output.semicolon(); }); - DEFPRINT(AST_Debugger, function(self, output) { + DEFPRINT(AST_Debugger, function(output) { output.print("debugger"); output.semicolon(); }); @@ -864,21 +863,21 @@ function OutputStream(options) { force_statement(this.body, output); }); - DEFPRINT(AST_Statement, function(self, output) { - self.body.print(output); + DEFPRINT(AST_Statement, function(output) { + this.body.print(output); output.semicolon(); }); - DEFPRINT(AST_Toplevel, function(self, output) { - display_body(self.body, true, output, true); + DEFPRINT(AST_Toplevel, function(output) { + display_body(this.body, true, output, true); output.print(""); }); - DEFPRINT(AST_LabeledStatement, function(self, output) { - self.label.print(output); + DEFPRINT(AST_LabeledStatement, function(output) { + this.label.print(output); output.colon(); - self.body.print(output); + this.body.print(output); }); - DEFPRINT(AST_SimpleStatement, function(self, output) { - self.body.print(output); + DEFPRINT(AST_SimpleStatement, function(output) { + this.body.print(output); output.semicolon(); }); function print_braced_empty(self, output) { @@ -895,13 +894,14 @@ function OutputStream(options) { }); } else print_braced_empty(self, output); } - DEFPRINT(AST_BlockStatement, function(self, output) { - print_braced(self, output); + DEFPRINT(AST_BlockStatement, function(output) { + print_braced(this, output); }); - DEFPRINT(AST_EmptyStatement, function(self, output) { + DEFPRINT(AST_EmptyStatement, function(output) { output.semicolon(); }); - DEFPRINT(AST_Do, function(self, output) { + DEFPRINT(AST_Do, function(output) { + var self = this; output.print("do"); output.space(); make_block(self.body, output); @@ -913,7 +913,8 @@ function OutputStream(options) { }); output.semicolon(); }); - DEFPRINT(AST_While, function(self, output) { + DEFPRINT(AST_While, function(output) { + var self = this; output.print("while"); output.space(); output.with_parens(function() { @@ -922,7 +923,8 @@ function OutputStream(options) { output.space(); self._do_print_body(output); }); - DEFPRINT(AST_For, function(self, output) { + DEFPRINT(AST_For, function(output) { + var self = this; output.print("for"); output.space(); output.with_parens(function() { @@ -951,7 +953,8 @@ function OutputStream(options) { output.space(); self._do_print_body(output); }); - DEFPRINT(AST_ForIn, function(self, output) { + DEFPRINT(AST_ForIn, function(output) { + var self = this; output.print("for"); output.space(); output.with_parens(function() { @@ -964,7 +967,8 @@ function OutputStream(options) { output.space(); self._do_print_body(output); }); - DEFPRINT(AST_With, function(self, output) { + DEFPRINT(AST_With, function(output) { + var self = this; output.print("with"); output.space(); output.with_parens(function() { @@ -975,7 +979,7 @@ function OutputStream(options) { }); /* -----[ functions ]----- */ - AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) { + DEFPRINT(AST_Lambda, function(output, nokeyword) { var self = this; if (!nokeyword) { output.print("function"); @@ -993,32 +997,23 @@ function OutputStream(options) { output.space(); print_braced(self, output, true); }); - DEFPRINT(AST_Lambda, function(self, output) { - self._do_print(output); - }); /* -----[ jumps ]----- */ - function print_jump(output, kind, target) { - output.print(kind); - if (target) { - output.space(); - target.print(output); - } - output.semicolon(); + function print_jump(kind, prop) { + return function(output) { + output.print(kind); + var target = this[prop]; + if (target) { + output.space(); + target.print(output); + } + output.semicolon(); + }; } - - DEFPRINT(AST_Return, function(self, output) { - print_jump(output, "return", self.value); - }); - DEFPRINT(AST_Throw, function(self, output) { - print_jump(output, "throw", self.value); - }); - DEFPRINT(AST_Break, function(self, output) { - print_jump(output, "break", self.label); - }); - DEFPRINT(AST_Continue, function(self, output) { - print_jump(output, "continue", self.label); - }); + DEFPRINT(AST_Return, print_jump("return", "value")); + DEFPRINT(AST_Throw, print_jump("throw", "value")); + DEFPRINT(AST_Break, print_jump("break", "label")); + DEFPRINT(AST_Continue, print_jump("continue", "label")); /* -----[ if ]----- */ function make_then(self, output) { @@ -1047,7 +1042,8 @@ function OutputStream(options) { } force_statement(self.body, output); } - DEFPRINT(AST_If, function(self, output) { + DEFPRINT(AST_If, function(output) { + var self = this; output.print("if"); output.space(); output.with_parens(function() { @@ -1069,7 +1065,8 @@ function OutputStream(options) { }); /* -----[ switch ]----- */ - DEFPRINT(AST_Switch, function(self, output) { + DEFPRINT(AST_Switch, function(output) { + var self = this; output.print("switch"); output.space(); output.with_parens(function() { @@ -1087,28 +1084,30 @@ function OutputStream(options) { }); }); }); - AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) { + function print_branch_body(self, output) { output.newline(); - this.body.forEach(function(stmt) { + self.body.forEach(function(stmt) { output.indent(); stmt.print(output); output.newline(); }); - }); - DEFPRINT(AST_Default, function(self, output) { + } + DEFPRINT(AST_Default, function(output) { output.print("default:"); - self._do_print_body(output); + print_branch_body(this, output); }); - DEFPRINT(AST_Case, function(self, output) { + DEFPRINT(AST_Case, function(output) { + var self = this; output.print("case"); output.space(); self.expression.print(output); output.print(":"); - self._do_print_body(output); + print_branch_body(self, output); }); /* -----[ exceptions ]----- */ - DEFPRINT(AST_Try, function(self, output) { + DEFPRINT(AST_Try, function(output) { + var self = this; output.print("try"); output.space(); print_braced(self, output); @@ -1121,7 +1120,8 @@ function OutputStream(options) { self.bfinally.print(output); } }); - DEFPRINT(AST_Catch, function(self, output) { + DEFPRINT(AST_Catch, function(output) { + var self = this; output.print("catch"); output.space(); output.with_parens(function() { @@ -1130,13 +1130,14 @@ function OutputStream(options) { output.space(); print_braced(self, output); }); - DEFPRINT(AST_Finally, function(self, output) { + DEFPRINT(AST_Finally, function(output) { output.print("finally"); output.space(); - print_braced(self, output); + print_braced(this, output); }); - DEFPRINT(AST_Var, function(self, output) { + DEFPRINT(AST_Var, function(output) { + var self = this; output.print("var"); output.space(); self.definitions.forEach(function(def, i) { @@ -1161,7 +1162,8 @@ function OutputStream(options) { node.print(output, parens); } - DEFPRINT(AST_VarDef, function(self, output) { + DEFPRINT(AST_VarDef, function(output) { + var self = this; self.name.print(output); if (self.value) { output.space(); @@ -1185,18 +1187,19 @@ function OutputStream(options) { }); }); } - DEFPRINT(AST_Call, function(self, output) { - self.expression.print(output); - print_call_args(self, output); + DEFPRINT(AST_Call, function(output) { + this.expression.print(output); + print_call_args(this, output); }); - DEFPRINT(AST_New, function(self, output) { + DEFPRINT(AST_New, function(output) { + var self = this; output.print("new"); output.space(); self.expression.print(output); if (need_constructor_parens(self, output)) print_call_args(self, output); }); - DEFPRINT(AST_Sequence, function(self, output) { - self.expressions.forEach(function(node, index) { + DEFPRINT(AST_Sequence, function(output) { + this.expressions.forEach(function(node, index) { if (index > 0) { output.comma(); if (output.should_break()) { @@ -1207,7 +1210,8 @@ function OutputStream(options) { node.print(output); }); }); - DEFPRINT(AST_Dot, function(self, output) { + DEFPRINT(AST_Dot, function(output) { + var self = this; var expr = self.expression; expr.print(output); var prop = self.property; @@ -1228,35 +1232,38 @@ function OutputStream(options) { output.print_name(prop); } }); - DEFPRINT(AST_Sub, function(self, output) { - self.expression.print(output); + DEFPRINT(AST_Sub, function(output) { + this.expression.print(output); output.print("["); - self.property.print(output); + this.property.print(output); output.print("]"); }); - DEFPRINT(AST_UnaryPrefix, function(self, output) { - var op = self.operator; + DEFPRINT(AST_UnaryPrefix, function(output) { + var op = this.operator; + var exp = this.expression; output.print(op); if (/^[a-z]/i.test(op) || (/[+-]$/.test(op) - && self.expression instanceof AST_UnaryPrefix - && /^[+-]/.test(self.expression.operator))) { + && exp instanceof AST_UnaryPrefix + && /^[+-]/.test(exp.operator))) { output.space(); } - self.expression.print(output); + exp.print(output); }); - DEFPRINT(AST_UnaryPostfix, function(self, output) { - self.expression.print(output); - output.print(self.operator); + DEFPRINT(AST_UnaryPostfix, function(output) { + this.expression.print(output); + output.print(this.operator); }); - DEFPRINT(AST_Binary, function(self, output) { + DEFPRINT(AST_Binary, function(output) { + var self = this; self.left.print(output); output.space(); output.print(self.operator); output.space(); self.right.print(output); }); - DEFPRINT(AST_Conditional, function(self, output) { + DEFPRINT(AST_Conditional, function(output) { + var self = this; self.condition.print(output); output.space(); output.print("?"); @@ -1268,10 +1275,10 @@ function OutputStream(options) { }); /* -----[ literals ]----- */ - DEFPRINT(AST_Array, function(self, output) { - output.with_square(function() { - var a = self.elements, len = a.length; - if (len > 0) output.space(); + DEFPRINT(AST_Array, function(output) { + var a = this.elements, len = a.length; + output.with_square(len > 0 ? function() { + output.space(); a.forEach(function(exp, i) { if (i) output.comma(); exp.print(output); @@ -1281,12 +1288,13 @@ function OutputStream(options) { if (i === len - 1 && exp instanceof AST_Hole) output.comma(); }); - if (len > 0) output.space(); - }); + output.space(); + } : noop); }); - DEFPRINT(AST_Object, function(self, output) { - if (self.properties.length > 0) output.with_block(function() { - self.properties.forEach(function(prop, i) { + DEFPRINT(AST_Object, function(output) { + var props = this.properties; + if (props.length > 0) output.with_block(function() { + props.forEach(function(prop, i) { if (i) { output.print(","); output.newline(); @@ -1296,7 +1304,7 @@ function OutputStream(options) { }); output.newline(); }); - else print_braced_empty(self, output); + else print_braced_empty(this, output); }); function print_property_name(key, quote, output) { @@ -1315,47 +1323,48 @@ function OutputStream(options) { } } - DEFPRINT(AST_ObjectKeyVal, function(self, output) { + DEFPRINT(AST_ObjectKeyVal, function(output) { + var self = this; print_property_name(self.key, self.quote, output); output.colon(); self.value.print(output); }); - AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) { - output.print(type); - output.space(); - print_property_name(this.key.name, this.quote, output); - this.value._do_print(output, true); - }); - DEFPRINT(AST_ObjectSetter, function(self, output) { - self._print_getter_setter("set", output); - }); - DEFPRINT(AST_ObjectGetter, function(self, output) { - self._print_getter_setter("get", output); - }); - DEFPRINT(AST_Symbol, function(self, output) { - var def = self.definition(); - output.print_name(def && def.mangled_name || self.name); + function print_accessor(type) { + return function(output) { + var self = this; + output.print(type); + output.space(); + print_property_name(self.key.name, self.quote, output); + self.value._codegen(output, true); + }; + } + DEFPRINT(AST_ObjectGetter, print_accessor("get")); + DEFPRINT(AST_ObjectSetter, print_accessor("set")); + DEFPRINT(AST_Symbol, function(output) { + var def = this.definition(); + output.print_name(def && def.mangled_name || this.name); }); DEFPRINT(AST_Hole, noop); - DEFPRINT(AST_This, function(self, output) { + DEFPRINT(AST_This, function(output) { output.print("this"); }); - DEFPRINT(AST_Constant, function(self, output) { - output.print(self.value); + DEFPRINT(AST_Constant, function(output) { + output.print(this.value); }); - DEFPRINT(AST_String, function(self, output) { - output.print_string(self.value, self.quote); + DEFPRINT(AST_String, function(output) { + output.print_string(this.value, this.quote); }); - DEFPRINT(AST_Number, function(self, output) { - if (use_asm && self.start && self.start.raw != null) { - output.print(self.start.raw); + DEFPRINT(AST_Number, function(output) { + var start = this.start; + if (use_asm && start && start.raw != null) { + output.print(start.raw); } else { - output.print(make_num(self.value)); + output.print(make_num(this.value)); } }); - DEFPRINT(AST_RegExp, function(self, output) { - var regexp = self.value; + DEFPRINT(AST_RegExp, function(output) { + var regexp = this.value; var str = regexp.toString(); var end = str.lastIndexOf("/"); if (regexp.raw_source) { @@ -1389,7 +1398,7 @@ function OutputStream(options) { } })); var p = output.parent(); - if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) + if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === this) output.print(" "); }); diff --git a/lib/propmangle.js b/lib/propmangle.js index 04194393..e47497de 100644 --- a/lib/propmangle.js +++ b/lib/propmangle.js @@ -110,7 +110,6 @@ function mangle_properties(ast, options) { cache: null, debug: false, keep_quoted: false, - only_cache: false, regex: null, reserved: null, }, true); @@ -213,7 +212,6 @@ function mangle_properties(ast, options) { function can_mangle(name) { if (unmangleable[name]) return false; - if (options.only_cache) return cache.has(name); if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; return true; } diff --git a/lib/scope.js b/lib/scope.js index 450c1062..5d990c06 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -96,8 +96,9 @@ 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 defun = null; + var next_def_id = 0; + var scope = self.parent_scope = null; var tw = new TreeWalker(function(node, descend) { if (node instanceof AST_Catch) { var save_scope = scope; @@ -149,7 +150,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { scope.def_variable(node).defun = defun; } }); - self.next_def_id = 0; + self.make_def = function(orig, init) { + return new SymbolDef(++next_def_id, this, orig, init); + }; self.walk(tw); // pass 2: find back references and eval @@ -240,12 +243,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { } }); -AST_Scope.DEFMETHOD("make_def", function(orig, init) { - var top = this; - while (top.parent_scope) top = top.parent_scope; - return new SymbolDef(++top.next_def_id, this, orig, init); -}); - AST_Toplevel.DEFMETHOD("def_global", function(node) { var globals = this.globals, name = node.name; if (globals.has(name)) { @@ -259,23 +256,28 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) { } }); +function init_scope_vars(scope, parent) { + scope.cname = -1; // the current index for mangling functions/variables + scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes + scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` + scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement + scope.parent_scope = parent; // the parent scope (null if this is the top level) + scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) + scope.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) + if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances +} + AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) { - this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) - this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) - this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement - this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` - this.parent_scope = parent_scope; // the parent scope - this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes - this.cname = -1; // the current index for mangling functions/variables + init_scope_vars(this, parent_scope); }); -AST_Lambda.DEFMETHOD("init_scope_vars", function() { - AST_Scope.prototype.init_scope_vars.apply(this, arguments); +AST_Lambda.DEFMETHOD("init_scope_vars", function(parent_scope) { + init_scope_vars(this, parent_scope); this.uses_arguments = false; this.def_variable(new AST_SymbolFunarg({ name: "arguments", start: this.start, - end: this.end + end: this.end, })); }); @@ -387,18 +389,10 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options) { // labels are always mangleable AST_Label.DEFMETHOD("unmangleable", return_false); -AST_Symbol.DEFMETHOD("unreferenced", function() { - return !this.definition().references.length && !this.scope.pinned(); -}); - AST_Symbol.DEFMETHOD("definition", function() { return this.thedef; }); -AST_Symbol.DEFMETHOD("global", function() { - return this.definition().global; -}); - function _default_mangler_options(options) { options = defaults(options, { eval : false, @@ -558,8 +552,8 @@ AST_Sequence.DEFMETHOD("tail_node", function() { AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { options = _default_mangler_options(options); base54.reset(); + var fn = AST_Symbol.prototype.add_source_map; try { - var fn = AST_Symbol.prototype.add_source_map; AST_Symbol.prototype.add_source_map = function() { if (!this.unmangleable(options)) base54.consider(this.name, -1); }; -- 2.34.1