aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ast.js10
-rw-r--r--lib/output.js9
-rw-r--r--lib/scope.js72
-rwxr-xr-xtmp/test-node.js2
4 files changed, 64 insertions, 29 deletions
diff --git a/lib/ast.js b/lib/ast.js
index ac5010bb..89a8237b 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -136,7 +136,7 @@ var AST_ForIn = DEFNODE("ForIn", "init name object", {
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.init) this.init._walk(visitor);
- if (this.name) this.name._walk(visitor);
+ else if (this.name) this.name._walk(visitor);
if (this.object) this.object._walk(visitor);
this.body._walk(visitor);
});
@@ -461,7 +461,13 @@ var AST_Object = DEFNODE("Object", "properties", {
}
});
-var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value");
+var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
+ _walk: function(visitor) {
+ return visitor._visit(this, function(){
+ this.value._walk(visitor);
+ });
+ }
+});
var AST_ObjectKeyVal = DEFNODE("ObjectKeyval", null, {
}, AST_ObjectProperty);
diff --git a/lib/output.js b/lib/output.js
index 748921c7..e6b2dd13 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -707,8 +707,9 @@ function OutputStream(options) {
var expr = self.expression;
expr.print(output);
if (expr instanceof AST_Number) {
- if (!/[xa-f.]/i.test(output.last()))
+ if (!/[xa-f.]/i.test(output.last())) {
output.print(".");
+ }
}
output.print(".");
output.print_name(self.property);
@@ -805,7 +806,11 @@ function OutputStream(options) {
output.print_name(self.name);
});
DEFPRINT(AST_SymbolDeclaration, function(self, output){
- output.print_name(self.mangled_name || self.name);
+ if (self.uniq) {
+ self.uniq.print(output);
+ } else {
+ output.print_name(self.mangled_name || self.name);
+ }
});
DEFPRINT(AST_SymbolRef, function(self, output){
var def = self.symbol;
diff --git a/lib/scope.js b/lib/scope.js
index d16ac8a0..c6d655ee 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -1,4 +1,4 @@
-AST_Scope.DEFMETHOD("figure_out_scope", function(){
+AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
// This does what ast_add_scope did in UglifyJS v1.
//
// Part of it could be done at parse time, but it would complicate
@@ -42,28 +42,30 @@ AST_Scope.DEFMETHOD("figure_out_scope", function(){
// XXX: this is wrong according to ECMA-262 (12.4). the
// `catch` argument name should be visible only inside the
// catch block. For a quick fix AST_Catch should inherit
- // from AST_Scope.
+ // from AST_Scope. Keeping it this way because of IE,
+ // which doesn't obey the standard. (it introduces the
+ // identifier in the enclosing scope)
scope.def_variable(node);
}
else if (node instanceof AST_SymbolRef) {
node.scope = scope;
}
+ if (node instanceof AST_LabelRef) {
+ var sym = scope.find_label(node);
+ if (!sym) throw new Error("Undefined label " + node.name);
+ node.reference(sym);
+ }
});
this.walk(tw);
// pass 2: find back references and eval/with
var tw = new TreeWalker(function(node){
- if (node instanceof AST_LabelRef) {
- var sym = node.scope.find_label(node);
- if (!sym) throw new Error("Undefined label " + node.name);
- node.reference(sym);
- }
- else if (node instanceof AST_SymbolRef) {
+ if (node instanceof AST_SymbolRef) {
var sym = node.scope.find_variable(node);
node.reference(sym);
if (!sym) {
if (node.name == "eval") {
- for (var s = scope; s; s = s.parent_scope)
+ for (var s = node.scope; s; s = s.parent_scope)
s.uses_eval = true;
}
}
@@ -72,10 +74,11 @@ AST_Scope.DEFMETHOD("figure_out_scope", function(){
this.walk(tw);
});
-AST_Scope.DEFMETHOD("scope_warnings", function(options){
+AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
options = defaults(options, {
undeclared : false,
- assign_to_global : true
+ assign_to_global : true,
+ eval : true
});
var tw = new TreeWalker(function(node){
if (options.undeclared
@@ -105,6 +108,12 @@ AST_Scope.DEFMETHOD("scope_warnings", function(options){
col: node.start.col
});
}
+ if (options.eval
+ && node instanceof AST_SymbolRef
+ && node.undeclared
+ && node.name == "eval") {
+ AST_Node.warn("Eval is used [{line},{col}]", node.start);
+ }
});
this.walk(tw);
});
@@ -139,15 +148,18 @@ AST_Scope.DEFMETHOD("find_label", function(name){
});
AST_Scope.DEFMETHOD("def_function", function(symbol){
- this.def_variable(symbol);
this.functions[symbol.name] = symbol;
- symbol.scope = this;
+ this.def_variable(symbol);
});
AST_Scope.DEFMETHOD("def_variable", function(symbol){
symbol.global = !this.parent_scope;
- this.variables[symbol.name] = symbol;
- delete this.functions[symbol.name];
+ var existing = this.variables[symbol.name];
+ if (!existing) {
+ this.variables[symbol.name] = symbol;
+ } else {
+ symbol.uniq = existing;
+ }
symbol.scope = this;
});
@@ -158,7 +170,7 @@ AST_Scope.DEFMETHOD("def_label", function(symbol){
AST_Scope.DEFMETHOD("next_mangled", function(for_label){
var ext = this.enclosed, n = ext.length;
- out: for (;;) {
+ out: while (true) {
var m = base54(for_label
? (++this.lname)
: (++this.cname));
@@ -184,22 +196,32 @@ AST_Scope.DEFMETHOD("next_mangled", function(for_label){
});
AST_SymbolDeclaration.DEFMETHOD("mangle", function(){
- if (!this.global)
- this.mangled_name = this.scope.next_mangled(false);
-});
-
-AST_Label.DEFMETHOD("mangle", function(){
- this.mangled_name = this.scope.next_mangled(true);
+ if (this.uniq) {
+ this.uniq.mangle();
+ }
+ else if (!(this.global
+ || this.scope.uses_eval
+ || this.scope.uses_with
+ || this.mangled_name)) {
+ this.mangled_name = this.scope.next_mangled(this instanceof AST_Label);
+ }
});
-AST_Scope.DEFMETHOD("mangle_names", function(){
+AST_Toplevel.DEFMETHOD("mangle_names", function(){
var tw = new TreeWalker(function(node){
// We only need to mangle declarations. Special logic wired
// into the code generator will display the mangled name if
// it's present (and for AST_SymbolRef-s it'll use the mangled
// name of the AST_SymbolDeclaration that it points to).
- if (node instanceof AST_SymbolDeclaration) {
- node.mangle();
+ if (node instanceof AST_Scope) {
+ var a = node.variables;
+ for (var i in a) if (HOP(a, i)) {
+ a[i].mangle();
+ }
+ var a = node.labels;
+ for (var i in a) if (HOP(a, i)) {
+ a[i].mangle();
+ }
}
});
this.walk(tw);
diff --git a/tmp/test-node.js b/tmp/test-node.js
index a80d0935..b78fccbc 100755
--- a/tmp/test-node.js
+++ b/tmp/test-node.js
@@ -5,8 +5,10 @@
var fs = require("fs");
var vm = require("vm");
var sys = require("util");
+ var path = require("path");
function load_global(file) {
+ file = path.resolve(path.dirname(module.filename), file);
try {
var code = fs.readFileSync(file, "utf8");
return vm.runInThisContext(code, file);