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) {
|
function best_of(ast1, ast2) {
|
||||||
return ast1.print_to_string({ beautify: false }).length >
|
return ast1.print_to_string().length >
|
||||||
ast2.print_to_string({ beautify: false }).length
|
ast2.print_to_string().length
|
||||||
? ast2 : ast1;
|
? ast2 : ast1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -448,14 +448,12 @@ function Compressor(options, false_by_default) {
|
|||||||
self.operator = "||";
|
self.operator = "||";
|
||||||
self.left = self.left.negate(compressor);
|
self.left = self.left.negate(compressor);
|
||||||
self.right = self.right.negate(compressor);
|
self.right = self.right.negate(compressor);
|
||||||
//return best_of(basic_negation(this), self);
|
return best_of(basic_negation(this), self);
|
||||||
return self;
|
|
||||||
case "||":
|
case "||":
|
||||||
self.operator = "&&";
|
self.operator = "&&";
|
||||||
self.left = self.left.negate(compressor);
|
self.left = self.left.negate(compressor);
|
||||||
self.right = self.right.negate(compressor);
|
self.right = self.right.negate(compressor);
|
||||||
//return best_of(basic_negation(this), self);
|
return best_of(basic_negation(this), self);
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
return basic_negation(this);
|
return basic_negation(this);
|
||||||
});
|
});
|
||||||
@@ -692,18 +690,19 @@ function Compressor(options, false_by_default) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.condition instanceof AST_UnaryPrefix
|
var negated = self.condition.negate(compressor);
|
||||||
&& self.condition.operator == "!") {
|
var negated_is_best = best_of(self.condition, negated) === negated;
|
||||||
self.condition = self.condition.expression;
|
if (self.alternative && negated_is_best) {
|
||||||
|
self.condition = negated;
|
||||||
var tmp = self.body;
|
var tmp = self.body;
|
||||||
self.body = self.alternative || make_node(AST_EmptyStatement, self);
|
self.body = self.alternative || new AST_EmptyStatement();
|
||||||
self.alternative = tmp;
|
self.alternative = tmp;
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_EmptyStatement
|
if (self.body instanceof AST_EmptyStatement
|
||||||
&& self.alternative instanceof AST_EmptyStatement) {
|
&& self.alternative instanceof AST_EmptyStatement) {
|
||||||
return make_node(AST_SimpleStatement, self.condition, {
|
return make_node(AST_SimpleStatement, self.condition, {
|
||||||
body: self.condition
|
body: self.condition
|
||||||
}).optimize(compressor);
|
});
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_SimpleStatement
|
if (self.body instanceof AST_SimpleStatement
|
||||||
&& self.alternative instanceof AST_SimpleStatement) {
|
&& self.alternative instanceof AST_SimpleStatement) {
|
||||||
@@ -718,7 +717,14 @@ function Compressor(options, false_by_default) {
|
|||||||
if ((!self.alternative
|
if ((!self.alternative
|
||||||
|| self.alternative instanceof AST_EmptyStatement)
|
|| self.alternative instanceof AST_EmptyStatement)
|
||||||
&& self.body instanceof AST_SimpleStatement) {
|
&& 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, {
|
body: make_node(AST_Binary, self, {
|
||||||
operator : "&&",
|
operator : "&&",
|
||||||
left : self.condition,
|
left : self.condition,
|
||||||
@@ -843,7 +849,61 @@ function Compressor(options, false_by_default) {
|
|||||||
self = self.clone();
|
self = self.clone();
|
||||||
self.expression = self.expression.squeeze(compressor);
|
self.expression = self.expression.squeeze(compressor);
|
||||||
self.args = do_list(self.args, 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){
|
SQUEEZE(AST_Seq, function(self, compressor){
|
||||||
@@ -914,6 +974,15 @@ function Compressor(options, false_by_default) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Binary.DEFMETHOD("optimize", function(compressor){
|
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) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (this.operator) {
|
||||||
case "&&":
|
case "&&":
|
||||||
var ll = this.left.evaluate(compressor), left = ll[0];
|
var ll = this.left.evaluate(compressor), left = ll[0];
|
||||||
@@ -984,12 +1053,39 @@ function Compressor(options, false_by_default) {
|
|||||||
return self.alternative;
|
return self.alternative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var rev = self.clone();
|
var negated = cond[0].negate(compressor);
|
||||||
rev.condition = cond[0].negate(compressor);
|
if (best_of(cond[0], negated) === negated) {
|
||||||
var tmp = rev.consequent;
|
self = make_node(AST_Conditional, self, {
|
||||||
rev.consequent = rev.alternative;
|
condition: negated,
|
||||||
rev.alternative = tmp;
|
consequent: self.alternative,
|
||||||
return best_of(self, rev);
|
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){
|
SQUEEZE(AST_Array, function(self, compressor){
|
||||||
|
|||||||
@@ -313,6 +313,9 @@ function OutputStream(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||||
|
options = defaults(options, {
|
||||||
|
beautify: false
|
||||||
|
});
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
this.print(s);
|
this.print(s);
|
||||||
return s.get();
|
return s.get();
|
||||||
|
|||||||
@@ -97,9 +97,9 @@ function repeat_string(str, i) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function defaults(args, defs) {
|
function defaults(args, defs) {
|
||||||
var ret = {};
|
|
||||||
if (args === true)
|
if (args === true)
|
||||||
args = {};
|
args = {};
|
||||||
|
var ret = args || {};
|
||||||
for (var i in defs) if (HOP(defs, i)) {
|
for (var i in defs) if (HOP(defs, i)) {
|
||||||
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,3 +72,18 @@ ifs_3_should_warn: {
|
|||||||
var jj; foo(); // 2
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user