Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf409800be | ||
|
|
18270dd9f3 | ||
|
|
d4c25c571b | ||
|
|
5248b79506 | ||
|
|
abe0ebbf02 | ||
|
|
0852f5595e | ||
|
|
cb3cafa14d | ||
|
|
202fb93799 | ||
|
|
7b87d2ef83 | ||
|
|
70fd2b1f33 | ||
|
|
30faaf13ed |
12
lib/ast.js
12
lib/ast.js
@@ -581,6 +581,18 @@ var AST_Seq = DEFNODE("Seq", "car cdr", {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
},
|
},
|
||||||
|
to_array: function() {
|
||||||
|
var p = this, a = [];
|
||||||
|
while (p) {
|
||||||
|
a.push(p.car);
|
||||||
|
if (p.cdr && !(p.cdr instanceof AST_Seq)) {
|
||||||
|
a.push(p.cdr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = p.cdr;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
},
|
||||||
add: function(node) {
|
add: function(node) {
|
||||||
var p = this;
|
var p = this;
|
||||||
while (p) {
|
while (p) {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ function Compressor(options, false_by_default) {
|
|||||||
dead_code : !false_by_default,
|
dead_code : !false_by_default,
|
||||||
drop_debugger : !false_by_default,
|
drop_debugger : !false_by_default,
|
||||||
unsafe : !false_by_default,
|
unsafe : !false_by_default,
|
||||||
|
unsafe_comps : false,
|
||||||
conditionals : !false_by_default,
|
conditionals : !false_by_default,
|
||||||
comparisons : !false_by_default,
|
comparisons : !false_by_default,
|
||||||
evaluate : !false_by_default,
|
evaluate : !false_by_default,
|
||||||
@@ -427,13 +428,24 @@ merge(Compressor.prototype, {
|
|||||||
var ret = [], prev = null;
|
var ret = [], prev = null;
|
||||||
statements.forEach(function(stat){
|
statements.forEach(function(stat){
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (stat instanceof AST_For && stat.init && !(stat.init instanceof AST_Definitions)) {
|
if (stat instanceof AST_For) {
|
||||||
|
var opera = {};
|
||||||
|
try {
|
||||||
|
prev.body.walk(new TreeWalker(function(node){
|
||||||
|
if (node instanceof AST_Binary && node.operator == "in")
|
||||||
|
throw opera;
|
||||||
|
}));
|
||||||
|
if (stat.init && !(stat.init instanceof AST_Definitions)) {
|
||||||
stat.init = cons_seq(stat.init);
|
stat.init = cons_seq(stat.init);
|
||||||
}
|
}
|
||||||
else if (stat instanceof AST_For && !stat.init) {
|
else if (!stat.init) {
|
||||||
stat.init = prev.body;
|
stat.init = prev.body;
|
||||||
ret.pop();
|
ret.pop();
|
||||||
}
|
}
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex !== opera) throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (stat instanceof AST_If) {
|
else if (stat instanceof AST_If) {
|
||||||
stat.condition = cons_seq(stat.condition);
|
stat.condition = cons_seq(stat.condition);
|
||||||
}
|
}
|
||||||
@@ -692,7 +704,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor){
|
def(AST_Binary, function(compressor){
|
||||||
var self = this.clone(), op = this.operator;
|
var self = this.clone(), op = this.operator;
|
||||||
if (compressor.option("comparisons") && compressor.option("unsafe")) {
|
if (compressor.option("unsafe_comps")) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case "<=" : self.operator = ">" ; return self;
|
case "<=" : self.operator = ">" ; return self;
|
||||||
case "<" : self.operator = ">=" ; return self;
|
case "<" : self.operator = ">=" ; return self;
|
||||||
@@ -1220,8 +1232,8 @@ merge(Compressor.prototype, {
|
|||||||
return make_node(self.body.CTOR, self, {
|
return make_node(self.body.CTOR, self, {
|
||||||
value: make_node(AST_Conditional, self, {
|
value: make_node(AST_Conditional, self, {
|
||||||
condition : self.condition,
|
condition : self.condition,
|
||||||
consequent : self.body.value,
|
consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
|
||||||
alternative : self.alternative.value || make_node(AST_Undefined, self).optimize(compressor)
|
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
|
||||||
})
|
})
|
||||||
}).transform(compressor);
|
}).transform(compressor);
|
||||||
}
|
}
|
||||||
@@ -1380,6 +1392,10 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Seq, function(self, compressor){
|
OPT(AST_Seq, function(self, compressor){
|
||||||
|
if (!compressor.option("side_effects"))
|
||||||
|
return self;
|
||||||
|
if (!self.car.has_side_effects())
|
||||||
|
return self.cdr;
|
||||||
if (compressor.option("cascade")) {
|
if (compressor.option("cascade")) {
|
||||||
if (self.car instanceof AST_Assign
|
if (self.car instanceof AST_Assign
|
||||||
&& !self.car.left.has_side_effects()
|
&& !self.car.left.has_side_effects()
|
||||||
@@ -1395,7 +1411,26 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
|
||||||
|
if (compressor.option("sequences")) {
|
||||||
|
if (this.expression instanceof AST_Seq) {
|
||||||
|
var seq = this.expression;
|
||||||
|
var x = seq.to_array();
|
||||||
|
this.expression = x.pop();
|
||||||
|
x.push(this);
|
||||||
|
seq = AST_Seq.from_array(x).transform(compressor);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
|
OPT(AST_UnaryPostfix, function(self, compressor){
|
||||||
|
return self.lift_sequences(compressor);
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_UnaryPrefix, function(self, compressor){
|
OPT(AST_UnaryPrefix, function(self, compressor){
|
||||||
|
self = self.lift_sequences(compressor);
|
||||||
var e = self.expression;
|
var e = self.expression;
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||||
switch (self.operator) {
|
switch (self.operator) {
|
||||||
@@ -1411,14 +1446,39 @@ merge(Compressor.prototype, {
|
|||||||
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_True, self);
|
return make_node(AST_True, self);
|
||||||
}
|
}
|
||||||
}
|
if (e instanceof AST_Binary && self.operator == "!") {
|
||||||
if (e instanceof AST_Binary) {
|
|
||||||
self = best_of(self, e.negate(compressor));
|
self = best_of(self, e.negate(compressor));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return self.evaluate(compressor)[0];
|
return self.evaluate(compressor)[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
|
||||||
|
if (compressor.option("sequences")) {
|
||||||
|
if (this.left instanceof AST_Seq) {
|
||||||
|
var seq = this.left;
|
||||||
|
var x = seq.to_array();
|
||||||
|
this.left = x.pop();
|
||||||
|
x.push(this);
|
||||||
|
seq = AST_Seq.from_array(x).transform(compressor);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
if (this.right instanceof AST_Seq
|
||||||
|
&& !(this.operator == "||" || this.operator == "&&")
|
||||||
|
&& !this.left.has_side_effects()) {
|
||||||
|
var seq = this.right;
|
||||||
|
var x = seq.to_array();
|
||||||
|
this.right = x.pop();
|
||||||
|
x.push(this);
|
||||||
|
seq = AST_Seq.from_array(x).transform(compressor);
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor){
|
OPT(AST_Binary, function(self, compressor){
|
||||||
|
self = self.lift_sequences(compressor);
|
||||||
if (compressor.option("comparisons")) switch (self.operator) {
|
if (compressor.option("comparisons")) switch (self.operator) {
|
||||||
case "===":
|
case "===":
|
||||||
case "!==":
|
case "!==":
|
||||||
@@ -1557,6 +1617,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||||
OPT(AST_Assign, function(self, compressor){
|
OPT(AST_Assign, function(self, compressor){
|
||||||
|
self = self.lift_sequences(compressor);
|
||||||
if (self.operator == "="
|
if (self.operator == "="
|
||||||
&& self.left instanceof AST_SymbolRef
|
&& self.left instanceof AST_SymbolRef
|
||||||
&& self.right instanceof AST_Binary
|
&& self.right instanceof AST_Binary
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
||||||
|| p instanceof AST_Unary // !(foo, bar, baz)
|
|| p instanceof AST_Unary // !(foo, bar, baz)
|
||||||
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 7
|
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|
||||||
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
||||||
|| p instanceof AST_Dot // (1, {foo:2}).foo ==> 2
|
|| p instanceof AST_Dot // (1, {foo:2}).foo ==> 2
|
||||||
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||||
|
|||||||
@@ -115,7 +115,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
node.init_scope_vars();
|
node.init_scope_vars();
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolLambda) {
|
||||||
scope.def_function(node);
|
//scope.def_function(node);
|
||||||
|
//
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/24 — MSIE
|
||||||
|
// leaks function expression names into the containing
|
||||||
|
// scope. Don't like this fix but seems we can't do any
|
||||||
|
// better. IE: please die. Please!
|
||||||
|
(node.scope = scope.parent_scope).def_function(node);
|
||||||
|
|
||||||
node.init.push(tw.parent());
|
node.init.push(tw.parent());
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolDefun) {
|
else if (node instanceof AST_SymbolDefun) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"main": "tools/node.js",
|
"main": "tools/node.js",
|
||||||
"version": "2.1.2",
|
"version": "2.1.5",
|
||||||
"engines": { "node" : ">=0.4.0" },
|
"engines": { "node" : ">=0.4.0" },
|
||||||
"maintainers": [{
|
"maintainers": [{
|
||||||
"name": "Mihai Bazon",
|
"name": "Mihai Bazon",
|
||||||
|
|||||||
17
test/compress/issue-22.js
Normal file
17
test/compress/issue-22.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
return_with_no_value_in_if_body: {
|
||||||
|
options = { conditionals: true };
|
||||||
|
input: {
|
||||||
|
function foo(bar) {
|
||||||
|
if (bar) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo (bar) {
|
||||||
|
return bar ? void 0 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,3 +87,75 @@ make_sequences_4: {
|
|||||||
with (x = 5, obj);
|
with (x = 5, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lift_sequences_1: {
|
||||||
|
options = { sequences: true };
|
||||||
|
input: {
|
||||||
|
foo = !(x(), y(), bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x(), y(), foo = !bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lift_sequences_2: {
|
||||||
|
options = { sequences: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
q = 1 + (foo(), bar(), 5) + 7 * (5 / (3 - (a(), (QW=ER), c(), 2))) - (x(), y(), 5);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
foo(), bar(), a(), QW = ER, c(), x(), y(), q = 36
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lift_sequences_3: {
|
||||||
|
options = { sequences: true, conditionals: true };
|
||||||
|
input: {
|
||||||
|
x = (foo(), bar(), baz()) ? 10 : 20;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
foo(), bar(), x = baz() ? 10 : 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lift_sequences_4: {
|
||||||
|
options = { side_effects: true };
|
||||||
|
input: {
|
||||||
|
x = (foo, bar, baz);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x = baz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_sequences: {
|
||||||
|
options = { sequences: true };
|
||||||
|
input: {
|
||||||
|
// 1
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
for (; false;);
|
||||||
|
// 2
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
for (x = 5; false;);
|
||||||
|
// 3
|
||||||
|
x = (foo in bar);
|
||||||
|
for (; false;);
|
||||||
|
// 4
|
||||||
|
x = (foo in bar);
|
||||||
|
for (y = 5; false;);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
// 1
|
||||||
|
for (foo(), bar(); false;);
|
||||||
|
// 2
|
||||||
|
for (foo(), bar(), x = 5; false;);
|
||||||
|
// 3
|
||||||
|
x = (foo in bar);
|
||||||
|
for (; false;);
|
||||||
|
// 4
|
||||||
|
x = (foo in bar);
|
||||||
|
for (y = 5; false;);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ var fs = require("fs");
|
|||||||
// but by the time you can set that the `path` module is already
|
// but by the time you can set that the `path` module is already
|
||||||
// loaded and `path.existsSync` is already changed to display that
|
// loaded and `path.existsSync` is already changed to display that
|
||||||
// warning, therefore here's the poor solution:
|
// warning, therefore here's the poor solution:
|
||||||
path.existsSync = fs.existsSync;
|
if (fs.existsSync) {
|
||||||
|
path.existsSync = fs.existsSync;
|
||||||
|
}
|
||||||
|
|
||||||
var vm = require("vm");
|
var vm = require("vm");
|
||||||
var sys = require("util");
|
var sys = require("util");
|
||||||
|
|||||||
Reference in New Issue
Block a user