support for hoisting declarations
and finally it seems we beat v1 in terms of compression
This commit is contained in:
@@ -64,7 +64,8 @@ function Compressor(options, false_by_default) {
|
||||
evaluate : !false_by_default,
|
||||
booleans : !false_by_default,
|
||||
dwloops : !false_by_default,
|
||||
hoist : !false_by_default,
|
||||
hoist_funs : !false_by_default,
|
||||
hoist_vars : !false_by_default,
|
||||
|
||||
warnings : true
|
||||
});
|
||||
@@ -102,7 +103,7 @@ function Compressor(options, false_by_default) {
|
||||
};
|
||||
};
|
||||
|
||||
(function(){
|
||||
(function(undefined){
|
||||
|
||||
AST_Node.DEFMETHOD("squeeze", function(){
|
||||
return this;
|
||||
@@ -124,7 +125,7 @@ function Compressor(options, false_by_default) {
|
||||
compressor.push_node(this);
|
||||
var new_node = squeeze(this, compressor);
|
||||
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) {
|
||||
return statements.reduce(function(a, stat){
|
||||
if (stat.TYPE == "BlockStatement") {
|
||||
// XXX: no instanceof here because we would catch
|
||||
// AST_Lambda-s and other blocks too. perhaps we
|
||||
// should refine the hierarchy.
|
||||
if (stat instanceof AST_BlockStatement) {
|
||||
a.push.apply(a, stat.body);
|
||||
} else {
|
||||
} else if (!(stat instanceof AST_EmptyStatement)) {
|
||||
a.push(stat);
|
||||
}
|
||||
return a;
|
||||
@@ -494,7 +492,49 @@ function Compressor(options, false_by_default) {
|
||||
});
|
||||
|
||||
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(){
|
||||
this.definitions = this.definitions.map(function(def){
|
||||
var def = def.clone();
|
||||
def = def.clone();
|
||||
def.value = null;
|
||||
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){
|
||||
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.definitions = do_list(self.definitions, compressor);
|
||||
return self;
|
||||
@@ -684,10 +760,11 @@ function Compressor(options, false_by_default) {
|
||||
});
|
||||
|
||||
SQUEEZE(AST_Lambda, function(self, compressor){
|
||||
if (self.hoisted) return make_node(AST_EmptyStatement, self);
|
||||
self = self.clone();
|
||||
self.hoist_declarations(compressor);
|
||||
if (self.name) self.name = self.name.squeeze(compressor);
|
||||
self.argnames = do_list(self.argnames, compressor);
|
||||
self.hoist_declarations(compressor);
|
||||
self.body = tighten_body(self.body, compressor);
|
||||
return self;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user