support for hoisting declarations

and finally it seems we beat v1 in terms of compression
This commit is contained in:
Mihai Bazon
2012-09-05 13:43:34 +03:00
parent 8633b0073f
commit 0503513dcc

View File

@@ -64,7 +64,8 @@ function Compressor(options, false_by_default) {
evaluate : !false_by_default, evaluate : !false_by_default,
booleans : !false_by_default, booleans : !false_by_default,
dwloops : !false_by_default, dwloops : !false_by_default,
hoist : !false_by_default, hoist_funs : !false_by_default,
hoist_vars : !false_by_default,
warnings : true warnings : true
}); });
@@ -102,7 +103,7 @@ function Compressor(options, false_by_default) {
}; };
}; };
(function(){ (function(undefined){
AST_Node.DEFMETHOD("squeeze", function(){ AST_Node.DEFMETHOD("squeeze", function(){
return this; return this;
@@ -124,7 +125,7 @@ function Compressor(options, false_by_default) {
compressor.push_node(this); compressor.push_node(this);
var new_node = squeeze(this, compressor); var new_node = squeeze(this, compressor);
compressor.pop_node(); compressor.pop_node();
return new_node || this; return new_node !== undefined ? new_node : this;
}); });
}; };
@@ -148,12 +149,9 @@ function Compressor(options, false_by_default) {
function eliminate_spurious_blocks(statements) { function eliminate_spurious_blocks(statements) {
return statements.reduce(function(a, stat){ return statements.reduce(function(a, stat){
if (stat.TYPE == "BlockStatement") { if (stat instanceof AST_BlockStatement) {
// XXX: no instanceof here because we would catch
// AST_Lambda-s and other blocks too. perhaps we
// should refine the hierarchy.
a.push.apply(a, stat.body); a.push.apply(a, stat.body);
} else { } else if (!(stat instanceof AST_EmptyStatement)) {
a.push(stat); a.push(stat);
} }
return a; return a;
@@ -494,7 +492,49 @@ function Compressor(options, false_by_default) {
}); });
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
if (compressor.option("hoist")) { var hoist_funs = compressor.option("hoist_funs");
var hoist_vars = compressor.option("hoist_vars");
if (hoist_funs || hoist_vars) {
var self = this;
var hoisted = [];
var defuns = {};
var vars = {}, vars_found = 0;
var tw = new TreeWalker(function(node){
if (node !== self) {
if (node instanceof AST_Defun && hoist_funs) {
hoisted.push(node.clone());
node.hoisted = true;
defuns[node.name.name] = true;
}
if (node instanceof AST_Var && hoist_vars) {
node.definitions.forEach(function(def){
vars[def.name.name] = def;
++vars_found;
});
node.hoisted = true;
}
if (node instanceof AST_Scope)
return true;
}
});
self.walk(tw);
if (vars_found > 0) {
if (self instanceof AST_Lambda && !self.uses_arguments) {
for (var i in vars) if (HOP(vars, i)) {
self.argnames.push(vars[i].name);
}
} else {
var node = make_node(AST_Var, self, {
definitions: Object.keys(vars).map(function(name){
var def = vars[name].clone();
def.value = null;
return def;
})
});
hoisted.unshift(node);
}
}
self.body = hoisted.concat(self.body);
} }
}); });
@@ -665,13 +705,49 @@ function Compressor(options, false_by_default) {
AST_Definitions.DEFMETHOD("remove_initializers", function(){ AST_Definitions.DEFMETHOD("remove_initializers", function(){
this.definitions = this.definitions.map(function(def){ this.definitions = this.definitions.map(function(def){
var def = def.clone(); def = def.clone();
def.value = null; def.value = null;
return def; return def;
}); });
}); });
AST_Definitions.DEFMETHOD("to_assignments", function(){
var assignments = this.definitions.reduce(function(a, def){
if (def.value) {
a.push(make_node(AST_Assign, def, {
operator : "=",
left : def.name,
right : def.value
}));
}
return a;
}, []);
if (assignments.length == 0) return null;
return (function seq(list){
var first = list[0];
if (list.length == 1) return first;
return make_node(AST_Seq, first, {
first: first,
second: seq(list.slice(1))
});
})(assignments);
});
SQUEEZE(AST_Definitions, function(self, compressor){ SQUEEZE(AST_Definitions, function(self, compressor){
if (self.hoisted) {
var seq = self.to_assignments();
var p = compressor.parent();
if (seq) seq = seq.squeeze(compressor);
if (p instanceof AST_ForIn && p.init === self) {
if (seq == null) return self.definitions[0].name; //XXX: is this fine?
return seq;
}
if (p instanceof AST_For && p.init === self) {
return seq;
}
if (!seq) return make_node(AST_EmptyStatement, self);
return make_node(AST_SimpleStatement, self, { body: seq });
}
self = self.clone(); self = self.clone();
self.definitions = do_list(self.definitions, compressor); self.definitions = do_list(self.definitions, compressor);
return self; return self;
@@ -684,10 +760,11 @@ function Compressor(options, false_by_default) {
}); });
SQUEEZE(AST_Lambda, function(self, compressor){ SQUEEZE(AST_Lambda, function(self, compressor){
if (self.hoisted) return make_node(AST_EmptyStatement, self);
self = self.clone(); self = self.clone();
self.hoist_declarations(compressor);
if (self.name) self.name = self.name.squeeze(compressor); if (self.name) self.name = self.name.squeeze(compressor);
self.argnames = do_list(self.argnames, compressor); self.argnames = do_list(self.argnames, compressor);
self.hoist_declarations(compressor);
self.body = tighten_body(self.body, compressor); self.body = tighten_body(self.body, compressor);
return self; return self;
}); });