more fixes:
authorMihai Bazon <mihai@bazon.net>
Tue, 21 Aug 2012 08:38:49 +0000 (11:38 +0300)
committerMihai Bazon <mihai@bazon.net>
Tue, 21 Aug 2012 08:38:49 +0000 (11:38 +0300)
- added walker for AST_ObjectProperty
- handle redefinitions properly (only mangle one symbol, make them all point
  to a single definition)

DynarchLIB seems to run fine after mangling + compressed output.

lib/ast.js
lib/output.js
lib/scope.js
tmp/test-node.js

index ac5010b..89a8237 100644 (file)
@@ -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);
index 748921c..e6b2dd1 100644 (file)
@@ -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;
index d16ac8a..c6d655e 100644 (file)
@@ -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);
index a80d093..b78fccb 100755 (executable)
@@ -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);