streamline parenthesis logic (#4072)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 25 Aug 2020 11:45:37 +0000 (12:45 +0100)
committerGitHub <noreply@github.com>
Tue, 25 Aug 2020 11:45:37 +0000 (19:45 +0800)
lib/output.js

index cf05e26..c2fc964 100644 (file)
@@ -682,78 +682,66 @@ function OutputStream(options) {
 
     PARENS(AST_Unary, function(output) {
         var p = output.parent();
-        return p instanceof AST_PropAccess && p.expression === this
-            || p instanceof AST_Call && p.expression === this;
+        return (p instanceof AST_Call || p instanceof AST_PropAccess) && p.expression === this;
     });
 
     PARENS(AST_Sequence, function(output) {
         var p = output.parent();
-            // (foo, bar)() or foo(1, (2, 3), 4)
-        return p instanceof AST_Call
-            // !(foo, bar, baz)
-            || p instanceof AST_Unary
+            // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
+        return p instanceof AST_Array
             // 1 + (2, 3) + 4 ==> 8
             || p instanceof AST_Binary
-            // var a = (1, 2), b = a + a; ==> b == 4
-            || p instanceof AST_VarDef
-            // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
-            || p instanceof AST_PropAccess && p.expression === this
-            // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
-            || p instanceof AST_Array
-            // { foo: (1, 2) }.foo ==> 2
-            || p instanceof AST_ObjectProperty
+            // new (foo, bar) or foo(1, (2, 3), 4)
+            || p instanceof AST_Call
             // (false, true) ? (a = 10, b = 20) : (c = 30)
             // ==> 20 (side effect, set a := 10 and b := 20)
-            || p instanceof AST_Conditional;
+            || p instanceof AST_Conditional
+            // { foo: (1, 2) }.foo ==> 2
+            || p instanceof AST_ObjectProperty
+            // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
+            || p instanceof AST_PropAccess && p.expression === this
+            // !(foo, bar, baz)
+            || p instanceof AST_Unary
+            // var a = (1, 2), b = a + a; ==> b == 4
+            || p instanceof AST_VarDef;
     });
 
     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];
-            if (pp > sp
-                || (pp == sp
-                    && this === p.right)) {
-                return true;
-            }
+            return pp > sp || (pp == sp && this === p.right);
         }
+        // (foo && bar)()
+        if (p instanceof AST_Call) return p.expression === this;
+        // (foo && bar)["prop"], (foo && bar).prop
+        if (p instanceof AST_PropAccess) return p.expression === this;
+        // typeof (foo && bar)
+        if (p instanceof AST_Unary) return true;
     });
 
     PARENS(AST_PropAccess, function(output) {
+        var node = this;
         var p = output.parent();
-        if (p instanceof AST_New && p.expression === this) {
-            // i.e. new (foo.bar().baz)
+        if (p instanceof AST_New && p.expression === node) {
+            // i.e. new (foo().bar)
             //
             // if there's one call into this subtree, then we need
             // parens around it too, otherwise the call will be
             // interpreted as passing the arguments to the upper New
             // expression.
-            var parens = false;
-            this.walk(new TreeWalker(function(node) {
-                if (parens || node instanceof AST_Scope) return true;
-                if (node instanceof AST_Call) {
-                    parens = true;
-                    return true;
-                }
-            }));
-            return parens;
+            do {
+                node = node.expression;
+            } while (node instanceof AST_PropAccess);
+            return node.TYPE == "Call";
         }
     });
 
     PARENS(AST_Call, function(output) {
         var p = output.parent();
-        if (p instanceof AST_New && p.expression === this) return true;
+        if (p instanceof AST_New) return p.expression === this;
         // https://bugs.webkit.org/show_bug.cgi?id=123506
         if (output.option('webkit')) {
             var g = output.parent(1);
@@ -766,11 +754,12 @@ function OutputStream(options) {
     });
 
     PARENS(AST_New, function(output) {
+        if (need_constructor_parens(this, output)) return false;
         var p = output.parent();
-        if (!need_constructor_parens(this, output)
-            && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
-                || p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
-            return true;
+        // (new foo)(bar)
+        if (p instanceof AST_Call) return p.expression === this;
+        // (new Date).getTime(), (new Date)["getTime"]()
+        return p instanceof AST_PropAccess;
     });
 
     PARENS(AST_Number, function(output) {
@@ -779,29 +768,22 @@ function OutputStream(options) {
             var value = this.value;
             // https://github.com/mishoo/UglifyJS/issues/115
             // https://github.com/mishoo/UglifyJS/pull/1009
-            if (value < 0 || /^0/.test(make_num(value))) {
-                return true;
-            }
+            return value < 0 || /^0/.test(make_num(value));
         }
     });
 
     PARENS([ AST_Assign, AST_Conditional ], function(output) {
         var p = output.parent();
-        // !(a = false) → true
-        if (p instanceof AST_Unary)
-            return true;
         // 1 + (a = 2) + 3 → 6, side effect setting a = 2
-        if (p instanceof AST_Binary && !(p instanceof AST_Assign))
-            return true;
+        if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
         // (a = func)() —or— new (a = Object)()
-        if (p instanceof AST_Call && p.expression === this)
-            return true;
+        if (p instanceof AST_Call) return p.expression === this;
         // (a = foo) ? bar : baz
-        if (p instanceof AST_Conditional && p.condition === this)
-            return true;
+        if (p instanceof AST_Conditional) return p.condition === this;
         // (a = foo)["prop"] —or— (a = foo).prop
-        if (p instanceof AST_PropAccess && p.expression === this)
-            return true;
+        if (p instanceof AST_PropAccess) return p.expression === this;
+        // !(a = false) → true
+        if (p instanceof AST_Unary) return true;
     });
 
     /* -----[ PRINTERS ]----- */