added some comments about the rules governing parens
authorMihai Bazon <mihai@bazon.net>
Fri, 17 Aug 2012 14:56:16 +0000 (17:56 +0300)
committerMihai Bazon <mihai@bazon.net>
Fri, 17 Aug 2012 15:06:29 +0000 (18:06 +0300)
lib/output.js

index 54707f0..b7bf79d 100644 (file)
@@ -228,6 +228,7 @@ function OutputStream(options) {
         nodetype.DEFMETHOD("print", function(stream){
             var self = this;
             stream.push_node(self);
+            //stream.print("«" + self.TYPE + ":" + self.start.line + ":" + self.start.col + "»");
             if (self.needs_parens(stream)) {
                 stream.with_parens(function(){
                     generator(self, stream);
@@ -268,23 +269,29 @@ function OutputStream(options) {
 
     PARENS(AST_Seq, function(output){
         var p = output.parent();
-        return p instanceof AST_Call
-            || p instanceof AST_Binary
-            || p instanceof AST_VarDef
-            || p instanceof AST_Dot
-            || p instanceof AST_Array
-            || p instanceof AST_ObjectProperty
-            || p instanceof AST_Conditional;
+        return p instanceof AST_Call             // (foo, bar)() β€”orβ€” foo(1, (2, 3), 4)
+            || p instanceof AST_Binary           // 1 + (2, 3) + 4 β†’ 7
+            || p instanceof AST_VarDef           // var a = (1, 2), b = a + a; β†’ b = 4
+            || p instanceof AST_Dot              // (1, {foo:2}).foo β†’ 2
+            || p instanceof AST_Array            // [ 1, (2, 3), 4 ] β†’ [ 1, 3, 4 ]
+            || p instanceof AST_ObjectProperty   // { foo: (1, 2) }.foo β†’ 2
+            || p instanceof AST_Conditional      /* (false, true) ? (a = 10, b = 20) : (c = 30)
+                                                  * β†’ 20 (side effect, set a = 10 and b = 20) */
+        ;
     });
 
     PARENS(AST_Binary, function(output){
         var p = output.parent();
+        // (foo && bar)()
         if (p instanceof AST_Call && p.expression === this)
             return true;
+        // typeof (foo && bar)
         if (p instanceof AST_Unary)
             return true;
+        // (foo && bar)["prop"], (foo && bar).prop
         if (p instanceof AST_PropAccess && p.expression === this)
             return true;
+        // this deals with precedence: 3 * (2 + 1)
         if (p instanceof AST_Binary) {
             var po = p.operator, pp = PRECEDENCE[po];
             var so = this.operator, sp = PRECEDENCE[so];
@@ -298,6 +305,7 @@ 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.
@@ -313,26 +321,32 @@ function OutputStream(options) {
 
     PARENS(AST_New, function(output){
         var p = output.parent();
+        // (new Date).getTime();
         if (p instanceof AST_Dot && no_constructor_parens(this, output))
             return true;
     });
 
     function assign_and_conditional_paren_rules(output) {
         var p = output.parent();
+        // !(a = false) β†’ true
         if (p instanceof AST_Unary)
             return true;
+        // 1 + (a = 2) + 3 β†’ 3, side effect setting a = 2
         if (p instanceof AST_Binary && !(p instanceof AST_Assign))
             return true;
+        // (a = func)() β€”orβ€” new (a = Object)()
         if (p instanceof AST_Call && p.expression === this)
             return true;
+        // (a = foo) ? bar : baz
         if (p instanceof AST_Conditional && p.condition === this)
             return true;
+        // (a = foo)["prop"] β€”orβ€” (a = foo).prop
         if (p instanceof AST_PropAccess && p.expression === this)
             return true;
     };
 
-    PARENS(AST_Conditional, assign_and_conditional_paren_rules);
     PARENS(AST_Assign, assign_and_conditional_paren_rules);
+    PARENS(AST_Conditional, assign_and_conditional_paren_rules);
 
     /* -----[ PRINTERS ]----- */
 
@@ -639,11 +653,6 @@ function OutputStream(options) {
             });
         });
     });
-    function no_constructor_parens(self, output) {
-        return (self.args.length == 0
-                // && !output.options("beautify")
-               );
-    };
     DEFPRINT(AST_New, function(self, output){
         output.print("new");
         output.space();
@@ -779,15 +788,16 @@ function OutputStream(options) {
     function first_in_statement(output) {
         var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
         while (i > 0) {
-            if (p instanceof AST_Statement) return true;
-            if ((p instanceof AST_Seq && p.first === node) ||
-                (p instanceof AST_Call && p.expression === node) ||
-                (p instanceof AST_Dot && p.expression === node) ||
-                (p instanceof AST_Sub && p.expression === node) ||
-                (p instanceof AST_Conditional && p.condition === node) ||
-                (p instanceof AST_Binary && p.first === node) ||
-                (p instanceof AST_Assign && p.first === node) ||
-                (p instanceof AST_UnaryPostfix && p.expression === node))
+            if (p instanceof AST_Statement)
+                return true;
+            if ((p instanceof AST_Seq           && p.first === node      ) ||
+                (p instanceof AST_Call          && p.expression === node ) ||
+                (p instanceof AST_Dot           && p.expression === node ) ||
+                (p instanceof AST_Sub           && p.expression === node ) ||
+                (p instanceof AST_Conditional   && p.condition === node  ) ||
+                (p instanceof AST_Binary        && p.first === node      ) ||
+                (p instanceof AST_Assign        && p.first === node      ) ||
+                (p instanceof AST_UnaryPostfix  && p.expression === node ))
             {
                 node = p;
                 p = a[--i];
@@ -797,6 +807,11 @@ function OutputStream(options) {
         }
     };
 
+    // self should be AST_New.  decide if we want to show parens or not.
+    function no_constructor_parens(self, output) {
+        return self.args.length == 0 && !output.options("beautify");
+    };
+
     function best_of(a) {
         var best = a[0], len = best.length;
         for (var i = 1; i < a.length; ++i) {