Compare commits

...

12 Commits

Author SHA1 Message Date
Mihai Bazon
6064bea3db v2.2.2 2012-12-06 14:25:18 +02:00
Mihai Bazon
98978fc827 Add proper parens in "NoIn" expressions.
fix #60.
2012-12-06 12:27:57 +02:00
Mihai Bazon
16430acc1f small improvement on merging assignments into hoisted vars 2012-12-05 13:14:49 +02:00
Mihai Bazon
320c110b33 When hoisting variables, try to merge in assignments that follow. 2012-12-05 12:30:25 +02:00
Mihai Bazon
dbe33bbfc5 Revert "Fixed reading from STDIN."
It breaks usage like this:

    echo '...code...' | uglifyjs

This reverts commit e48802ad29.
2012-11-30 11:33:50 +02:00
Mihai Bazon
b5c3253b49 Add test for issue #59 2012-11-30 11:26:37 +02:00
Mihai Bazon
5cc90db7d0 Don't messup compressor stack while optimizing Switch
Fix #59
2012-11-30 11:16:09 +02:00
Mihai Bazon
f427e5efc7 Merge pull request #58 from roxeteer/master
Fixed reading from STDIN
2012-11-29 01:23:07 -08:00
Visa Kopu
e48802ad29 Fixed reading from STDIN. 2012-11-29 10:51:15 +02:00
Mihai Bazon
13c4dfcabd fix #55 2012-11-24 10:02:08 +02:00
Mihai Bazon
1abde9c8b0 v2.2.1 2012-11-23 10:25:44 +02:00
Mihai Bazon
4f555e2232 fix for https://github.com/mishoo/UglifyJS/issues/474 2012-11-23 10:20:00 +02:00
7 changed files with 149 additions and 49 deletions

View File

@@ -287,9 +287,9 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
}, },
wrap_commonjs: function(name, export_all) { wrap_commonjs: function(name, export_all) {
var self = this; var self = this;
var to_export = [];
if (export_all) { if (export_all) {
self.figure_out_scope(); self.figure_out_scope();
var to_export = [];
self.walk(new TreeWalker(function(node){ self.walk(new TreeWalker(function(node){
if (node instanceof AST_SymbolDeclaration && node.definition().global) { if (node instanceof AST_SymbolDeclaration && node.definition().global) {
if (!find_if(function(n){ return n.name == node.name }, to_export)) if (!find_if(function(n){ return n.name == node.name }, to_export))

View File

@@ -883,19 +883,24 @@ merge(Compressor.prototype, {
&& !self.uses_eval && !self.uses_eval
) { ) {
var in_use = []; var in_use = [];
var initializations = new Dictionary();
// pass 1: find out which symbols are directly used in // pass 1: find out which symbols are directly used in
// this scope (not in nested scopes). // this scope (not in nested scopes).
var scope = this; var scope = this;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (node !== self) { if (node !== self) {
if (node instanceof AST_Defun) { if (node instanceof AST_Defun) {
initializations.add(node.name.name, node);
return true; // don't go in nested scopes return true; // don't go in nested scopes
} }
if (node instanceof AST_Definitions && scope === self) { if (node instanceof AST_Definitions && scope === self) {
node.definitions.forEach(function(def){ node.definitions.forEach(function(def){
if (def.value && def.value.has_side_effects()) { if (def.value) {
initializations.add(def.name.name, def.value);
if (def.value.has_side_effects()) {
def.value.walk(tw); def.value.walk(tw);
} }
}
}); });
return true; return true;
} }
@@ -919,8 +924,8 @@ merge(Compressor.prototype, {
for (var i = 0; i < in_use.length; ++i) { for (var i = 0; i < in_use.length; ++i) {
in_use[i].orig.forEach(function(decl){ in_use[i].orig.forEach(function(decl){
// undeclared globals will be instanceof AST_SymbolRef // undeclared globals will be instanceof AST_SymbolRef
if (decl instanceof AST_SymbolDeclaration) { var init = initializations.get(decl.name);
decl.init.forEach(function(init){ if (init) init.forEach(function(init){
var tw = new TreeWalker(function(node){ var tw = new TreeWalker(function(node){
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
push_uniq(in_use, node.definition()); push_uniq(in_use, node.definition());
@@ -928,7 +933,6 @@ merge(Compressor.prototype, {
}); });
init.walk(tw); init.walk(tw);
}); });
}
}); });
} }
// pass 3: we should drop declarations not in_use // pass 3: we should drop declarations not in_use
@@ -1100,13 +1104,71 @@ merge(Compressor.prototype, {
} }
); );
self = self.transform(tt); self = self.transform(tt);
if (vars_found > 0) hoisted.unshift(make_node(AST_Var, self, { if (vars_found > 0) {
definitions: vars.map(function(def){ // collect only vars which don't show up in self's arguments list
var defs = [];
vars.each(function(def, name){
if (self instanceof AST_Lambda
&& find_if(function(x){ return x.name == def.name.name },
self.argnames)) {
vars.del(name);
} else {
def = def.clone(); def = def.clone();
def.value = null; def.value = null;
return def; defs.push(def);
}) vars.set(name, def);
})); }
});
if (defs.length > 0) {
// try to merge in assignments
for (var i = 0; i < self.body.length;) {
if (self.body[i] instanceof AST_SimpleStatement) {
var expr = self.body[i].body, sym, assign;
if (expr instanceof AST_Assign
&& expr.operator == "="
&& (sym = expr.left) instanceof AST_Symbol
&& vars.has(sym.name))
{
var def = vars.get(sym.name);
if (def.value) break;
def.value = expr.right;
remove(defs, def);
defs.push(def);
self.body.splice(i, 1);
continue;
}
if (expr instanceof AST_Seq
&& (assign = expr.car) instanceof AST_Assign
&& assign.operator == "="
&& (sym = assign.left) instanceof AST_Symbol
&& vars.has(sym.name))
{
var def = vars.get(sym.name);
if (def.value) break;
def.value = assign.right;
remove(defs, def);
defs.push(def);
self.body[i].body = expr.cdr;
continue;
}
}
if (self.body[i] instanceof AST_EmptyStatement) {
self.body.splice(i, 1);
continue;
}
if (self.body[i] instanceof AST_BlockStatement) {
var tmp = [ i, 1 ].concat(self.body[i].body);
self.body.splice.apply(self.body, tmp);
continue;
}
break;
}
defs = make_node(AST_Var, self, {
definitions: defs
});
hoisted.push(defs);
};
}
self.body = dirs.concat(hoisted, self.body); self.body = dirs.concat(hoisted, self.body);
} }
return self; return self;
@@ -1430,7 +1492,7 @@ merge(Compressor.prototype, {
return node; return node;
} }
}); });
tt.stack = compressor.stack; // so that's able to see parent nodes tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
self = self.transform(tt); self = self.transform(tt);
} catch(ex) { } catch(ex) {
if (ex !== self) throw ex; if (ex !== self) throw ex;
@@ -1744,7 +1806,7 @@ merge(Compressor.prototype, {
} }
if (self.operator == "+" && self.right instanceof AST_String if (self.operator == "+" && self.right instanceof AST_String
&& self.right.getValue() === "" && self.left instanceof AST_Binary && self.right.getValue() === "" && self.left instanceof AST_Binary
&& self.left.operator == "+" && self.left.is_string()) { && self.left.operator == "+" && self.left.is_string(compressor)) {
return self.left; return self.left;
} }
return self; return self;

View File

@@ -340,10 +340,10 @@ function OutputStream(options) {
/* -----[ utils ]----- */ /* -----[ utils ]----- */
function DEFPRINT(nodetype, generator) { function DEFPRINT(nodetype, generator) {
nodetype.DEFMETHOD("print", function(stream){ nodetype.DEFMETHOD("print", function(stream, force_parens){
var self = this; var self = this;
stream.push_node(self); stream.push_node(self);
if (self.needs_parens(stream)) { if (force_parens || self.needs_parens(stream)) {
stream.with_parens(function(){ stream.with_parens(function(){
self.add_comments(stream); self.add_comments(stream);
self.add_source_map(stream); self.add_source_map(stream);
@@ -467,18 +467,6 @@ function OutputStream(options) {
return true; return true;
} }
} }
// for (var i = (foo in bar);;); ← perhaps useless, but valid syntax
if (this.operator == "in") {
// the “NoIn” stuff :-\
// UglifyJS 1.3.3 misses this one.
if ((p instanceof AST_For || p instanceof AST_ForIn) && p.init === this)
return true;
if (p instanceof AST_VarDef) {
var v = output.parent(1), p2 = output.parent(2);
if ((p2 instanceof AST_For || p2 instanceof AST_ForIn) && p2.init === v)
return true;
}
}
}); });
PARENS(AST_PropAccess, function(output){ PARENS(AST_PropAccess, function(output){
@@ -622,7 +610,11 @@ function OutputStream(options) {
output.space(); output.space();
output.with_parens(function(){ output.with_parens(function(){
if (self.init) { if (self.init) {
if (self.init instanceof AST_Definitions) {
self.init.print(output); self.init.print(output);
} else {
parenthesize_for_noin(self.init, output, true);
}
output.print(";"); output.print(";");
output.space(); output.space();
} else { } else {
@@ -866,13 +858,32 @@ function OutputStream(options) {
DEFPRINT(AST_Const, function(self, output){ DEFPRINT(AST_Const, function(self, output){
self._do_print(output, "const"); self._do_print(output, "const");
}); });
function parenthesize_for_noin(node, output, noin) {
if (!noin) node.print(output);
else try {
// need to take some precautions here:
// https://github.com/mishoo/UglifyJS2/issues/60
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Binary && node.operator == "in")
throw output;
}));
node.print(output);
} catch(ex) {
if (ex !== output) throw ex;
node.print(output, true);
}
};
DEFPRINT(AST_VarDef, function(self, output){ DEFPRINT(AST_VarDef, function(self, output){
self.name.print(output); self.name.print(output);
if (self.value) { if (self.value) {
output.space(); output.space();
output.print("="); output.print("=");
output.space(); output.space();
self.value.print(output); var p = output.parent(1);
var noin = p instanceof AST_For || p instanceof AST_ForIn;
parenthesize_for_noin(self.value, output, noin);
} }
}); });

View File

@@ -110,9 +110,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
labels.del(l.name); labels.del(l.name);
return true; // no descend again return true; // no descend again
} }
if (node instanceof AST_SymbolDeclaration) {
node.init_scope_vars();
}
if (node instanceof AST_Symbol) { if (node instanceof AST_Symbol) {
node.scope = scope; node.scope = scope;
} }
@@ -128,8 +125,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
// scope. Don't like this fix but seems we can't do any // scope. Don't like this fix but seems we can't do any
// better. IE: please die. Please! // better. IE: please die. Please!
(node.scope = scope.parent_scope).def_function(node); (node.scope = scope.parent_scope).def_function(node);
node.init.push(tw.parent());
} }
else if (node instanceof AST_SymbolDefun) { else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is // Careful here, the scope where this should be defined is
@@ -138,14 +133,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
// instanceof AST_Scope) but we get to the symbol a bit // instanceof AST_Scope) but we get to the symbol a bit
// later. // later.
(node.scope = scope.parent_scope).def_function(node); (node.scope = scope.parent_scope).def_function(node);
node.init.push(tw.parent());
} }
else if (node instanceof AST_SymbolVar else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) { || node instanceof AST_SymbolConst) {
var def = scope.def_variable(node); var def = scope.def_variable(node);
def.constant = node instanceof AST_SymbolConst; def.constant = node instanceof AST_SymbolConst;
def = tw.parent(); def = tw.parent();
if (def.value) node.init.push(def);
} }
else if (node instanceof AST_SymbolCatch) { else if (node instanceof AST_SymbolCatch) {
// XXX: this is wrong according to ECMA-262 (12.4). the // XXX: this is wrong according to ECMA-262 (12.4). the
@@ -246,10 +239,6 @@ AST_SymbolRef.DEFMETHOD("reference", function() {
this.frame = this.scope.nesting - def.scope.nesting; this.frame = this.scope.nesting - def.scope.nesting;
}); });
AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){
this.init = [];
});
AST_Label.DEFMETHOD("init_scope_vars", function(){ AST_Label.DEFMETHOD("init_scope_vars", function(){
this.references = []; this.references = [];
}); });

View File

@@ -255,6 +255,14 @@ Dictionary.prototype = {
this._values["$" + key] = val; this._values["$" + key] = val;
return this; return this;
}, },
add: function(key, val) {
if (this.has(key)) {
this.get(key).push(val);
} else {
this.set(key, [ val ]);
}
return this;
},
get: function(key) { return this._values["$" + key] }, get: function(key) { return this._values["$" + key] },
del: function(key) { del: function(key) {
if (this.has(key)) { if (this.has(key)) {

View File

@@ -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.2.0", "version": "2.2.2",
"engines": { "node" : ">=0.4.0" }, "engines": { "node" : ">=0.4.0" },
"maintainers": [{ "maintainers": [{
"name": "Mihai Bazon", "name": "Mihai Bazon",

30
test/compress/issue-59.js Normal file
View File

@@ -0,0 +1,30 @@
keep_continue: {
options = {
dead_code: true,
evaluate: true
};
input: {
while (a) {
if (b) {
switch (true) {
case c():
d();
}
continue;
}
f();
}
}
expect: {
while (a) {
if (b) {
switch (true) {
case c():
d();
}
continue;
}
f();
}
}
}