more progress on the compressor (WIP)
This commit is contained in:
134
lib/compress.js
134
lib/compress.js
@@ -289,8 +289,8 @@ function Compressor(options, false_by_default) {
|
||||
});
|
||||
|
||||
function best_of(ast1, ast2) {
|
||||
return ast1.print_to_string({ beautify: false }).length >
|
||||
ast2.print_to_string({ beautify: false }).length
|
||||
return ast1.print_to_string().length >
|
||||
ast2.print_to_string().length
|
||||
? ast2 : ast1;
|
||||
};
|
||||
|
||||
@@ -448,14 +448,12 @@ function Compressor(options, false_by_default) {
|
||||
self.operator = "||";
|
||||
self.left = self.left.negate(compressor);
|
||||
self.right = self.right.negate(compressor);
|
||||
//return best_of(basic_negation(this), self);
|
||||
return self;
|
||||
return best_of(basic_negation(this), self);
|
||||
case "||":
|
||||
self.operator = "&&";
|
||||
self.left = self.left.negate(compressor);
|
||||
self.right = self.right.negate(compressor);
|
||||
//return best_of(basic_negation(this), self);
|
||||
return self;
|
||||
return best_of(basic_negation(this), self);
|
||||
}
|
||||
return basic_negation(this);
|
||||
});
|
||||
@@ -692,18 +690,19 @@ function Compressor(options, false_by_default) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self.condition instanceof AST_UnaryPrefix
|
||||
&& self.condition.operator == "!") {
|
||||
self.condition = self.condition.expression;
|
||||
var negated = self.condition.negate(compressor);
|
||||
var negated_is_best = best_of(self.condition, negated) === negated;
|
||||
if (self.alternative && negated_is_best) {
|
||||
self.condition = negated;
|
||||
var tmp = self.body;
|
||||
self.body = self.alternative || make_node(AST_EmptyStatement, self);
|
||||
self.body = self.alternative || new AST_EmptyStatement();
|
||||
self.alternative = tmp;
|
||||
}
|
||||
if (self.body instanceof AST_EmptyStatement
|
||||
&& self.alternative instanceof AST_EmptyStatement) {
|
||||
return make_node(AST_SimpleStatement, self.condition, {
|
||||
body: self.condition
|
||||
}).optimize(compressor);
|
||||
});
|
||||
}
|
||||
if (self.body instanceof AST_SimpleStatement
|
||||
&& self.alternative instanceof AST_SimpleStatement) {
|
||||
@@ -718,7 +717,14 @@ function Compressor(options, false_by_default) {
|
||||
if ((!self.alternative
|
||||
|| self.alternative instanceof AST_EmptyStatement)
|
||||
&& self.body instanceof AST_SimpleStatement) {
|
||||
return make_node(AST_SimpleStatement, self, {
|
||||
if (negated_is_best) return make_node(AST_SimpleStatement, self, {
|
||||
body: make_node(AST_Binary, self, {
|
||||
operator : "||",
|
||||
left : negated,
|
||||
right : self.body.body
|
||||
}).optimize(compressor)
|
||||
});
|
||||
else return make_node(AST_SimpleStatement, self, {
|
||||
body: make_node(AST_Binary, self, {
|
||||
operator : "&&",
|
||||
left : self.condition,
|
||||
@@ -843,7 +849,61 @@ function Compressor(options, false_by_default) {
|
||||
self = self.clone();
|
||||
self.expression = self.expression.squeeze(compressor);
|
||||
self.args = do_list(self.args, compressor);
|
||||
return self;
|
||||
return self.optimize(compressor);
|
||||
});
|
||||
|
||||
AST_Call.DEFMETHOD("optimize", function(compressor){
|
||||
if (compressor.option("unsafe")) {
|
||||
var exp = this.expression;
|
||||
if (exp instanceof AST_SymbolRef && exp.undeclared) {
|
||||
switch (exp.name) {
|
||||
case "Array":
|
||||
if (this.args.length != 1) {
|
||||
return make_node(AST_Array, this, {
|
||||
elements: this.args
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
case "Object":
|
||||
if (this.args.length == 0) {
|
||||
return make_node(AST_Object, this, {
|
||||
properties: []
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
case "String":
|
||||
return make_node(AST_Binary, this, {
|
||||
left: this.args[0],
|
||||
operator: "+",
|
||||
right: make_node(AST_String, this, { value: "" })
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (exp instanceof AST_Dot && exp.property == "toString" && this.args.length == 0) {
|
||||
return make_node(AST_Binary, this, {
|
||||
left: exp.expression,
|
||||
operator: "+",
|
||||
right: make_node(AST_String, this, { value: "" })
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
AST_New.DEFMETHOD("optimize", function(compressor){
|
||||
if (compressor.option("unsafe")) {
|
||||
var exp = this.expression;
|
||||
if (exp instanceof AST_SymbolRef && exp.undeclared) {
|
||||
switch (exp.name) {
|
||||
case "Object":
|
||||
case "RegExp":
|
||||
case "Function":
|
||||
case "Error":
|
||||
case "Array":
|
||||
return make_node(AST_Call, this, this).optimize(compressor);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SQUEEZE(AST_Seq, function(self, compressor){
|
||||
@@ -914,6 +974,15 @@ function Compressor(options, false_by_default) {
|
||||
});
|
||||
|
||||
AST_Binary.DEFMETHOD("optimize", function(compressor){
|
||||
if (compressor.option("comparations")) switch (this.operator) {
|
||||
case "===":
|
||||
case "!==":
|
||||
if ((this.left.is_string() && this.right.is_string()) ||
|
||||
(this.left.is_boolean() && this.right.is_boolean())) {
|
||||
this.operator = this.operator.substr(0, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (this.operator) {
|
||||
case "&&":
|
||||
var ll = this.left.evaluate(compressor), left = ll[0];
|
||||
@@ -984,12 +1053,39 @@ function Compressor(options, false_by_default) {
|
||||
return self.alternative;
|
||||
}
|
||||
}
|
||||
var rev = self.clone();
|
||||
rev.condition = cond[0].negate(compressor);
|
||||
var tmp = rev.consequent;
|
||||
rev.consequent = rev.alternative;
|
||||
rev.alternative = tmp;
|
||||
return best_of(self, rev);
|
||||
var negated = cond[0].negate(compressor);
|
||||
if (best_of(cond[0], negated) === negated) {
|
||||
self = make_node(AST_Conditional, self, {
|
||||
condition: negated,
|
||||
consequent: self.alternative,
|
||||
alternative: self.consequent
|
||||
});
|
||||
}
|
||||
var consequent = self.consequent;
|
||||
var alternative = self.alternative;
|
||||
if (consequent instanceof AST_Assign
|
||||
&& alternative instanceof AST_Assign
|
||||
&& consequent.operator == alternative.operator
|
||||
// XXX: this is a rather expensive way to test two node's equivalence:
|
||||
&& consequent.left.print_to_string() == alternative.left.print_to_string()
|
||||
) {
|
||||
/*
|
||||
* Stuff like this:
|
||||
* if (foo) exp = something; else exp = something_else;
|
||||
* ==>
|
||||
* exp = foo ? something : something_else;
|
||||
*/
|
||||
self = make_node(AST_Assign, self, {
|
||||
operator: consequent.operator,
|
||||
left: consequent.left,
|
||||
right: make_node(AST_Conditional, self, {
|
||||
condition: self.condition,
|
||||
consequent: consequent.right,
|
||||
alternative: alternative.right
|
||||
})
|
||||
});
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
SQUEEZE(AST_Array, function(self, compressor){
|
||||
|
||||
Reference in New Issue
Block a user