refactor compute_char_frequency() (#2152)

- minimise maintenance when updating AST
- maximise code sharing between `master` & `harmony`
This commit is contained in:
Alex Lam S.L
2017-06-23 20:05:31 +08:00
committed by GitHub
parent dc6bcaa18e
commit 94e5e00c03
2 changed files with 46 additions and 78 deletions

View File

@@ -501,6 +501,7 @@ function OutputStream(options) {
use_asm = prev_use_asm; use_asm = prev_use_asm;
} }
}); });
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
AST_Node.DEFMETHOD("print_to_string", function(options){ AST_Node.DEFMETHOD("print_to_string", function(options){
var s = OutputStream(options); var s = OutputStream(options);

View File

@@ -361,7 +361,8 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
}); });
AST_Symbol.DEFMETHOD("unmangleable", function(options){ AST_Symbol.DEFMETHOD("unmangleable", function(options){
return this.definition().unmangleable(options); var def = this.definition();
return !def || def.unmangleable(options);
}); });
// labels are always mangleable // labels are always mangleable
@@ -460,103 +461,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
options = this._default_mangler_options(options); options = this._default_mangler_options(options);
var tw = new TreeWalker(function(node){ try {
if (node instanceof AST_Constant) AST_Node.prototype.print = function(stream, force_parens) {
base54.consider(node.print_to_string()); this._print(stream, force_parens);
else if (node instanceof AST_Return) if (this instanceof AST_Symbol && !this.unmangleable(options)) {
base54.consider("return"); base54.consider(this.name, -1);
else if (node instanceof AST_Throw) } else if (options.properties) {
base54.consider("throw"); if (this instanceof AST_Dot) {
else if (node instanceof AST_Continue) base54.consider(this.property, -1);
base54.consider("continue"); } else if (this instanceof AST_Sub) {
else if (node instanceof AST_Break) skip_string(this.property);
base54.consider("break"); }
else if (node instanceof AST_Debugger) }
base54.consider("debugger"); };
else if (node instanceof AST_Directive) base54.consider(this.print_to_string(), 1);
base54.consider(node.value); } finally {
else if (node instanceof AST_While) AST_Node.prototype.print = AST_Node.prototype._print;
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);
base54.sort(); 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 base54 = (function() {
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
var digits = "0123456789".split("");
var chars, frequency; var chars, frequency;
function reset() { function reset() {
frequency = Object.create(null); frequency = Object.create(null);
chars = string.split("").map(function(ch){ return ch.charCodeAt(0) }); leading.forEach(function(ch) {
chars.forEach(function(ch){ frequency[ch] = 0 }); 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;) { for (var i = str.length; --i >= 0;) {
var code = str.charCodeAt(i); frequency[str[i]] += delta;
if (code in frequency) ++frequency[code];
} }
}; };
function compare(a, b) {
return frequency[b] - frequency[a];
}
base54.sort = function() { base54.sort = function() {
chars = mergeSort(chars, function(a, b){ chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
if (is_digit(a) && !is_digit(b)) return 1;
if (is_digit(b) && !is_digit(a)) return -1;
return frequency[b] - frequency[a];
});
}; };
base54.reset = reset; base54.reset = reset;
reset(); reset();
base54.get = function(){ return chars };
base54.freq = function(){ return frequency };
function base54(num) { function base54(num) {
var ret = "", base = 54; var ret = "", base = 54;
num++; num++;
do { do {
num--; num--;
ret += String.fromCharCode(chars[num % base]); ret += chars[num % base];
num = Math.floor(num / base); num = Math.floor(num / base);
base = 64; base = 64;
} while (num > 0); } while (num > 0);