aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMihai Bazon <mihai@bazon.net>2012-09-05 13:43:34 +0300
committerMihai Bazon <mihai@bazon.net>2012-09-05 13:43:34 +0300
commit0503513dcc9e4dc9f01ffc894245076de9f48cb0 (patch)
tree2d92ef300f08694d82a844802fe4308272b91c2a
parent8633b0073f016fddd655ae5e1f1726287a24828d (diff)
downloadtracifyjs-0503513dcc9e4dc9f01ffc894245076de9f48cb0.tar.gz
tracifyjs-0503513dcc9e4dc9f01ffc894245076de9f48cb0.zip
support for hoisting declarations
and finally it seems we beat v1 in terms of compression
-rw-r--r--lib/compress.js99
1 files changed, 88 insertions, 11 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 71b20edb..3d2f5404 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -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;
});