diff options
-rw-r--r-- | lib/ast.js | 10 | ||||
-rw-r--r-- | lib/output.js | 9 | ||||
-rw-r--r-- | lib/scope.js | 72 | ||||
-rwxr-xr-x | tmp/test-node.js | 2 |
4 files changed, 64 insertions, 29 deletions
@@ -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); |