minor consolidations (#2484)

- unique symbol generation
- `unsafe` on `AST_Call`
This commit is contained in:
Alex Lam S.L
2017-11-16 04:37:37 +08:00
committed by GitHub
parent fa7a7c5c5a
commit ebe761cad0

View File

@@ -2778,18 +2778,29 @@ merge(Compressor.prototype, {
return self; return self;
}); });
AST_Scope.DEFMETHOD("make_var_name", function(prefix) {
var var_names = this.var_names;
if (!var_names) {
this.var_names = var_names = Object.create(null);
this.enclosed.forEach(function(def) {
var_names[def.name] = true;
});
this.variables.each(function(def, name) {
var_names[name] = true;
});
}
prefix = prefix.replace(/[^a-z_$]+/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
var_names[name] = true;
return name;
});
AST_Scope.DEFMETHOD("hoist_properties", function(compressor){ AST_Scope.DEFMETHOD("hoist_properties", function(compressor){
var self = this; var self = this;
if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self; if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false; var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
var defs_by_id = Object.create(null); var defs_by_id = Object.create(null);
var var_names = Object.create(null);
self.enclosed.forEach(function(def) {
var_names[def.name] = true;
});
self.variables.each(function(def, name) {
var_names[name] = true;
});
return self.transform(new TreeTransformer(function(node) { return self.transform(new TreeTransformer(function(node) {
if (node instanceof AST_VarDef) { if (node instanceof AST_VarDef) {
var sym = node.name, def, value; var sym = node.name, def, value;
@@ -2829,17 +2840,13 @@ merge(Compressor.prototype, {
} }
function make_sym(key) { function make_sym(key) {
var prefix = sym.name + "_" + key.toString().replace(/[^a-z_$]+/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
var new_var = make_node(sym.CTOR, sym, { var new_var = make_node(sym.CTOR, sym, {
name: name, name: self.make_var_name(sym.name + "_" + key),
scope: self scope: self
}); });
var def = self.def_variable(new_var); var def = self.def_variable(new_var);
defs.set(key, def); defs.set(key, def);
self.enclosed.push(def); self.enclosed.push(def);
var_names[name] = true;
return new_var; return new_var;
} }
})); }));
@@ -3408,130 +3415,133 @@ merge(Compressor.prototype, {
self.args.length = last; self.args.length = last;
} }
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp)) { if (is_undeclared_ref(exp)) switch (exp.name) {
switch (exp.name) { case "Array":
case "Array": if (self.args.length != 1) {
if (self.args.length != 1) { return make_node(AST_Array, self, {
return make_node(AST_Array, self, { elements: self.args
elements: self.args
}).optimize(compressor);
}
break;
case "Object":
if (self.args.length == 0) {
return make_node(AST_Object, self, {
properties: []
});
}
break;
case "String":
if (self.args.length == 0) return make_node(AST_String, self, {
value: ""
});
if (self.args.length <= 1) return make_node(AST_Binary, self, {
left: self.args[0],
operator: "+",
right: make_node(AST_String, self, { value: "" })
}).optimize(compressor); }).optimize(compressor);
break;
case "Number":
if (self.args.length == 0) return make_node(AST_Number, self, {
value: 0
});
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "+"
}).optimize(compressor);
case "Boolean":
if (self.args.length == 0) return make_node(AST_False, self);
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "!"
}),
operator: "!"
}).optimize(compressor);
break;
} }
} break;
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { case "Object":
return make_node(AST_Binary, self, { if (self.args.length == 0) {
return make_node(AST_Object, self, {
properties: []
});
}
break;
case "String":
if (self.args.length == 0) return make_node(AST_String, self, {
value: ""
});
if (self.args.length <= 1) return make_node(AST_Binary, self, {
left: self.args[0],
operator: "+",
right: make_node(AST_String, self, { value: "" })
}).optimize(compressor);
break;
case "Number":
if (self.args.length == 0) return make_node(AST_Number, self, {
value: 0
});
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "+"
}).optimize(compressor);
case "Boolean":
if (self.args.length == 0) return make_node(AST_False, self);
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "!"
}),
operator: "!"
}).optimize(compressor);
break;
} else if (exp instanceof AST_Dot) switch(exp.property) {
case "toString":
if (self.args.length == 0) return make_node(AST_Binary, self, {
left: make_node(AST_String, self, { value: "" }), left: make_node(AST_String, self, { value: "" }),
operator: "+", operator: "+",
right: exp.expression right: exp.expression
}).optimize(compressor); }).optimize(compressor);
} break;
else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { case "join":
var separator; if (exp.expression instanceof AST_Array) EXIT: {
if (self.args.length > 0) { var separator;
separator = self.args[0].evaluate(compressor); if (self.args.length > 0) {
if (separator === self.args[0]) break EXIT; // not a constant separator = self.args[0].evaluate(compressor);
} if (separator === self.args[0]) break EXIT; // not a constant
var elements = []; }
var consts = []; var elements = [];
exp.expression.elements.forEach(function(el) { var consts = [];
var value = el.evaluate(compressor); exp.expression.elements.forEach(function(el) {
if (value !== el) { var value = el.evaluate(compressor);
consts.push(value); if (value !== el) {
} else { consts.push(value);
if (consts.length > 0) { } else {
elements.push(make_node(AST_String, self, { if (consts.length > 0) {
value: consts.join(separator) elements.push(make_node(AST_String, self, {
})); value: consts.join(separator)
consts.length = 0; }));
consts.length = 0;
}
elements.push(el);
} }
elements.push(el);
}
});
if (consts.length > 0) {
elements.push(make_node(AST_String, self, {
value: consts.join(separator)
}));
}
if (elements.length == 0) return make_node(AST_String, self, { value: "" });
if (elements.length == 1) {
if (elements[0].is_string(compressor)) {
return elements[0];
}
return make_node(AST_Binary, elements[0], {
operator : "+",
left : make_node(AST_String, self, { value: "" }),
right : elements[0]
}); });
} if (consts.length > 0) {
if (separator == "") { elements.push(make_node(AST_String, self, {
var first; value: consts.join(separator)
if (elements[0].is_string(compressor) }));
|| elements[1].is_string(compressor)) {
first = elements.shift();
} else {
first = make_node(AST_String, self, { value: "" });
} }
return elements.reduce(function(prev, el){ if (elements.length == 0) return make_node(AST_String, self, { value: "" });
return make_node(AST_Binary, el, { if (elements.length == 1) {
if (elements[0].is_string(compressor)) {
return elements[0];
}
return make_node(AST_Binary, elements[0], {
operator : "+", operator : "+",
left : prev, left : make_node(AST_String, self, { value: "" }),
right : el right : elements[0]
}); });
}, first).optimize(compressor); }
if (separator == "") {
var first;
if (elements[0].is_string(compressor)
|| elements[1].is_string(compressor)) {
first = elements.shift();
} else {
first = make_node(AST_String, self, { value: "" });
}
return elements.reduce(function(prev, el){
return make_node(AST_Binary, el, {
operator : "+",
left : prev,
right : el
});
}, first).optimize(compressor);
}
// need this awkward cloning to not affect original element
// best_of will decide which one to get through.
var node = self.clone();
node.expression = node.expression.clone();
node.expression.expression = node.expression.expression.clone();
node.expression.expression.elements = elements;
return best_of(compressor, self, node);
} }
// need this awkward cloning to not affect original element break;
// best_of will decide which one to get through. case "charAt":
var node = self.clone(); if (exp.expression.is_string(compressor)) {
node.expression = node.expression.clone(); var arg = self.args[0];
node.expression.expression = node.expression.expression.clone(); var index = arg ? arg.evaluate(compressor) : 0;
node.expression.expression.elements = elements; if (index !== arg) {
return best_of(compressor, self, node); return make_node(AST_Sub, exp, {
} expression: exp.expression,
else if (exp instanceof AST_Dot && exp.expression.is_string(compressor) && exp.property == "charAt") { property: make_node_from_constant(index | 0, arg || exp)
var arg = self.args[0]; }).optimize(compressor);
var index = arg ? arg.evaluate(compressor) : 0; }
if (index !== arg) {
return make_node(AST_Sub, exp, {
expression: exp.expression,
property: make_node_from_constant(index | 0, arg || exp)
}).optimize(compressor);
} }
break;
} }
} }
if (compressor.option("unsafe_Func") if (compressor.option("unsafe_Func")