Repository: prettier/plugin-php
Pull request #617 (2018-09-12 10:12:58)

docs: issue template


Patch:
diff --git a/.github/ISSUE_TEMPLATE/formatting.md b/.github/ISSUE_TEMPLATE/formatting.md
new file mode 100644
index 0000000..77870dd
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/formatting.md
@@ -0,0 +1,44 @@
+---
+name: ✨ Formatting
+about: Issues for ugly or incorrect code
+---
+
+<!--
+
+BEFORE SUBMITTING AN ISSUE:
+
+1.  Search for your issue on GitHub: https://github.com/prettier/plugin-php/issues
+    A large number of opened issues are duplicates of existing issues.
+    If someone has already opened an issue for what you are experiencing,
+    you do not need to open a new issue — please add a 👍 reaction to the
+    existing issue instead.
+
+2.  We get a lot of requests for adding options, but Prettier is
+    built on the principle of being opinionated about code formatting.
+    This means we have a very high bar for adding new options.
+    Find out more: https://prettier.io/docs/en/option-philosophy.html
+
+-->
+
+**Prettier 1.14.2**
+
+**PHP Plugin 0.6.0**
+
+```sh
+# Options (if any):
+--single-quote
+```
+
+**Input:**
+
+```php
+// code snippet
+```
+
+**Output:**
+
+```php
+// code snippet
+```
+
+**Expected behavior:**
diff --git a/src/needs-parens.js b/src/needs-parens.js
index 42787d5..7ba6668 100644
--- a/src/needs-parens.js
+++ b/src/needs-parens.js
@@ -1,6 +1,13 @@
 "use strict";
 
-const { isLookupNode } = require("./util");
+const assert = require("assert");
+
+const {
+  isLookupNode,
+  getPrecedence,
+  shouldFlatten,
+  isBitwiseOperator
+} = require("./util");
 
 function needsParens(path) {
   const parent = path.getParentNode();
@@ -39,8 +46,6 @@ function needsParens(path) {
   }
 
   switch (node.kind) {
-    case "call":
-      return false;
     case "pre":
     case "post":
       if (parent.kind === "unary") {
@@ -67,13 +72,70 @@ function needsParens(path) {
         default:
           return false;
       }
-    case "clone":
-    case "new": {
-      if (isLookupNode(parent)) {
+    case "bin": {
+      // $var = false or true;
+      // The constant false is assigned to $f before the "or" operation occurs
+      // Acts like: (($var = false) or true)
+      if (["and", "xor", "or"].includes(node.type)) {
         return true;
       }
 
-      return false;
+      switch (parent.kind) {
+        case "pre":
+        case "post":
+        case "unary":
+        case "cast":
+        case "silent":
+          return true;
+        case "call":
+        case "propertylookup":
+        case "staticlookup":
+        case "offsetlookup":
+          return name === "what" && parent.what === node;
+        case "bin": {
+          const po = parent.type;
+          const pp = getPrecedence(po);
+          const no = node.type;
+          const np = getPrecedence(no);
+
+          if (pp > np) {
+            return true;
+          }
+
+          if (po === "||" && no === "&&") {
+            return true;
+          }
+
+          if (pp === np && name === "right") {
+            assert.strictEqual(parent.right, node);
+
+            return true;
+          }
+
+          if (pp === np && !shouldFlatten(po, no)) {
+            return true;
+          }
+
+          if (pp < np && no === "%") {
+            return !shouldFlatten(po, no);
+          }
+
+          // Add parenthesis when working with binary operators
+          // It's not stricly needed but helps with code understanding
+          if (isBitwiseOperator(po)) {
+            return true;
+          }
+
+          return false;
+        }
+
+        default:
+          return false;
+      }
+    }
+    case "clone":
+    case "new": {
+      return isLookupNode(parent);
     }
     case "yield": {
       switch (parent.kind) {
@@ -114,7 +176,7 @@ function needsParens(path) {
         case "cast":
           return true;
         case "retif":
-          return name === "test" && parent.test === node;
+          return true;
         case "propertylookup":
         case "staticlookup":
         case "offsetlookup":
@@ -125,23 +187,7 @@ function needsParens(path) {
           return false;
       }
     case "closure":
-      if (parent.kind === "call" && name === "what" && parent.what === node) {
-        return true;
-      }
-
-      return false;
-    case "boolean":
-    case "number":
-    case "magic":
-    case "encapsed":
-    case "nowdoc":
-    case "variable":
-    case "isset":
-    case "empty":
-    case "silent":
-    case "exit":
-    case "eval":
-      return false;
+      return parent.kind === "call" && name === "what" && parent.what === node;
     case "string":
     case "array":
     case "cast":
@@ -162,36 +208,12 @@ function needsParens(path) {
       }
 
       return false;
-    case "propertylookup":
-    case "staticlookup":
-    case "offsetlookup":
-      return false;
-    case "bin": {
-      if (["pre", "post"].includes(parent.kind)) {
-        return true;
-      }
-
-      if (["if", "while", "do", "switch", "case"].includes(parent.kind)) {
-        return false;
-      }
-
-      // $var = false or true;
-      // The constant false is assigned to $f before the "or" operation occurs
-      // Acts like: (($var = false) or true)
-      if (
-        node.right.kind === "bin" &&
-        ["and", "xor", "or"].includes(node.right.type)
-      ) {
-        return true;
-      }
-
-      if (parent.kind === "cast") {
-        return true;
-      }
-    }
+    case "print":
+    case "include":
+      return parent.kind === "bin";
   }
 
-  return node.parenthesizedExpression;
+  return false;
 }
 
 module.exports = needsParens;
diff --git a/src/printer.js b/src/printer.js
index 9e48502..0b27891 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -1811,7 +1811,7 @@ function printNode(path, options, print) {
         indent(
           concat([hasEmptyBody ? "" : hardline, path.call(print, "body")])
         ),
-        concat([hardline, "}"])
+        concat([hasEmptyBody ? "" : hardline, "}"])
       ]);
     }
     case "retif": {
@@ -2041,8 +2041,17 @@ function printNode(path, options, print) {
       );
     case "echo": {
       const printedArguments = path.map((argumentPath, index) => {
+        const argumentNode = argumentPath.getValue();
         let printed = print(argumentPath);
 
+        if (
+          (argumentNode.kind === "encapsed" &&
+            argumentNode.type === "heredoc") ||
+          argumentNode.kind === "nowdoc"
+        ) {
+          return printed;
+        }
+
         if (index === 0) {
           printed = dedent(printed);
         }
diff --git a/src/util.js b/src/util.js
index f114450..b7fae92 100644
--- a/src/util.js
+++ b/src/util.js
@@ -49,6 +49,7 @@ const PRECEDENCE = {};
   ["+", "-", "."],
   ["*", "/", "%"],
   ["!"],
+  ["instanceof"],
   ["++", "--", "~"],
   ["**"]
 ].forEach((tier, i) => {
@@ -66,6 +67,15 @@ const additiveOperators = ["+", "-"];
 const multiplicativeOperators = ["*", "/", "%"];
 const bitshiftOperators = [">>", "<<"];
 
+function isBitwiseOperator(operator) {
+  return (
+    !!bitshiftOperators[operator] ||
+    operator === "|" ||
+    operator === "^" ||
+    operator === "&"
+  );
+}
+
 function shouldFlatten(parentOp, nodeOp) {
   if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
     // x + y % z --> (x + y) % z
@@ -231,7 +241,36 @@ function isFirstChildrenInlineNode(path) {
  * appear as function arguments or array elements
  */
 function docShouldHaveTrailingNewline(path) {
-  return ["array", "parameter"].includes(path.getParentNode().kind);
+  const node = path.getValue();
+  const parent = path.getParentNode();
+
+  if (!parent) {
+    return false;
+  }
+
+  if (parent.kind === "echo") {
+    const lastIndex = parent.arguments.length - 1;
+    const index = parent.arguments.indexOf(node);
+
+    return index !== lastIndex;
+  }
+
+  if (parent.kind === "array") {
+    const lastIndex = parent.items.length - 1;
+    const index = parent.items.indexOf(node);
+
+    return index !== lastIndex;
+  }
+
+  if (parent.kind === "parameter") {
+    const parentParent = path.getParentNode(1);
+    const lastIndex = parentParent.arguments.length - 1;
+    const index = parentParent.arguments.indexOf(parent);
+
+    return index !== lastIndex;
+  }
+
+  return false;
 }
 
 function lineShouldEndWithSemicolon(path) {
@@ -533,6 +572,7 @@ function hasNewline(text, index, opts) {
 module.exports = {
   printNumber,
   getPrecedence,
+  isBitwiseOperator,
   shouldFlatten,
   nodeHasStatement,
   getNodeListProperty,


Test patch:
diff --git a/tests/bin/__snapshots__/jsfmt.spec.js.snap b/tests/bin/__snapshots__/jsfmt.spec.js.snap
index 0f95088..58ed762 100644
--- a/tests/bin/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/bin/__snapshots__/jsfmt.spec.js.snap
@@ -345,8 +345,8 @@ call(
 );
 
 $var =
-    $someReallyReallyReallyLongBooleanVariable *
-        $someReallyReallyReallyLongBooleanVariable /
+    ($someReallyReallyReallyLongBooleanVariable *
+        $someReallyReallyReallyLongBooleanVariable) /
     100;
 $var =
     ($someReallyReallyReallyLongBooleanVariable *
@@ -357,18 +357,18 @@ $var =
     ($someReallyReallyReallyLongBooleanVariable / 100);
 $var =
     $someReallyReallyReallyLongBooleanVariable +
-    $someReallyReallyReallyLongBooleanVariable % 100;
+    ($someReallyReallyReallyLongBooleanVariable % 100);
 $var =
-    $someReallyReallyReallyLongBooleanVariable *
-        $someReallyReallyReallyLongBooleanVariable %
+    ($someReallyReallyReallyLongBooleanVariable *
+        $someReallyReallyReallyLongBooleanVariable) %
     100;
 $var =
-    $someReallyReallyReallyLongBooleanVariable <<
-        $someReallyReallyReallyLongBooleanVariable <<
+    ($someReallyReallyReallyLongBooleanVariable <<
+        $someReallyReallyReallyLongBooleanVariable) <<
     100;
 $var =
     $someReallyReallyReallyLongBooleanVariable **
-    $someReallyReallyReallyLongBooleanVariable ** 100;
+    ($someReallyReallyReallyLongBooleanVariable ** 100);
 $var =
     $someReallyReallyReallyLongBooleanVariable +
     $someReallyReallyReallyLongBooleanVariable * 100;
@@ -378,15 +378,15 @@ $var =
     100;
 $var =
     $someReallyReallyReallyLongBooleanVariable +
-    $someReallyReallyReallyLongBooleanVariable % 100;
+    ($someReallyReallyReallyLongBooleanVariable % 100);
 $var =
-    $someReallyReallyReallyLongBooleanVariable %
-        $someReallyReallyReallyLongBooleanVariable +
+    ($someReallyReallyReallyLongBooleanVariable %
+        $someReallyReallyReallyLongBooleanVariable) +
     100;
 
 if (
-    $someReallyReallyReallyLongBooleanVariable *
-        $someReallyReallyReallyLongBooleanVariable /
+    ($someReallyReallyReallyLongBooleanVariable *
+        $someReallyReallyReallyLongBooleanVariable) /
     100
 ) {
 }
@@ -403,24 +403,24 @@ if (
 }
 if (
     $someReallyReallyReallyLongBooleanVariable +
-    $someReallyReallyReallyLongBooleanVariable % 100
+    ($someReallyReallyReallyLongBooleanVariable % 100)
 ) {
 }
 if (
-    $someReallyReallyReallyLongBooleanVariable *
-        $someReallyReallyReallyLongBooleanVariable %
+    ($someReallyReallyReallyLongBooleanVariable *
+        $someReallyReallyReallyLongBooleanVariable) %
     100
 ) {
 }
 if (
-    $someReallyReallyReallyLongBooleanVariable <<
-        $someReallyReallyReallyLongBooleanVariable <<
+    ($someReallyReallyReallyLongBooleanVariable <<
+        $someReallyReallyReallyLongBooleanVariable) <<
     100
 ) {
 }
 if (
     $someReallyReallyReallyLongBooleanVariable **
-    $someReallyReallyReallyLongBooleanVariable ** 100
+    ($someReallyReallyReallyLongBooleanVariable ** 100)
 ) {
 }
 if (
@@ -436,12 +436,12 @@ if (
 }
 if (
     $someReallyReallyReallyLongBooleanVariable +
-    $someReallyReallyReallyLongBooleanVariable % 100
+    ($someReallyReallyReallyLongBooleanVariable % 100)
 ) {
 }
 if (
-    $someReallyReallyReallyLongBooleanVariable %
-        $someReallyReallyReallyLongBooleanVariable +
+    ($someReallyReallyReallyLongBooleanVariable %
+        $someReallyReallyReallyLongBooleanVariable) +
     100
 ) {
 }
@@ -455,9 +455,9 @@ echo 'This ' .
     'string ' .
     (100 - 100) .
     'was ' .
-    (100 * 100) .
+    100 * 100 .
     'made ' .
-    (100 / 100) .
+    100 / 100 .
     'with concatenation.';
 
 if ($someReallyReallyReallyLongBooleanVariableWithRddllyReallyLongName || []) {
diff --git a/tests/closure/__snapshots__/jsfmt.spec.js.snap b/tests/closure/__snapshots__/jsfmt.spec.js.snap
index abcac1f..c6b3ae7 100644
--- a/tests/closure/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/closure/__snapshots__/jsfmt.spec.js.snap
@@ -135,6 +135,8 @@ $var = function &() {
 
 $func = static function() {};
 $fn = function &() use (&$value) { return $value; };
+
+$var = function () {};
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -198,8 +200,7 @@ $foo->bar(
     $longLongLongLongLongLongLongLongLongLongArg3
 );
 
-$emptyFunc = function () {
-};
+$emptyFunc = function () {};
 
 $emptyFuncWithComment = function () {
     /* Comment */
@@ -267,10 +268,11 @@ $var = function &() {
     return $collection;
 };
 
-$func = static function () {
-};
+$func = static function () {};
 $fn = function &() use (&$value) {
     return $value;
 };
 
+$var = function () {};
+
 `;
diff --git a/tests/closure/closure.php b/tests/closure/closure.php
index 7373482..28e02fe 100644
--- a/tests/closure/closure.php
+++ b/tests/closure/closure.php
@@ -132,3 +132,5 @@ $var = function &() {
 
 $func = static function() {};
 $fn = function &() use (&$value) { return $value; };
+
+$var = function () {};
diff --git a/tests/comments/__snapshots__/jsfmt.spec.js.snap b/tests/comments/__snapshots__/jsfmt.spec.js.snap
index b102d0a..9545002 100644
--- a/tests/comments/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/comments/__snapshots__/jsfmt.spec.js.snap
@@ -336,7 +336,7 @@ $foo->bar(/* B */);
 foo(
     /* Comment */ $a /* Comment */,
     /* Comment */ [] /* Comment */,
-    /* Comment */ ($a + 2) /* Comment */
+    /* Comment */ $a + 2 /* Comment */
 );
 foo(/* A */);
 $foo->bar(/* B */);
diff --git a/tests/echo/__snapshots__/jsfmt.spec.js.snap b/tests/echo/__snapshots__/jsfmt.spec.js.snap
index 0f4669c..1cf4008 100644
--- a/tests/echo/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/echo/__snapshots__/jsfmt.spec.js.snap
@@ -168,6 +168,22 @@ Example of string
 spanning multiple lines
 using nowdoc syntax.
 EOD;
+
+echo <<<EOD
+Example of string
+spanning multiple lines
+using heredoc syntax.
+EOD
+    ,
+    'test';
+
+echo <<<'EOD'
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOD
+    ,
+    'test';
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -276,7 +292,7 @@ echo 1;
 echo 1;
 echo 1, 1;
 
-echo "The sum is " . 1 | 2; // output: "2". Parentheses needed.
+echo ("The sum is " . 1) | 2; // output: "2". Parentheses needed.
 echo "The sum is ", 1 | 2; // output: "The sum is 3". Fine.
 
 echo "Foo" . f("bar") . "Foo";
@@ -394,4 +410,20 @@ spanning multiple lines
 using nowdoc syntax.
 EOD;
 
+echo <<<EOD
+Example of string
+spanning multiple lines
+using heredoc syntax.
+EOD
+    ,
+    'test';
+
+echo <<<'EOD'
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOD
+    ,
+    'test';
+
 `;
diff --git a/tests/echo/echo.php b/tests/echo/echo.php
index 34308fd..14ac18c 100644
--- a/tests/echo/echo.php
+++ b/tests/echo/echo.php
@@ -165,3 +165,19 @@ Example of string
 spanning multiple lines
 using nowdoc syntax.
 EOD;
+
+echo <<<EOD
+Example of string
+spanning multiple lines
+using heredoc syntax.
+EOD
+    ,
+    'test';
+
+echo <<<'EOD'
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOD
+    ,
+    'test';
diff --git a/tests/encapsed/__snapshots__/jsfmt.spec.js.snap b/tests/encapsed/__snapshots__/jsfmt.spec.js.snap
index 5152c4d..dca1a12 100644
--- a/tests/encapsed/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/encapsed/__snapshots__/jsfmt.spec.js.snap
@@ -62,6 +62,12 @@ foo
 EOF
 , "bar"
 );
+$content = array(
+    "bar",
+    <<<EOF
+foo
+EOF
+);
 
 function foo($a = 1, $b = <<<EOF
 Example of string
@@ -85,6 +91,17 @@ EOF
 ) {
     echo $b;
 }
+
+function foo1(
+    $a = 1,
+    $b = <<<EOF
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOF
+) {
+    echo $b;
+}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 $encapsShell = \`a $b\`;
@@ -152,6 +169,12 @@ EOF
     ,
     "bar"
 );
+$content = array(
+    "bar",
+    <<<EOF
+foo
+EOF
+);
 
 function foo(
     $a = 1,
@@ -181,6 +204,18 @@ EOF
     echo $b;
 }
 
+function foo1(
+    $a = 1,
+    $b = <<<EOF
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOF
+)
+{
+    echo $b;
+}
+
 `;
 
 exports[`single.php 1`] = `
diff --git a/tests/encapsed/encapsed.php b/tests/encapsed/encapsed.php
index 5fbcdbe..421b1a7 100644
--- a/tests/encapsed/encapsed.php
+++ b/tests/encapsed/encapsed.php
@@ -59,6 +59,12 @@ foo
 EOF
 , "bar"
 );
+$content = array(
+    "bar",
+    <<<EOF
+foo
+EOF
+);
 
 function foo($a = 1, $b = <<<EOF
 Example of string
@@ -82,3 +88,14 @@ EOF
 ) {
     echo $b;
 }
+
+function foo1(
+    $a = 1,
+    $b = <<<EOF
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOF
+) {
+    echo $b;
+}
diff --git a/tests/if/__snapshots__/jsfmt.spec.js.snap b/tests/if/__snapshots__/jsfmt.spec.js.snap
index 40a5fef..bcdaeb6 100644
--- a/tests/if/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/if/__snapshots__/jsfmt.spec.js.snap
@@ -155,30 +155,30 @@ if (
 
 if (
     $this ||
-    $that && $theOtherThing && $someReallyReallyReallyLongBooleanVariable
+    ($that && $theOtherThing && $someReallyReallyReallyLongBooleanVariable)
 ) {
     return true;
 }
 
 if (
     $this ||
-    $that && $theOtherThing < $someReallyReallyReallyLongBooleanVariable
+    ($that && $theOtherThing < $someReallyReallyReallyLongBooleanVariable)
 ) {
     return true;
 }
 
 if (
     $this ||
-    $that &&
+    ($that &&
         $theOtherThing < $someReallyReallyReallyLongBooleanVariable ==
-            $equalCheck
+            $equalCheck)
 ) {
     return true;
 }
 
 if (
     $this ||
-    $that && $theOtherThing ||
+    ($that && $theOtherThing) ||
     $someReallyReallyReallyLongBooleanVariable
 ) {
     return true;
diff --git a/tests/include/__snapshots__/jsfmt.spec.js.snap b/tests/include/__snapshots__/jsfmt.spec.js.snap
index ba7a1a1..46152dc 100644
--- a/tests/include/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/include/__snapshots__/jsfmt.spec.js.snap
@@ -67,7 +67,7 @@ require_once "other/other.php";
 
 include 'http://www.example.com/file.php?foo=1&bar=2';
 include $filename;
-(isset($_GET['p']) && $_GET['p'] === 'home') ? include 'pages/home.php' : '';
+isset($_GET['p']) && $_GET['p'] === 'home' ? include 'pages/home.php' : '';
 include Kohana::find_file('views', 'admin/system/errors');
 include "test.php";
 include 'foo.php' . ' MORE OUTPUT';
diff --git a/tests/nowdoc/__snapshots__/jsfmt.spec.js.snap b/tests/nowdoc/__snapshots__/jsfmt.spec.js.snap
index 7c709c7..930d6ce 100644
--- a/tests/nowdoc/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/nowdoc/__snapshots__/jsfmt.spec.js.snap
@@ -25,6 +25,13 @@ EOF
 , "bar"
 );
 
+$str = array(
+    "bar",
+    <<<'EOF'
+foo
+EOF
+);
+
 $str = sprintf(<<<'EOF'
 foo
 EOF
@@ -62,6 +69,17 @@ EOD
 ) {
     echo $b;
 }
+
+function foo1(
+    $a = 1,
+    $b = <<<'EOD'
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOD
+) {
+    echo $b;
+}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -89,6 +107,13 @@ EOF
     "bar"
 );
 
+$str = array(
+    "bar",
+    <<<'EOF'
+foo
+EOF
+);
+
 $str = sprintf(
     <<<'EOF'
 foo
@@ -139,6 +164,18 @@ EOD
     echo $b;
 }
 
+function foo1(
+    $a = 1,
+    $b = <<<'EOD'
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOD
+)
+{
+    echo $b;
+}
+
 `;
 
 exports[`single.php 1`] = `
diff --git a/tests/nowdoc/nowdoc.php b/tests/nowdoc/nowdoc.php
index a63660b..d92bfb8 100644
--- a/tests/nowdoc/nowdoc.php
+++ b/tests/nowdoc/nowdoc.php
@@ -22,6 +22,13 @@ EOF
 , "bar"
 );
 
+$str = array(
+    "bar",
+    <<<'EOF'
+foo
+EOF
+);
+
 $str = sprintf(<<<'EOF'
 foo
 EOF
@@ -59,3 +66,14 @@ EOD
 ) {
     echo $b;
 }
+
+function foo1(
+    $a = 1,
+    $b = <<<'EOD'
+Example of string
+spanning multiple lines
+using nowdoc syntax.
+EOD
+) {
+    echo $b;
+}
diff --git a/tests/parens/__snapshots__/jsfmt.spec.js.snap b/tests/parens/__snapshots__/jsfmt.spec.js.snap
index c64663a..08feb79 100644
--- a/tests/parens/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/parens/__snapshots__/jsfmt.spec.js.snap
@@ -193,10 +193,10 @@ for ($i = 1; $i <= 10; $i++) {
     echo $i;
 }
 
-for ($i = 1; ($i <= 10); $i++) {
+for ($i = 1; $i <= 10; $i++) {
     echo $i;
 }
-for ($i = 1, $j = 0; ($i <= 10); $j += $i, print $i, $i++);
+for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i, $i++);
 
 if ($a = 1) {
 }
@@ -378,6 +378,195 @@ $var = true && false;
 $var = (true && false);
 $var = true and false;
 $var = (true and false);
+
+$var = $var || $var();
+$var = ($var || $var)();
+$var = $var && $var();
+$var = ($var && $var)();
+$var = call($var || $var);
+$var = call(($var || $var));
+$var = call($var && $var);
+$var = call(($var && $var));
+
+$var = +($var || $var);
+$var = -($var || $var);
+$var = ~($var || $var);
+
+$var = ($var || $var)->foo;
+$var = ($var || $var)->foo();
+$var = ($var || $var)[1];
+
+$var = $var || $var && $var;
+$var = ($var || $var) && $var;
+$var = $var || ($var && $var);
+
+$var = $var & ($var || 'test');
+$var = ($var || 'test') & $var;
+$var = $var & ($var . 'test');
+$var = ($var . 'test') & $var;
+$var = ($var & $var) || 'test';
+$var = $var || ('test' & $var);
+
+$var = ($var || $var) % 100;
+$var = ($var + $var) % 100;
+$var = 100 % ($var || $var);
+$var = 100 % ($var + $var);
+$var = $var || ($var % 100);
+$var = $var + ($var % 100);
+$var = (100 % $var) || $var;
+$var = (100 % $var) + $var;
+
+$var = ($var + $var) >> 1;
+$var = (($var - 1) >> $var) & $var;
+$var = $var > $var ? 0 : ($var - $var) >> $var;
+$var = (($var - $var) >> $var) + 1;
+
+if ($var < 1 << ($var + $var)) {}
+
+$var = $var < $var ? 0 : ((($var - 1) >> $var) << $var);
+$var = 1 - (2 * ($var[3] >> 7));
+$var = ((($var[3] << 1) & 0xff) | ($var[2] >> 7)) - 127;
+$var = (($var[2] & 0x7f) << 16) | ($var[1] << 8) | $var[0];
+
+$var = 2 / 3 * 10 / 2 + 2;
+
+$var = (($var / $var) * $var - $var / 2) * call($var);
+$var = (($var / $var) * $var - $var / 2) * call($var);
+
+$var = $var % 10 - 5;
+$var = $var * $var % 10;
+$var = $var % 10 > 5;
+$var = $var % 10 == 0;
+
+$var = $var + $var / $var;
+$var = $var / $var + $var;
+
+$var = $var * $var % $var;
+$var = $var / $var % $var;
+$var = $var % $var * $var;
+$var = $var % $var / $var;
+
+$var = $var % $var % $var;
+
+$var = $var << $var >> $var;
+$var = $var >> $var << $var;
+$var = $var >> $var >> $var;
+$var = $var + $var >> $var;
+$var = ($var + $var) >> $var;
+$var = $var + ($var >> $var);
+
+$var = $var | $var & $var;
+$var = $var & $var | $var;
+$var = $var ^ $var ^ $var;
+$var = $var & $var & $var;
+$var = $var | $var | $var;
+$var = $var & $var >> $var;
+$var = $var << $var | $var;
+
+$var = $var ? 'foo' : 'bar' . 'test';
+$var = ($var ? 'foo' : 'bar') . 'test';
+$var = $var ? 'foo' : ('bar' . 'test');
+
+call(($var + $var));
+
+$var = call(($var + $var));
+
+$var = $var + $var ** 2;
+$var = ($var + $var) ** 2;
+$var = $var + ($var ** 2);
+$var = (+$var) ** 2;
+$var = +$var ** 2;
+
+$var = $foo instanceof Foo;
+$var = $foo instanceof Foo || $foo instanceof Foo;
+$var = ($foo instanceof Foo) || ($foo instanceof Foo);
+$var = (($foo) instanceof Foo);
+
+$var = !$var;
+$var = !($var);
+$var = (!($var));
+$var = !!$var;
+$var = !!($var);
+$var = !(!($var));
+$var = (!(!($var)));
+$var = !!!$var;
+$var = !!!($var);
+$var = !!(!($var));
+$var = !(!(!($var)));
+$var = (!(!(!($var))));
+
+$var = !$var || !$var;
+$var = (!($var) || !($var));
+$var = !(!($var) || !($var));
+
+$var = $var + $var * $var;
+$var = ($var + $var) * $var;
+
+$var = @foo() || @foo();
+$var = @(foo() || foo());
+
+($var += ($var += ($var += $var)));
+($var -= ($var -= ($var -= $var)));
+($var *= ($var *= ($var *= $var)));
+($var **= ($var **= ($var **= $var)));
+($var /= ($var /= ($var /= $var)));
+($var .= ($var .= ($var .= $var)));
+($var %= ($var %= ($var %= $var)));
+($var &= ($var &= ($var &= $var)));
+($var |= ($var |= ($var |= $var)));
+($var ^= ($var ^= ($var ^= $var)));
+($var <<= ($var <<= ($var <<= $var)));
+($var >>= ($var >>= ($var >>= $var)));
+
+$var = $var | $var | $var;
+$var = $var | ($var | $var);
+$var = ($var | $var) | $var;
+$var = $var & $var & $var;
+$var = $var & ($var & $var);
+$var = ($var & $var) & $var;
+
+$var = $var ^ $var | $var;
+$var = ($var ^ $var) | $var;
+$var = $var | $var ^ $var;
+$var = $var | ($var ^ $var);
+$var = ($var | $var) ^ $var;
+
+$var = $var & $var | $var;
+$var = ($var & $var) | $var;
+$var = $var | $var & $var;
+$var = $var | ($var & $var);
+$var = ($var | $var) & $var;
+
+$var = $var == $var || false;
+$var = ($var == $var) || false;
+$var = $var == ($var || false);
+
+$var = false || $var == $var;
+$var = false || ($var == $var);
+$var = ($var || false) == $var;
+
+$var = 'string' . true ? '1' : '2';
+$var = 'string' . (true ? '1' : '2');
+
+$var = 'string' . (100 + 100);
+$var = (100 + 100) . 'string';
+$var = 'string' . ($var || 100);
+$var = ($var || 100) . 'string';
+$var = 'string' . ($var * 100);
+$var = ($var * 100) . 'string';
+$var = 'string' . !$var;
+$var = !$var . 'string';
+$var = 'string' . ($var | 100);
+$var = ($var | 100) . 'string';
+
+$var = $var . $var % $var;
+$var = ($var . $var) % $var;
+$var = $var % $var . $var;
+$var = $var % ($var . $var);
+
+$var = '100' - '100' - '100';
+$var = ('100' - '100') - '100';
+$var = '100' - ('100' - '100');
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -420,11 +609,11 @@ $var = '10' . '20' . '30';
 $var = '10' . '20' . '30';
 $var = '10' . ('20' . '30');
 
-$var = 10 + 20 % 30;
+$var = 10 + (20 % 30);
 $var = (10 + 20) % 30;
 $var = 10 + (20 % 30);
 
-$var = 10 ** 20 ** 30;
+$var = 10 ** (20 ** 30);
 $var = (10 ** 20) ** 30;
 $var = 10 ** (20 ** 30);
 
@@ -434,23 +623,23 @@ $var = 10 == (20 == 30);
 $var = (10 === 20) === 30;
 $var = 10 === (20 === 30);
 
-$var = 10 * 20 % 30;
+$var = (10 * 20) % 30;
 $var = (10 * 20) % 30;
 $var = 10 * (20 % 30);
 
-$var = 10 * 20 / 30;
+$var = (10 * 20) / 30;
 $var = (10 * 20) / 30;
 $var = 10 * (20 / 30);
 
-$var = 10 / 20 * 30;
+$var = (10 / 20) * 30;
 $var = (10 / 20) * 30;
 $var = 10 / (20 * 30);
 
-$var = 10 << 20 << 30;
+$var = (10 << 20) << 30;
 $var = (10 << 20) << 30;
 $var = 10 << (20 << 30);
 
-$var = 10 >> 20 >> 30;
+$var = (10 >> 20) >> 30;
 $var = (10 >> 20) >> 30;
 $var = 10 >> (20 >> 30);
 
@@ -463,14 +652,204 @@ $var = 10 | 20 | 30;
 $var = 10 | (20 | 30);
 
 $var = false || true;
-$var = (false || true);
+$var = false || true;
 ($var = false) or true;
 $var = (false or true);
 $var = true && false;
-$var = (true && false);
+$var = true && false;
 ($var = true) and false;
 $var = (true and false);
 
+$var = $var || $var();
+$var = ($var || $var)();
+$var = $var && $var();
+$var = ($var && $var)();
+$var = call($var || $var);
+$var = call($var || $var);
+$var = call($var && $var);
+$var = call($var && $var);
+
+$var = +($var || $var);
+$var = -($var || $var);
+$var = ~($var || $var);
+
+$var = ($var || $var)->foo;
+$var = ($var || $var)->foo();
+$var = ($var || $var)[1];
+
+$var = $var || ($var && $var);
+$var = ($var || $var) && $var;
+$var = $var || ($var && $var);
+
+$var = $var & ($var || 'test');
+$var = ($var || 'test') & $var;
+$var = $var & ($var . 'test');
+$var = ($var . 'test') & $var;
+$var = $var & $var || 'test';
+$var = $var || 'test' & $var;
+
+$var = ($var || $var) % 100;
+$var = ($var + $var) % 100;
+$var = 100 % ($var || $var);
+$var = 100 % ($var + $var);
+$var = $var || $var % 100;
+$var = $var + ($var % 100);
+$var = 100 % $var || $var;
+$var = (100 % $var) + $var;
+
+$var = $var + $var >> 1;
+$var = ($var - 1 >> $var) & $var;
+$var = $var > $var ? 0 : $var - $var >> $var;
+$var = ($var - $var >> $var) + 1;
+
+if ($var < 1 << $var + $var) {
+}
+
+$var = $var < $var ? 0 : ($var - 1 >> $var) << $var;
+$var = 1 - 2 * ($var[3] >> 7);
+$var = ((($var[3] << 1) & 0xff) | ($var[2] >> 7)) - 127;
+$var = (($var[2] & 0x7f) << 16) | ($var[1] << 8) | $var[0];
+
+$var = ((2 / 3) * 10) / 2 + 2;
+
+$var = (($var / $var) * $var - $var / 2) * call($var);
+$var = (($var / $var) * $var - $var / 2) * call($var);
+
+$var = ($var % 10) - 5;
+$var = ($var * $var) % 10;
+$var = $var % 10 > 5;
+$var = $var % 10 == 0;
+
+$var = $var + $var / $var;
+$var = $var / $var + $var;
+
+$var = ($var * $var) % $var;
+$var = ($var / $var) % $var;
+$var = ($var % $var) * $var;
+$var = ($var % $var) / $var;
+
+$var = ($var % $var) % $var;
+
+$var = ($var << $var) >> $var;
+$var = ($var >> $var) << $var;
+$var = ($var >> $var) >> $var;
+$var = $var + $var >> $var;
+$var = $var + $var >> $var;
+$var = $var + ($var >> $var);
+
+$var = $var | ($var & $var);
+$var = ($var & $var) | $var;
+$var = $var ^ $var ^ $var;
+$var = $var & $var & $var;
+$var = $var | $var | $var;
+$var = $var & ($var >> $var);
+$var = ($var << $var) | $var;
+
+$var = $var ? 'foo' : 'bar' . 'test';
+$var = ($var ? 'foo' : 'bar') . 'test';
+$var = $var ? 'foo' : 'bar' . 'test';
+
+call($var + $var);
+
+$var = call($var + $var);
+
+$var = $var + $var ** 2;
+$var = ($var + $var) ** 2;
+$var = $var + $var ** 2;
+$var = (+$var) ** 2;
+$var = (+$var) ** 2;
+
+$var = $foo instanceof Foo;
+$var = $foo instanceof Foo || $foo instanceof Foo;
+$var = $foo instanceof Foo || $foo instanceof Foo;
+$var = $foo instanceof Foo;
+
+$var = !$var;
+$var = !$var;
+$var = !$var;
+$var = !!$var;
+$var = !!$var;
+$var = !!$var;
+$var = !!$var;
+$var = !!!$var;
+$var = !!!$var;
+$var = !!!$var;
+$var = !!!$var;
+$var = !!!$var;
+
+$var = !$var || !$var;
+$var = !$var || !$var;
+$var = !(!$var || !$var);
+
+$var = $var + $var * $var;
+$var = ($var + $var) * $var;
+
+$var = @(foo() || @foo());
+$var = @(foo() || foo());
+
+$var += $var += $var += $var;
+$var -= $var -= $var -= $var;
+$var *= $var *= $var *= $var;
+$var **= $var **= $var **= $var;
+$var /= $var /= $var /= $var;
+$var .= $var .= $var .= $var;
+$var %= $var %= $var %= $var;
+$var &= $var &= $var &= $var;
+$var |= $var |= $var |= $var;
+$var ^= $var ^= $var ^= $var;
+$var <<= $var <<= $var <<= $var;
+$var >>= $var >>= $var >>= $var;
+
+$var = $var | $var | $var;
+$var = $var | ($var | $var);
+$var = $var | $var | $var;
+$var = $var & $var & $var;
+$var = $var & ($var & $var);
+$var = $var & $var & $var;
+
+$var = ($var ^ $var) | $var;
+$var = ($var ^ $var) | $var;
+$var = $var | ($var ^ $var);
+$var = $var | ($var ^ $var);
+$var = ($var | $var) ^ $var;
+
+$var = ($var & $var) | $var;
+$var = ($var & $var) | $var;
+$var = $var | ($var & $var);
+$var = $var | ($var & $var);
+$var = ($var | $var) & $var;
+
+$var = $var == $var || false;
+$var = $var == $var || false;
+$var = $var == ($var || false);
+
+$var = false || $var == $var;
+$var = false || $var == $var;
+$var = ($var || false) == $var;
+
+$var = 'string' . true ? '1' : '2';
+$var = 'string' . (true ? '1' : '2');
+
+$var = 'string' . (100 + 100);
+$var = 100 + 100 . 'string';
+$var = 'string' . ($var || 100);
+$var = ($var || 100) . 'string';
+$var = 'string' . $var * 100;
+$var = $var * 100 . 'string';
+$var = 'string' . !$var;
+$var = !$var . 'string';
+$var = 'string' . ($var | 100);
+$var = ($var | 100) . 'string';
+
+$var = $var . $var % $var;
+$var = ($var . $var) % $var;
+$var = $var % $var . $var;
+$var = $var % ($var . $var);
+
+$var = '100' - '100' - '100';
+$var = '100' - '100' - '100';
+$var = '100' - ('100' - '100');
+
 `;
 
 exports[`block.php 1`] = `
@@ -701,7 +1080,7 @@ $var = ((int) $raw['data']) + $value;
 $var = (bool) ($var ? 1 : 2);
 $var = (bool) ($var + 1 ? 1 : 2);
 $var = ((bool) $var) + 1 ? 1 : 2;
-$var = (bool) (($var + 1) ? 1 : 2);
+$var = (bool) ($var + 1 ? 1 : 2);
 $var = (bool) $var ? 1 : 2;
 $var = (bool) $var ? (bool) 1 : (bool) 2;
 $var = (bool) $var ? (bool) 1 : (bool) 2;
@@ -824,51 +1203,25 @@ var_dump(...(function() use ($type) {})());
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
-(function () {
-})();
+(function () {})();
 
-$var = function () {
-};
-$var = function () {
-};
-$var = (function () {
-})();
-$var = (function () {
-})()();
-$func = static function () {
-};
-$func = static function () {
-};
+$var = function () {};
+$var = function () {};
+$var = (function () {})();
+$var = (function () {})()();
+$func = static function () {};
+$func = static function () {};
 
 function foo()
 {
-    $var = function () {
-    };
-    $var = (function () {
-    })();
+    $var = function () {};
+    $var = (function () {})();
 }
 
-call(
-    function () {
-    },
-    function () {
-    },
-    function () {
-    }
-);
-call(
-    function () {
-    },
-    function () {
-    },
-    function () {
-    }
-);
+call(function () {}, function () {}, function () {});
+call(function () {}, function () {}, function () {});
 
-var_dump(
-    ...(function () use ($type) {
-    })()
-);
+var_dump(...(function () use ($type) {})());
 
 `;
 
@@ -1055,6 +1408,90 @@ $a->c();
 
 `;
 
+exports[`echo.php 1`] = `
+<?php
+
+echo "Hello World";
+echo ("Hello World");
+
+echo "Sum: ", 1 + 2;
+echo "Hello ", isset($name) ? $name : "John Doe", "!";
+echo "Hello ", (isset($name) ? $name : "John Doe"), "!";
+
+echo 'Sum: ' . (1 + 2);
+echo 'Hello ' . isset($name) ? $name : 'John Doe' . '!';
+echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!';
+
+echo $some_var ? 'true': 'false';
+echo ($some_var ? 'true': 'false');
+
+echo 'This ', 'string ', 'was ', 'made ', 'with multiple parameters.', chr(10);
+echo ('This '), ('string '), ('was '), ('made '), ('with multiple parameters.'), (chr(10));
+echo 'This ' . 'string ' . 'was ' . 'made ' . 'with concatenation.' . "\\n";
+echo ('This ') . ('string ') . ('was ') . ('made ') . ('with concatenation.') . ("\\n");
+
+echo <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon. no extra whitespace!
+END;
+
+echo (<<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon. no extra whitespace!
+END
+);
+
+echo (function () { return 'test'; })();
+echo ((function () { return 'test'; })());
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+
+echo "Hello World";
+echo "Hello World";
+
+echo "Sum: ", 1 + 2;
+echo "Hello ", isset($name) ? $name : "John Doe", "!";
+echo "Hello ", isset($name) ? $name : "John Doe", "!";
+
+echo 'Sum: ' . (1 + 2);
+echo 'Hello ' . isset($name) ? $name : 'John Doe' . '!';
+echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!';
+
+echo $some_var ? 'true' : 'false';
+echo $some_var ? 'true' : 'false';
+
+echo 'This ', 'string ', 'was ', 'made ', 'with multiple parameters.', chr(10);
+echo 'This ', 'string ', 'was ', 'made ', 'with multiple parameters.', chr(10);
+echo 'This ' . 'string ' . 'was ' . 'made ' . 'with concatenation.' . "\\n";
+echo 'This ' . 'string ' . 'was ' . 'made ' . 'with concatenation.' . "\\n";
+
+echo <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon. no extra whitespace!
+END;
+
+echo <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon. no extra whitespace!
+END;
+
+echo (function () {
+    return 'test';
+})();
+echo (function () {
+    return 'test';
+})();
+
+`;
+
 exports[`empty.php 1`] = `
 <?php
 
@@ -1143,6 +1580,82 @@ call(exit(1));
 
 `;
 
+exports[`include.php 1`] = `
+<?php
+
+include 'foo.php';
+(include 'foo.php');
+
+include $var;
+(include $var);
+(include ($var));
+
+$var = include 'foo.php';
+$var = (include 'foo.php');
+$var = include $var;
+$var = (include $var);
+$var = (include ($var));
+
+function foo() {
+    include 'foo.php';
+    (include 'foo.php');
+}
+
+if (include('vars.php') == TRUE) {}
+if ((include 'vars.php') == TRUE) {}
+
+include $path . 'example-config-file.php';
+include ($path) . ('example-config-file.php');
+include (($path) . ('example-config-file.php'));
+
+include __DIR__ . '/../src/includeFile.php';
+include (__DIR__) . ('/../src/includeFile.php');
+include ((__DIR__) . ('/../src/includeFile.php'));
+
+include(dirname(dirname(__FILE__)) . '/prepend.php');
+
+include ($_GET['id'].".php");
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+
+include 'foo.php';
+include 'foo.php';
+
+include $var;
+include $var;
+include $var;
+
+$var = include 'foo.php';
+$var = include 'foo.php';
+$var = include $var;
+$var = include $var;
+$var = include $var;
+
+function foo()
+{
+    include 'foo.php';
+    include 'foo.php';
+}
+
+if (include 'vars.php' == true) {
+}
+if ((include 'vars.php') == true) {
+}
+
+include $path . 'example-config-file.php';
+include $path . 'example-config-file.php';
+include $path . 'example-config-file.php';
+
+include __DIR__ . '/../src/includeFile.php';
+include __DIR__ . '/../src/includeFile.php';
+include __DIR__ . '/../src/includeFile.php';
+
+include dirname(dirname(__FILE__)) . '/prepend.php';
+
+include $_GET['id'] . ".php";
+
+`;
+
 exports[`isset.php 1`] = `
 <?php
 
@@ -1551,6 +2064,98 @@ $var = call(--$var->_uuidCounter);
 
 `;
 
+exports[`print.php 1`] = `
+<?php
+
+print("Hello World");
+(print("Hello World"));
+
+print "print() also works without parentheses.";
+
+print "This spans
+multiple lines. The newlines will be
+output as well";
+(print "This spans
+multiple lines. The newlines will be
+output as well");
+
+print <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon no extra whitespace!
+END;
+
+print (<<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon no extra whitespace!
+END
+);
+
+if (print("foo") && print("bar")) {
+}
+
+if ((print("foo")) && (print("bar"))) {
+}
+
+$var = $var ? print "$string_message<br />" : print "$string_message\\n";
+$var = $var ? (print "$string_message<br />") : (print "$string_message\\n");
+$var = $var ? (print ("$string_message<br />")) : (print ("$string_message\\n"));
+
+print 1 . print(2) + 3; // 511
+print 1 . (print(2)) + 3; // 214
+
+print ($var || $var) && $var;
+print (($var || $var) && $var);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+
+print "Hello World";
+print "Hello World";
+
+print "print() also works without parentheses.";
+
+print "This spans
+multiple lines. The newlines will be
+output as well";
+print "This spans
+multiple lines. The newlines will be
+output as well";
+
+print <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon no extra whitespace!
+END;
+
+print <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon no extra whitespace!
+END;
+
+if (print "foo" && (print "bar")) {
+}
+
+if ((print "foo") && (print "bar")) {
+}
+
+$var = $var ? print "$string_message<br />" : print "$string_message\\n";
+$var = $var ? print "$string_message<br />" : print "$string_message\\n";
+$var = $var ? print "$string_message<br />" : print "$string_message\\n";
+
+print 1 . (print 2 + 3); // 511
+print 1 . (print 2) + 3; // 214
+
+print ($var || $var) && $var;
+print ($var || $var) && $var;
+
+`;
+
 exports[`program.php 1`] = `
 <?php
 
@@ -1606,6 +2211,7 @@ $var = +($var ? 1 : 2);
 $var = +(+$var ? 1 : 2);
 $var = +($var++ ? 1 : 2);
 $var = ((true ? 'true' : false) ? (true ? 'true' : false) : (true ? 'true' : false));
+$var = $var ? $var1 ? 1 : 2 : $var2 ? 3 : 4;
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -1648,12 +2254,21 @@ $var[
 ]->map();
 
 $var = $var . $var ? "()" : "";
-$var = ($var . $var) ? "()" : "";
+$var = $var . $var ? "()" : "";
 $var = $var . ($var ? "()" : "");
 $var = +($var ? 1 : 2);
 $var = +(+$var ? 1 : 2);
 $var = +($var++ ? 1 : 2);
-$var = (true ? 'true' : false) ? true ? 'true' : false : true ? 'true' : false;
+$var = (true
+        ? 'true'
+        : false)
+    ? (true
+        ? 'true'
+        : false)
+    : (true
+        ? 'true'
+        : false);
+$var = ($var ? ($var1 ? 1 : 2) : $var2) ? 3 : 4;
 
 `;
 
@@ -1683,7 +2298,7 @@ return (
     'veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString'
 );
 return $var1 + $var2;
-return $var ? $var1 ? 1 : 2 : $var2 ? 3 : 4;
+return $var ? ($var1 ? 1 : 2) : ($var2 ? 3 : 4);
 return 'veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString'
     ? 'veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString'
     : 'veryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString';
@@ -1711,6 +2326,45 @@ $var = @foo();
 
 `;
 
+exports[`throw.php 1`] = `
+<?php
+
+throw new Exception('Division by zero.');
+throw (new Exception('Division by zero.'));
+throw $e;
+throw ($e);
+throw new \\Exception("Bye");
+throw (new \\Exception("Bye"));
+
+if (!$var) {
+    throw new Exception('Division by zero.');
+    throw (new Exception('Division by zero.'));
+    throw $e;
+    throw ($e);
+    throw new \\Exception("Bye");
+    throw (new \\Exception("Bye"));
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+
+throw new Exception('Division by zero.');
+throw new Exception('Division by zero.');
+throw $e;
+throw $e;
+throw new \\Exception("Bye");
+throw new \\Exception("Bye");
+
+if (!$var) {
+    throw new Exception('Division by zero.');
+    throw new Exception('Division by zero.');
+    throw $e;
+    throw $e;
+    throw new \\Exception("Bye");
+    throw new \\Exception("Bye");
+}
+
+`;
+
 exports[`unary.php 1`] = `
 <?php
 
@@ -1818,7 +2472,7 @@ $var = +$foo->bar;
 
 $var = +$var || +$var;
 $var = +$var || +$var;
-$var = (+$var || +$var);
+$var = +$var || +$var;
 
 $var = -+$var;
 
diff --git a/tests/parens/bin.php b/tests/parens/bin.php
index 03b6c99..311ac1f 100644
--- a/tests/parens/bin.php
+++ b/tests/parens/bin.php
@@ -89,3 +89,192 @@ $var = true && false;
 $var = (true && false);
 $var = true and false;
 $var = (true and false);
+
+$var = $var || $var();
+$var = ($var || $var)();
+$var = $var && $var();
+$var = ($var && $var)();
+$var = call($var || $var);
+$var = call(($var || $var));
+$var = call($var && $var);
+$var = call(($var && $var));
+
+$var = +($var || $var);
+$var = -($var || $var);
+$var = ~($var || $var);
+
+$var = ($var || $var)->foo;
+$var = ($var || $var)->foo();
+$var = ($var || $var)[1];
+
+$var = $var || $var && $var;
+$var = ($var || $var) && $var;
+$var = $var || ($var && $var);
+
+$var = $var & ($var || 'test');
+$var = ($var || 'test') & $var;
+$var = $var & ($var . 'test');
+$var = ($var . 'test') & $var;
+$var = ($var & $var) || 'test';
+$var = $var || ('test' & $var);
+
+$var = ($var || $var) % 100;
+$var = ($var + $var) % 100;
+$var = 100 % ($var || $var);
+$var = 100 % ($var + $var);
+$var = $var || ($var % 100);
+$var = $var + ($var % 100);
+$var = (100 % $var) || $var;
+$var = (100 % $var) + $var;
+
+$var = ($var + $var) >> 1;
+$var = (($var - 1) >> $var) & $var;
+$var = $var > $var ? 0 : ($var - $var) >> $var;
+$var = (($var - $var) >> $var) + 1;
+
+if ($var < 1 << ($var + $var)) {}
+
+$var = $var < $var ? 0 : ((($var - 1) >> $var) << $var);
+$var = 1 - (2 * ($var[3] >> 7));
+$var = ((($var[3] << 1) & 0xff) | ($var[2] >> 7)) - 127;
+$var = (($var[2] & 0x7f) << 16) | ($var[1] << 8) | $var[0];
+
+$var = 2 / 3 * 10 / 2 + 2;
+
+$var = (($var / $var) * $var - $var / 2) * call($var);
+$var = (($var / $var) * $var - $var / 2) * call($var);
+
+$var = $var % 10 - 5;
+$var = $var * $var % 10;
+$var = $var % 10 > 5;
+$var = $var % 10 == 0;
+
+$var = $var + $var / $var;
+$var = $var / $var + $var;
+
+$var = $var * $var % $var;
+$var = $var / $var % $var;
+$var = $var % $var * $var;
+$var = $var % $var / $var;
+
+$var = $var % $var % $var;
+
+$var = $var << $var >> $var;
+$var = $var >> $var << $var;
+$var = $var >> $var >> $var;
+$var = $var + $var >> $var;
+$var = ($var + $var) >> $var;
+$var = $var + ($var >> $var);
+
+$var = $var | $var & $var;
+$var = $var & $var | $var;
+$var = $var ^ $var ^ $var;
+$var = $var & $var & $var;
+$var = $var | $var | $var;
+$var = $var & $var >> $var;
+$var = $var << $var | $var;
+
+$var = $var ? 'foo' : 'bar' . 'test';
+$var = ($var ? 'foo' : 'bar') . 'test';
+$var = $var ? 'foo' : ('bar' . 'test');
+
+call(($var + $var));
+
+$var = call(($var + $var));
+
+$var = $var + $var ** 2;
+$var = ($var + $var) ** 2;
+$var = $var + ($var ** 2);
+$var = (+$var) ** 2;
+$var = +$var ** 2;
+
+$var = $foo instanceof Foo;
+$var = $foo instanceof Foo || $foo instanceof Foo;
+$var = ($foo instanceof Foo) || ($foo instanceof Foo);
+$var = (($foo) instanceof Foo);
+
+$var = !$var;
+$var = !($var);
+$var = (!($var));
+$var = !!$var;
+$var = !!($var);
+$var = !(!($var));
+$var = (!(!($var)));
+$var = !!!$var;
+$var = !!!($var);
+$var = !!(!($var));
+$var = !(!(!($var)));
+$var = (!(!(!($var))));
+
+$var = !$var || !$var;
+$var = (!($var) || !($var));
+$var = !(!($var) || !($var));
+
+$var = $var + $var * $var;
+$var = ($var + $var) * $var;
+
+$var = @foo() || @foo();
+$var = @(foo() || foo());
+
+($var += ($var += ($var += $var)));
+($var -= ($var -= ($var -= $var)));
+($var *= ($var *= ($var *= $var)));
+($var **= ($var **= ($var **= $var)));
+($var /= ($var /= ($var /= $var)));
+($var .= ($var .= ($var .= $var)));
+($var %= ($var %= ($var %= $var)));
+($var &= ($var &= ($var &= $var)));
+($var |= ($var |= ($var |= $var)));
+($var ^= ($var ^= ($var ^= $var)));
+($var <<= ($var <<= ($var <<= $var)));
+($var >>= ($var >>= ($var >>= $var)));
+
+$var = $var | $var | $var;
+$var = $var | ($var | $var);
+$var = ($var | $var) | $var;
+$var = $var & $var & $var;
+$var = $var & ($var & $var);
+$var = ($var & $var) & $var;
+
+$var = $var ^ $var | $var;
+$var = ($var ^ $var) | $var;
+$var = $var | $var ^ $var;
+$var = $var | ($var ^ $var);
+$var = ($var | $var) ^ $var;
+
+$var = $var & $var | $var;
+$var = ($var & $var) | $var;
+$var = $var | $var & $var;
+$var = $var | ($var & $var);
+$var = ($var | $var) & $var;
+
+$var = $var == $var || false;
+$var = ($var == $var) || false;
+$var = $var == ($var || false);
+
+$var = false || $var == $var;
+$var = false || ($var == $var);
+$var = ($var || false) == $var;
+
+$var = 'string' . true ? '1' : '2';
+$var = 'string' . (true ? '1' : '2');
+
+$var = 'string' . (100 + 100);
+$var = (100 + 100) . 'string';
+$var = 'string' . ($var || 100);
+$var = ($var || 100) . 'string';
+$var = 'string' . ($var * 100);
+$var = ($var * 100) . 'string';
+$var = 'string' . !$var;
+$var = !$var . 'string';
+$var = 'string' . ($var | 100);
+$var = ($var | 100) . 'string';
+
+$var = $var . $var % $var;
+$var = ($var . $var) % $var;
+$var = $var % $var . $var;
+$var = $var % ($var . $var);
+
+$var = '100' - '100' - '100';
+$var = ('100' - '100') - '100';
+$var = '100' - ('100' - '100');
diff --git a/tests/parens/echo.php b/tests/parens/echo.php
new file mode 100644
index 0000000..1de4fcc
--- /dev/null
+++ b/tests/parens/echo.php
@@ -0,0 +1,38 @@
+<?php
+
+echo "Hello World";
+echo ("Hello World");
+
+echo "Sum: ", 1 + 2;
+echo "Hello ", isset($name) ? $name : "John Doe", "!";
+echo "Hello ", (isset($name) ? $name : "John Doe"), "!";
+
+echo 'Sum: ' . (1 + 2);
+echo 'Hello ' . isset($name) ? $name : 'John Doe' . '!';
+echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!';
+
+echo $some_var ? 'true': 'false';
+echo ($some_var ? 'true': 'false');
+
+echo 'This ', 'string ', 'was ', 'made ', 'with multiple parameters.', chr(10);
+echo ('This '), ('string '), ('was '), ('made '), ('with multiple parameters.'), (chr(10));
+echo 'This ' . 'string ' . 'was ' . 'made ' . 'with concatenation.' . "\n";
+echo ('This ') . ('string ') . ('was ') . ('made ') . ('with concatenation.') . ("\n");
+
+echo <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon. no extra whitespace!
+END;
+
+echo (<<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon. no extra whitespace!
+END
+);
+
+echo (function () { return 'test'; })();
+echo ((function () { return 'test'; })());
diff --git a/tests/parens/include.php b/tests/parens/include.php
new file mode 100644
index 0000000..aa8f45c
--- /dev/null
+++ b/tests/parens/include.php
@@ -0,0 +1,34 @@
+<?php
+
+include 'foo.php';
+(include 'foo.php');
+
+include $var;
+(include $var);
+(include ($var));
+
+$var = include 'foo.php';
+$var = (include 'foo.php');
+$var = include $var;
+$var = (include $var);
+$var = (include ($var));
+
+function foo() {
+    include 'foo.php';
+    (include 'foo.php');
+}
+
+if (include('vars.php') == TRUE) {}
+if ((include 'vars.php') == TRUE) {}
+
+include $path . 'example-config-file.php';
+include ($path) . ('example-config-file.php');
+include (($path) . ('example-config-file.php'));
+
+include __DIR__ . '/../src/includeFile.php';
+include (__DIR__) . ('/../src/includeFile.php');
+include ((__DIR__) . ('/../src/includeFile.php'));
+
+include(dirname(dirname(__FILE__)) . '/prepend.php');
+
+include ($_GET['id'].".php");
diff --git a/tests/parens/print.php b/tests/parens/print.php
new file mode 100644
index 0000000..1651f0a
--- /dev/null
+++ b/tests/parens/print.php
@@ -0,0 +1,44 @@
+<?php
+
+print("Hello World");
+(print("Hello World"));
+
+print "print() also works without parentheses.";
+
+print "This spans
+multiple lines. The newlines will be
+output as well";
+(print "This spans
+multiple lines. The newlines will be
+output as well");
+
+print <<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon no extra whitespace!
+END;
+
+print (<<<END
+This uses the "here document" syntax to output
+multiple lines with $variable interpolation. Note
+that the here document terminator must appear on a
+line with just a semicolon no extra whitespace!
+END
+);
+
+if (print("foo") && print("bar")) {
+}
+
+if ((print("foo")) && (print("bar"))) {
+}
+
+$var = $var ? print "$string_message<br />" : print "$string_message\n";
+$var = $var ? (print "$string_message<br />") : (print "$string_message\n");
+$var = $var ? (print ("$string_message<br />")) : (print ("$string_message\n"));
+
+print 1 . print(2) + 3; // 511
+print 1 . (print(2)) + 3; // 214
+
+print ($var || $var) && $var;
+print (($var || $var) && $var);
diff --git a/tests/parens/retif.php b/tests/parens/retif.php
index 84861e8..418e6a3 100644
--- a/tests/parens/retif.php
+++ b/tests/parens/retif.php
@@ -41,3 +41,4 @@ $var = +($var ? 1 : 2);
 $var = +(+$var ? 1 : 2);
 $var = +($var++ ? 1 : 2);
 $var = ((true ? 'true' : false) ? (true ? 'true' : false) : (true ? 'true' : false));
+$var = $var ? $var1 ? 1 : 2 : $var2 ? 3 : 4;
diff --git a/tests/parens/throw.php b/tests/parens/throw.php
new file mode 100644
index 0000000..004add3
--- /dev/null
+++ b/tests/parens/throw.php
@@ -0,0 +1,17 @@
+<?php
+
+throw new Exception('Division by zero.');
+throw (new Exception('Division by zero.'));
+throw $e;
+throw ($e);
+throw new \Exception("Bye");
+throw (new \Exception("Bye"));
+
+if (!$var) {
+    throw new Exception('Division by zero.');
+    throw (new Exception('Division by zero.'));
+    throw $e;
+    throw ($e);
+    throw new \Exception("Bye");
+    throw (new \Exception("Bye"));
+}
diff --git a/tests/retif/__snapshots__/jsfmt.spec.js.snap b/tests/retif/__snapshots__/jsfmt.spec.js.snap
index 5efeb9a..25d37ec 100644
--- a/tests/retif/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/retif/__snapshots__/jsfmt.spec.js.snap
@@ -72,12 +72,12 @@ $arr = [
 <?php
 
 return true ? 1 : 2;
-return ($testReallyReallyLong >= 1)
+return $testReallyReallyLong >= 1
     ? $someOtherReallyReallyLongVariable
     : $thisOtherVariable;
 return true ?: 2;
-return ($testReallyReallyLong === $someOtherReallyReallyLongVariable &&
-    $otherTest != $someOtherTest)
+return $testReallyReallyLong === $someOtherReallyReallyLongVariable &&
+    $otherTest != $someOtherTest
     ? 1
     : 0;
 
@@ -90,26 +90,26 @@ $category_color = get_field(Category_Meta::COLOR, 'category_' . $term_id)
     ?: 'gold';
 
 $var = ($someOtherReallyReallyLongVariable
-        ? $someOtherReallyReallyLongVariable
+        ? ($someOtherReallyReallyLongVariable
             ? $someOtherReallyReallyLongVariable
-            : $someOtherReallyReallyLongVariable
+            : $someOtherReallyReallyLongVariable)
         : $someOtherReallyReallyLongVariable)
     ? $someOtherReallyReallyLongVariable
     : $someOtherReallyReallyLongVariable;
 $var = ($someOtherReallyReallyLongVariable
-        ? $someOtherReallyReallyLongVariable
+        ? ($someOtherReallyReallyLongVariable
             ? $someOtherReallyReallyLongVariable
-            : $someOtherReallyReallyLongVariable
+            : $someOtherReallyReallyLongVariable)
         : $someOtherReallyReallyLongVariable)
     ? $someOtherReallyReallyLongVariable
     : $someOtherReallyReallyLongVariable;
 $var = $someOtherReallyReallyLongVariable
-    ? $someOtherReallyReallyLongVariable
+    ? ($someOtherReallyReallyLongVariable
         ? $someOtherReallyReallyLongVariable
-        : $someOtherReallyReallyLongVariable
-    : $someOtherReallyReallyLongVariable
+        : $someOtherReallyReallyLongVariable)
+    : ($someOtherReallyReallyLongVariable
         ? $someOtherReallyReallyLongVariable
-        : $someOtherReallyReallyLongVariable;
+        : $someOtherReallyReallyLongVariable);
 $test = $foo
     ?: bar(
         $someOtherReallyReallyLongVariable,
@@ -117,7 +117,7 @@ $test = $foo
         $someOtherReallyReallyLongVariable
     );
 $test =
-    ($testReallyReallyReallyReallyReallyReallyLong >= 1)
+    $testReallyReallyReallyReallyReallyReallyLong >= 1
         ?: $someOtherReallyReallyReallyReallyReallyReallyLongVariable;
 $test = $foo ?: bar(['foo' => 'bar', 'bar' => 'foo']);
 $test = $foo
@@ -171,28 +171,28 @@ $var = 1
     ? $someOtherReallyReallyLongVariable
     : $someOtherReallyReallyLongVariable
 )->call();
-$var = $test ?: true ? 1 : 2;
+$var = $test ?: (true ? 1 : 2);
 $var = $test
-    ?: $someOtherReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariable
+    ?: ($someOtherReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariable
         ? 1
-        : 2;
+        : 2);
 $var = $test
-    ?: true
+    ?: (true
         ? $someOtherReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariable
-        : 2;
+        : 2);
 $var = $test
-    ?: true
+    ?: (true
         ? 1
-        : $someOtherReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariable;
+        : $someOtherReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariable);
 $var = $test
     ? 'string'
-    : $someOtherReallyReallyLongVariable
+    : ($someOtherReallyReallyLongVariable
         ? $someOtherReallyReallyLongVariable
-        : $someOtherReallyReallyLongVariable;
+        : $someOtherReallyReallyLongVariable);
 $var = $test
-    ? $someOtherReallyReallyLongVariable
+    ? ($someOtherReallyReallyLongVariable
         ? $someOtherReallyReallyLongVariable
-        : $someOtherReallyReallyLongVariable
+        : $someOtherReallyReallyLongVariable)
     : 'string';
 
 $arr = [
diff --git a/tests/return/__snapshots__/jsfmt.spec.js.snap b/tests/return/__snapshots__/jsfmt.spec.js.snap
index b6c5bdd..7df1e07 100644
--- a/tests/return/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/return/__snapshots__/jsfmt.spec.js.snap
@@ -83,6 +83,6 @@ return $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable
     ? true
     : false;
 return $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable->veryVeryVeryVeryVeryVeryLongProperty;
-return $true ? ('foo' . ('foo' . 'bar')) : "foobarfoo";
+return $true ? 'foo' . ('foo' . 'bar') : "foobarfoo";
 
 `;
diff --git a/tests/silent/__snapshots__/jsfmt.spec.js.snap b/tests/silent/__snapshots__/jsfmt.spec.js.snap
index 0a9695b..5c62c45 100644
--- a/tests/silent/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/silent/__snapshots__/jsfmt.spec.js.snap
@@ -18,8 +18,8 @@ $value = @     $cache[$key];
 <?php
 $variable = @foo();
 /* Intentional file error */
-$my_file = @file('non_existent_file') or
-    die("Failed opening file: error was '$php_errormsg'");
+$my_file = @(file('non_existent_file') or
+    die("Failed opening file: error was '$php_errormsg'"));
 
 // this works for any expression, not just functions:
 $value = @$cache[$key];