aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js134
-rw-r--r--lib/output.js3
-rw-r--r--lib/utils.js2
-rw-r--r--test/compress/conditionals.js15
4 files changed, 134 insertions, 20 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 3ce06298..e615699c 100644
--- a/lib/compress.js
+++ b/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){
diff --git a/lib/output.js b/lib/output.js
index c803fbae..35c7ade7 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -313,6 +313,9 @@ function OutputStream(options) {
};
AST_Node.DEFMETHOD("print_to_string", function(options){
+ options = defaults(options, {
+ beautify: false
+ });
var s = OutputStream(options);
this.print(s);
return s.get();
diff --git a/lib/utils.js b/lib/utils.js
index 519e6962..79e612c6 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -97,9 +97,9 @@ function repeat_string(str, i) {
};
function defaults(args, defs) {
- var ret = {};
if (args === true)
args = {};
+ var ret = args || {};
for (var i in defs) if (HOP(defs, i)) {
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
}
diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js
index ba5e674d..b9c348a0 100644
--- a/test/compress/conditionals.js
+++ b/test/compress/conditionals.js
@@ -72,3 +72,18 @@ ifs_3_should_warn: {
var jj; foo(); // 2
}
}
+
+ifs_4: {
+ options = {
+ conditionals: true
+ };
+ input: {
+ if (foo && bar) {
+ x(foo)[10].bar.baz = something();
+ } else
+ x(foo)[10].bar.baz = something_else();
+ }
+ expect: {
+ x(foo)[10].bar.baz = (foo && bar) ? something() : something_else();
+ }
+}