Add proper parens in "NoIn" expressions.
authorMihai Bazon <mihai@bazon.net>
Thu, 6 Dec 2012 10:27:57 +0000 (12:27 +0200)
committerMihai Bazon <mihai@bazon.net>
Thu, 6 Dec 2012 10:27:57 +0000 (12:27 +0200)
fix #60.

lib/output.js

index 8f43245..72f49b9 100644 (file)
@@ -340,10 +340,10 @@ function OutputStream(options) {
     /* -----[ utils ]----- */
 
     function DEFPRINT(nodetype, generator) {
-        nodetype.DEFMETHOD("print", function(stream){
+        nodetype.DEFMETHOD("print", function(stream, force_parens){
             var self = this;
             stream.push_node(self);
-            if (self.needs_parens(stream)) {
+            if (force_parens || self.needs_parens(stream)) {
                 stream.with_parens(function(){
                     self.add_comments(stream);
                     self.add_source_map(stream);
@@ -467,18 +467,6 @@ function OutputStream(options) {
                 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){
@@ -622,7 +610,11 @@ function OutputStream(options) {
         output.space();
         output.with_parens(function(){
             if (self.init) {
-                self.init.print(output);
+                if (self.init instanceof AST_Definitions) {
+                    self.init.print(output);
+                } else {
+                    parenthesize_for_noin(self.init, output, true);
+                }
                 output.print(";");
                 output.space();
             } else {
@@ -866,13 +858,32 @@ function OutputStream(options) {
     DEFPRINT(AST_Const, function(self, output){
         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){
         self.name.print(output);
         if (self.value) {
             output.space();
             output.print("=");
             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);
         }
     });