From 94e5e00c0321b92aca1abf170c12a02d6c3275b5 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Fri, 23 Jun 2017 20:05:31 +0800 Subject: [PATCH] refactor `compute_char_frequency()` (#2152) - minimise maintenance when updating AST - maximise code sharing between `master` & `harmony` --- lib/output.js | 1 + lib/scope.js | 123 ++++++++++++++++++-------------------------------- 2 files changed, 46 insertions(+), 78 deletions(-) diff --git a/lib/output.js b/lib/output.js index 38f58531..92c72484 100644 --- a/lib/output.js +++ b/lib/output.js @@ -501,6 +501,7 @@ function OutputStream(options) { use_asm = prev_use_asm; } }); + AST_Node.DEFMETHOD("_print", AST_Node.prototype.print); AST_Node.DEFMETHOD("print_to_string", function(options){ var s = OutputStream(options); diff --git a/lib/scope.js b/lib/scope.js index c147ce00..f8ecedb5 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -361,7 +361,8 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){ }); AST_Symbol.DEFMETHOD("unmangleable", function(options){ - return this.definition().unmangleable(options); + var def = this.definition(); + return !def || def.unmangleable(options); }); // labels are always mangleable @@ -460,103 +461,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ options = this._default_mangler_options(options); - var tw = new TreeWalker(function(node){ - if (node instanceof AST_Constant) - base54.consider(node.print_to_string()); - else if (node instanceof AST_Return) - base54.consider("return"); - else if (node instanceof AST_Throw) - base54.consider("throw"); - else if (node instanceof AST_Continue) - base54.consider("continue"); - else if (node instanceof AST_Break) - base54.consider("break"); - else if (node instanceof AST_Debugger) - base54.consider("debugger"); - else if (node instanceof AST_Directive) - base54.consider(node.value); - else if (node instanceof AST_While) - base54.consider("while"); - else if (node instanceof AST_Do) - base54.consider("do while"); - else if (node instanceof AST_If) { - base54.consider("if"); - if (node.alternative) base54.consider("else"); - } - else if (node instanceof AST_Var) - base54.consider("var"); - else if (node instanceof AST_Lambda) - base54.consider("function"); - else if (node instanceof AST_For) - base54.consider("for"); - else if (node instanceof AST_ForIn) - base54.consider("for in"); - else if (node instanceof AST_Switch) - base54.consider("switch"); - else if (node instanceof AST_Case) - base54.consider("case"); - else if (node instanceof AST_Default) - base54.consider("default"); - else if (node instanceof AST_With) - base54.consider("with"); - else if (node instanceof AST_ObjectSetter) - base54.consider("set" + node.key); - else if (node instanceof AST_ObjectGetter) - base54.consider("get" + node.key); - else if (node instanceof AST_ObjectKeyVal) - base54.consider(node.key); - else if (node instanceof AST_New) - base54.consider("new"); - else if (node instanceof AST_This) - base54.consider("this"); - else if (node instanceof AST_Try) - base54.consider("try"); - else if (node instanceof AST_Catch) - base54.consider("catch"); - else if (node instanceof AST_Finally) - base54.consider("finally"); - else if (node instanceof AST_Symbol && node.unmangleable(options)) - base54.consider(node.name); - else if (node instanceof AST_Unary || node instanceof AST_Binary) - base54.consider(node.operator); - else if (node instanceof AST_Dot) - base54.consider(node.property); - }); - this.walk(tw); + try { + AST_Node.prototype.print = function(stream, force_parens) { + this._print(stream, force_parens); + if (this instanceof AST_Symbol && !this.unmangleable(options)) { + base54.consider(this.name, -1); + } else if (options.properties) { + if (this instanceof AST_Dot) { + base54.consider(this.property, -1); + } else if (this instanceof AST_Sub) { + skip_string(this.property); + } + } + }; + base54.consider(this.print_to_string(), 1); + } finally { + AST_Node.prototype.print = AST_Node.prototype._print; + } base54.sort(); + + function skip_string(node) { + if (node instanceof AST_String) { + base54.consider(node.value, -1); + } else if (node instanceof AST_Conditional) { + skip_string(node.consequent); + skip_string(node.alternative); + } else if (node instanceof AST_Sequence) { + skip_string(node.expressions[node.expressions.length - 1]); + } + } }); var base54 = (function() { - var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; + var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split(""); + var digits = "0123456789".split(""); var chars, frequency; function reset() { frequency = Object.create(null); - chars = string.split("").map(function(ch){ return ch.charCodeAt(0) }); - chars.forEach(function(ch){ frequency[ch] = 0 }); + leading.forEach(function(ch) { + frequency[ch] = 0; + }); + digits.forEach(function(ch) { + frequency[ch] = 0; + }); } - base54.consider = function(str){ + base54.consider = function(str, delta) { for (var i = str.length; --i >= 0;) { - var code = str.charCodeAt(i); - if (code in frequency) ++frequency[code]; + frequency[str[i]] += delta; } }; + function compare(a, b) { + return frequency[b] - frequency[a]; + } base54.sort = function() { - chars = mergeSort(chars, function(a, b){ - if (is_digit(a) && !is_digit(b)) return 1; - if (is_digit(b) && !is_digit(a)) return -1; - return frequency[b] - frequency[a]; - }); + chars = mergeSort(leading, compare).concat(mergeSort(digits, compare)); }; base54.reset = reset; reset(); - base54.get = function(){ return chars }; - base54.freq = function(){ return frequency }; function base54(num) { var ret = "", base = 54; num++; do { num--; - ret += String.fromCharCode(chars[num % base]); + ret += chars[num % base]; num = Math.floor(num / base); base = 64; } while (num > 0); -- 2.34.1