Repository: prettier/plugin-php
Pull request #489 (2018-07-23 19:40:22)

fix: binary cast
Also find bug in parser, todo and link in source code

From http://php.net/manual/en/language.types.type-juggling.php#language.types.typecasting


Patch:
diff --git a/src/printer.js b/src/printer.js
index 71abb53..4e65c3e 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -1032,6 +1032,7 @@ function printExpression(path, options, print) {
       case "unary":
         return concat([node.type, path.call(print, "what")]);
       case "cast":
+        // @TODO: binary type cast is broken https://github.com/glayzzle/php-parser/issues/166
         return concat(["(", node.type, ") ", path.call(print, "what")]);
       default:
         return `Have not implemented operation kind ${node.kind} yet.`;
@@ -1070,13 +1071,16 @@ function printExpression(path, options, print) {
         return node.value ? "true" : "false";
       case "string": {
         // @TODO: need resolve https://github.com/glayzzle/php-parser/issues/101
-        // @TODO: need resolve https://github.com/glayzzle/php-parser/issues/123
-        // @TODO: need resolve https://github.com/glayzzle/php-parser/issues/124
         // @TODO: for now just reusing double/single quote preference from doc. could eventually
         // use setting from options. need to figure out how this works w/ complex strings and interpolation
         // also need to figure out splitting long strings
         const quote = node.isDoubleQuote ? '"' : "'";
         let stringValue = node.raw;
+
+        if (node.raw[0] === "b") {
+          stringValue = stringValue.slice(1);
+        }
+
         // we need to strip out the quotes from the raw value
         if (['"', "'"].includes(stringValue[0])) {
           stringValue = stringValue.substr(1);
@@ -1084,7 +1088,10 @@ function printExpression(path, options, print) {
         if (['"', "'"].includes(stringValue[stringValue.length - 1])) {
           stringValue = stringValue.substr(0, stringValue.length - 1);
         }
-        return makeString(stringValue, quote, false);
+        return concat([
+          node.raw[0] === "b" ? "b" : "",
+          makeString(stringValue, quote, false)
+        ]);
       }
       case "number":
         return printNumber(node.value);
@@ -1333,12 +1340,18 @@ function printStatement(path, options, print) {
         return concat([
           "namespace ",
           hasName ? node.name : "",
-          node.withBrackets ? concat([" ", "{"]) : ";",
-          // don't know why we need 2 line breaks here, but 1 doesn't work
-          node.children.length > 0 && !node.withBrackets
-            ? concat([hardline, hardline])
+          node.withBrackets
+            ? " {"
+            : concat([
+                ";",
+                // Second hardline for newline between `namespace` and first child node
+                node.children.length > 0 ? concat([hardline, hardline]) : ""
+              ]),
+          node.children.length > 0
+            ? node.withBrackets
+              ? indent(concat([hardline, printed]))
+              : printed
             : "",
-          node.withBrackets ? indent(concat([hardline, printed])) : printed,
           node.withBrackets ? concat([hardline, "}"]) : ""
         ]);
       }


Test patch:
diff --git a/tests/cast/__snapshots__/jsfmt.spec.js.snap b/tests/cast/__snapshots__/jsfmt.spec.js.snap
index 4d5f96a..85e09ff 100644
--- a/tests/cast/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/cast/__snapshots__/jsfmt.spec.js.snap
@@ -16,6 +16,12 @@ $bar = (unset) $foo;
 
 $bar = ( int ) $foo;
 $bar = (  int  )  $foo;
+
+$binary = (binary) $string;
+$binary = b"binary string";
+$binary = b'binary string';
+$binary = "b'binary string'";
+$binary = 'b"binary string"';
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 $bar = (int) $foo;
@@ -32,4 +38,10 @@ $bar = (unset) $foo;
 $bar = (int) $foo;
 $bar = (int) $foo;
 
+$binary = (string) $string;
+$binary = b"binary string";
+$binary = b'binary string';
+$binary = "b'binary string'";
+$binary = 'b"binary string"';
+
 `;
diff --git a/tests/cast/cast.php b/tests/cast/cast.php
index f0738bc..7732a9c 100644
--- a/tests/cast/cast.php
+++ b/tests/cast/cast.php
@@ -13,3 +13,9 @@ $bar = (unset) $foo;
 
 $bar = ( int ) $foo;
 $bar = (  int  )  $foo;
+
+$binary = (binary) $string;
+$binary = b"binary string";
+$binary = b'binary string';
+$binary = "b'binary string'";
+$binary = 'b"binary string"';
diff --git a/tests/classconstant/__snapshots__/jsfmt.spec.js.snap b/tests/classconstant/__snapshots__/jsfmt.spec.js.snap
index c4c0ec6..6b66061 100644
--- a/tests/classconstant/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/classconstant/__snapshots__/jsfmt.spec.js.snap
@@ -5,12 +5,44 @@ exports[`classconstant.php 1`] = `
 class ConstDemo
 {
     const PUBLIC_CONST_A = 1;
+    const TEST_CLASS_CONSTANT = 3;
+    public const PUBLIC_TEST_CLASS_CONSTANT = 'value';
+    protected const PROTECTED_TEST_CLASS_CONSTANT = 'value';
+    private const PRIVATE_TEST_CLASS_CONSTANT = 'value';
+    public const THREE = TWO + 1;
+    public const ONE_THIRD = ONE / self::THREE;
+    public const SENTENCE = 'The value of THREE is ' . self::THREE;
+
+    public static function testClassConstant() {
+        return self::TEST_CLASS_CONSTANT;
+    }
+
+    public function f($a = ONE + self::THREE) {
+        return $a;
+    }
 }
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 class ConstDemo
 {
     const PUBLIC_CONST_A = 1;
+    const TEST_CLASS_CONSTANT = 3;
+    public const PUBLIC_TEST_CLASS_CONSTANT = 'value';
+    protected const PROTECTED_TEST_CLASS_CONSTANT = 'value';
+    private const PRIVATE_TEST_CLASS_CONSTANT = 'value';
+    public const THREE = TWO + 1;
+    public const ONE_THIRD = ONE / self::THREE;
+    public const SENTENCE = 'The value of THREE is ' . self::THREE;
+
+    public static function testClassConstant()
+    {
+        return self::TEST_CLASS_CONSTANT;
+    }
+
+    public function f($a = ONE + self::THREE)
+    {
+        return $a;
+    }
 }
 
 `;
diff --git a/tests/classconstant/classconstant.php b/tests/classconstant/classconstant.php
index 4feb9a6..e62d482 100644
--- a/tests/classconstant/classconstant.php
+++ b/tests/classconstant/classconstant.php
@@ -2,4 +2,19 @@
 class ConstDemo
 {
     const PUBLIC_CONST_A = 1;
+    const TEST_CLASS_CONSTANT = 3;
+    public const PUBLIC_TEST_CLASS_CONSTANT = 'value';
+    protected const PROTECTED_TEST_CLASS_CONSTANT = 'value';
+    private const PRIVATE_TEST_CLASS_CONSTANT = 'value';
+    public const THREE = TWO + 1;
+    public const ONE_THIRD = ONE / self::THREE;
+    public const SENTENCE = 'The value of THREE is ' . self::THREE;
+
+    public static function testClassConstant() {
+        return self::TEST_CLASS_CONSTANT;
+    }
+
+    public function f($a = ONE + self::THREE) {
+        return $a;
+    }
 }
diff --git a/tests/constant/__snapshots__/jsfmt.spec.js.snap b/tests/constant/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 0000000..3c98662
--- /dev/null
+++ b/tests/constant/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,24 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`constants.php 1`] = `
+<?php
+define("TEST_CONSTANT", 1);
+
+const OTHER_TEST_CONSTANT = 2;
+const ONE = 1;
+const TWO = ONE * 2;
+
+$test = TEST_CONSTANT;
+$test = OTHER_TEST_CONSTANT;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+define("TEST_CONSTANT", 1);
+
+const OTHER_TEST_CONSTANT = 2;
+const ONE = 1;
+const TWO = ONE * 2;
+
+$test = TEST_CONSTANT;
+$test = OTHER_TEST_CONSTANT;
+
+`;
diff --git a/tests/constant/constants.php b/tests/constant/constants.php
new file mode 100644
index 0000000..e675b32
--- /dev/null
+++ b/tests/constant/constants.php
@@ -0,0 +1,9 @@
+<?php
+define("TEST_CONSTANT", 1);
+
+const OTHER_TEST_CONSTANT = 2;
+const ONE = 1;
+const TWO = ONE * 2;
+
+$test = TEST_CONSTANT;
+$test = OTHER_TEST_CONSTANT;
diff --git a/tests/constants/jsfmt.spec.js b/tests/constant/jsfmt.spec.js
similarity index 100%
rename from tests/constants/jsfmt.spec.js
rename to tests/constant/jsfmt.spec.js
diff --git a/tests/constants/__snapshots__/jsfmt.spec.js.snap b/tests/constants/__snapshots__/jsfmt.spec.js.snap
deleted file mode 100644
index 6a253dc..0000000
--- a/tests/constants/__snapshots__/jsfmt.spec.js.snap
+++ /dev/null
@@ -1,61 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`constants.php 1`] = `
-<?php
-define("TEST_CONSTANT", 1);
-const OTHER_TEST_CONSTANT = 2;
-const ONE = 1;
-const TWO = ONE * 2;
-
-$test = TEST_CONSTANT;
-$test = OTHER_TEST_CONSTANT;
-
-class Constants {
-  const TEST_CLASS_CONSTANT = 3;
-  public const PUBLIC_TEST_CLASS_CONSTANT = 'value';
-  protected const PROTECTED_TEST_CLASS_CONSTANT = 'value';
-  private const PRIVATE_TEST_CLASS_CONSTANT = 'value';
-  public const THREE = TWO + 1;
-  public const ONE_THIRD = ONE / self::THREE;
-  public const SENTENCE = 'The value of THREE is ' . self::THREE;
-
-  public static function testClassConstant() {
-    return self::TEST_CLASS_CONSTANT;
-  }
-
-  public function f($a = ONE + self::THREE) {
-    return $a;
-  }
-}
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-<?php
-define("TEST_CONSTANT", 1);
-const OTHER_TEST_CONSTANT = 2;
-const ONE = 1;
-const TWO = ONE * 2;
-
-$test = TEST_CONSTANT;
-$test = OTHER_TEST_CONSTANT;
-
-class Constants
-{
-    const TEST_CLASS_CONSTANT = 3;
-    public const PUBLIC_TEST_CLASS_CONSTANT = 'value';
-    protected const PROTECTED_TEST_CLASS_CONSTANT = 'value';
-    private const PRIVATE_TEST_CLASS_CONSTANT = 'value';
-    public const THREE = TWO + 1;
-    public const ONE_THIRD = ONE / self::THREE;
-    public const SENTENCE = 'The value of THREE is ' . self::THREE;
-
-    public static function testClassConstant()
-    {
-        return self::TEST_CLASS_CONSTANT;
-    }
-
-    public function f($a = ONE + self::THREE)
-    {
-        return $a;
-    }
-}
-
-`;
diff --git a/tests/constants/constants.php b/tests/constants/constants.php
deleted file mode 100644
index 5d5c63d..0000000
--- a/tests/constants/constants.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-define("TEST_CONSTANT", 1);
-const OTHER_TEST_CONSTANT = 2;
-const ONE = 1;
-const TWO = ONE * 2;
-
-$test = TEST_CONSTANT;
-$test = OTHER_TEST_CONSTANT;
-
-class Constants {
-  const TEST_CLASS_CONSTANT = 3;
-  public const PUBLIC_TEST_CLASS_CONSTANT = 'value';
-  protected const PROTECTED_TEST_CLASS_CONSTANT = 'value';
-  private const PRIVATE_TEST_CLASS_CONSTANT = 'value';
-  public const THREE = TWO + 1;
-  public const ONE_THIRD = ONE / self::THREE;
-  public const SENTENCE = 'The value of THREE is ' . self::THREE;
-
-  public static function testClassConstant() {
-    return self::TEST_CLASS_CONSTANT;
-  }
-
-  public function f($a = ONE + self::THREE) {
-    return $a;
-  }
-}
diff --git a/tests/namespace/__snapshots__/jsfmt.spec.js.snap b/tests/namespace/__snapshots__/jsfmt.spec.js.snap
index 7fbb510..96d658c 100644
--- a/tests/namespace/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/namespace/__snapshots__/jsfmt.spec.js.snap
@@ -24,6 +24,11 @@ namespace foo {
     }
     echo bar(2, 3);
 }
+
+namespace Name\\Space {
+    const FOO = 42;
+    function f() { echo __FUNCTION__."\\n"; }
+}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 namespace foo {
@@ -34,6 +39,14 @@ namespace foo {
     echo bar(2, 3);
 }
 
+namespace Name\\Space {
+    const FOO = 42;
+    function f()
+    {
+        echo __FUNCTION__ . "\\n";
+    }
+}
+
 `;
 
 exports[`single.php 1`] = `
@@ -51,7 +64,6 @@ namespace {}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 namespace  {
-
 }
 
 `;
diff --git a/tests/namespace/nested.php b/tests/namespace/nested.php
index 0e7cde3..2491457 100644
--- a/tests/namespace/nested.php
+++ b/tests/namespace/nested.php
@@ -6,3 +6,8 @@ namespace foo {
     }
     echo bar(2, 3);
 }
+
+namespace Name\Space {
+    const FOO = 42;
+    function f() { echo __FUNCTION__."\n"; }
+}
diff --git a/tests/string/__snapshots__/jsfmt.spec.js.snap b/tests/string/__snapshots__/jsfmt.spec.js.snap
index 8263803..6230d1b 100644
--- a/tests/string/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/string/__snapshots__/jsfmt.spec.js.snap
@@ -49,13 +49,16 @@ exports[`single.php 1`] = `
 exports[`string.php 1`] = `
 <?php
 $string = 'this is a simple string';
-// $string = 'You can also have embedded\\n newlines in
-// strings this way as it is
-// okay to do';
+$string = 'You can also have embedded\\n newlines in
+strings this way as it is
+okay to do';
+$string = "You can also have embedded\\n newlines in
+strings this way as it is
+okay to do";
 $string = 'Arnold once said: "I\\'ll be back"';
 $string = 'You deleted C:\\\\*.*?';
 $string = 'You deleted C:\\*.*?';
-// $string = 'This will not expand: \\n a newline';
+$string = 'This will not expand: \\n a newline';
 $string = 'Variables do not $expand $either';
 $string = 'qwe{$a}rty';
 $string = 'qwe\${a}rty';
@@ -67,10 +70,10 @@ $string = "foo\\vbar";
 $string = "foo\\ebar";
 $string = "foo\\fbar";
 $string = "foo\\\\bar";
-// $string = "foo\\\\\\bar";
+$string = "foo\\\\\\bar";
 $string = "foo\\\\\\\\bar";
-// $string = "foo\\$bar";
-// $string = "foo\\\\\\$bar";
+$string = "foo\\$bar";
+$string = "foo\\\\\\$bar";
 $string = "foo\\"bar";
 $string = "foo\\"";
 $string = "foo'bar";
@@ -89,19 +92,19 @@ $string = "encapsed variable {$value}.";
 $string = "encapsed offset {$value[0]}.";
 $string = "encapsed {$method->call()}.";
 $string = "combined \${$encapsed}.";
-// $string = "He drank some $juices[koolaid1] juice.";
+$string = "He drank some $juices[koolaid1] juice.";
 $string = "$people->john drank some $juices[0] juice.";
 $string = "This is { $great}";
 $string = "This is {$great}";
-// $string = "This square is {$square->width}00 centimeters broad.";
-// $string = "This works: {$arr['key']}";
-// $string = "This works: {$arr[4][3]}";
+$string = "This square is {$square->width}00 centimeters broad.";
+$string = "This works: {$arr['key']}";
+$string = "This works: {$arr[4][3]}";
 $string = "This works: " . $arr['foo'][3];
-// $string = "This works too: {$obj->values[3]->name}";
+$string = "This works too: {$obj->values[3]->name}";
 $string = "This is the value of the var named $name: {\${$name}}";
 $string = "This is the value of the var named by the return value of getName(): {\${getName()}}";
 $string = "This is the value of the var named by the return value of getName(): {\${getName($arg1, $arg2, $arg3)}}";
-// $string = "This is the value of the var named by the return value of \\$object->getName(): {\${$object->getName()}}";
+$string = "This is the value of the var named by the return value of \\$object->getName(): {\${$object->getName()}}";
 $string = "I'd like an {\${beers::softdrink}}\\n";
 $string = "I'd like an {\${beers::$ale}}\\n";
 $test = "\\\\";
@@ -122,13 +125,16 @@ $string = "\\u{9999}";
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 $string = 'this is a simple string';
-// $string = 'You can also have embedded\\n newlines in
-// strings this way as it is
-// okay to do';
+$string = 'You can also have embedded\\n newlines in
+strings this way as it is
+okay to do';
+$string = "You can also have embedded\\n newlines in
+strings this way as it is
+okay to do";
 $string = 'Arnold once said: "I\\'ll be back"';
 $string = 'You deleted C:\\\\*.*?';
 $string = 'You deleted C:\\*.*?';
-// $string = 'This will not expand: \\n a newline';
+$string = 'This will not expand: \\n a newline';
 $string = 'Variables do not $expand $either';
 $string = 'qwe{$a}rty';
 $string = 'qwe\${a}rty';
@@ -140,10 +146,10 @@ $string = "foo\\vbar";
 $string = "foo\\ebar";
 $string = "foo\\fbar";
 $string = "foo\\\\bar";
-// $string = "foo\\\\\\bar";
+$string = "foo\\\\\\bar";
 $string = "foo\\\\\\\\bar";
-// $string = "foo\\$bar";
-// $string = "foo\\\\\\$bar";
+$string = "foo\\$bar";
+$string = "foo\\\\\\$bar";
 $string = "foo\\"bar";
 $string = "foo\\"";
 $string = "foo'bar";
@@ -162,15 +168,15 @@ $string = "encapsed variable {$value}.";
 $string = "encapsed offset {$value[0]}.";
 $string = "encapsed {$method->call()}.";
 $string = "combined \${$encapsed}.";
-// $string = "He drank some $juices[koolaid1] juice.";
+$string = "He drank some {$juices[koolaid1]} juice.";
 $string = "{$people->john} drank some {$juices[0]} juice.";
 $string = "This is { $great}";
 $string = "This is {$great}";
-// $string = "This square is {$square->width}00 centimeters broad.";
-// $string = "This works: {$arr['key']}";
-// $string = "This works: {$arr[4][3]}";
+$string = "This square is {$square->width}00 centimeters broad.";
+$string = "This works: {$arr['key']}";
+$string = "This works: {$arr[4][3]}";
 $string = "This works: " . $arr['foo'][3];
-// $string = "This works too: {$obj->values[3]->name}";
+$string = "This works too: {$obj->values[3]->name}";
 $string = "This is the value of the var named $name: \${$name}";
 $string = "This is the value of the var named by the return value of getName(): \${getName()}";
 $string = "This is the value of the var named by the return value of getName(): \${getName(
@@ -178,7 +184,7 @@ $string = "This is the value of the var named by the return value of getName():
     $arg2,
     $arg3
 )}";
-// $string = "This is the value of the var named by the return value of \\$object->getName(): {\${$object->getName()}}";
+$string = "This is the value of the var named by the return value of \\$object->getName(): \${$object->getName()}";
 $string = "I'd like an \${beers::softdrink}\\n";
 $string = "I'd like an \${beers::$ale}\\n";
 $test = "\\\\";
diff --git a/tests/string/string.php b/tests/string/string.php
index b52be64..c16d7b1 100644
--- a/tests/string/string.php
+++ b/tests/string/string.php
@@ -1,12 +1,15 @@
 <?php
 $string = 'this is a simple string';
-// $string = 'You can also have embedded\n newlines in
-// strings this way as it is
-// okay to do';
+$string = 'You can also have embedded\n newlines in
+strings this way as it is
+okay to do';
+$string = "You can also have embedded\n newlines in
+strings this way as it is
+okay to do";
 $string = 'Arnold once said: "I\'ll be back"';
 $string = 'You deleted C:\\*.*?';
 $string = 'You deleted C:\*.*?';
-// $string = 'This will not expand: \n a newline';
+$string = 'This will not expand: \n a newline';
 $string = 'Variables do not $expand $either';
 $string = 'qwe{$a}rty';
 $string = 'qwe${a}rty';
@@ -18,10 +21,10 @@ $string = "foo\vbar";
 $string = "foo\ebar";
 $string = "foo\fbar";
 $string = "foo\\bar";
-// $string = "foo\\\bar";
+$string = "foo\\\bar";
 $string = "foo\\\\bar";
-// $string = "foo\$bar";
-// $string = "foo\\\$bar";
+$string = "foo\$bar";
+$string = "foo\\\$bar";
 $string = "foo\"bar";
 $string = "foo\"";
 $string = "foo'bar";
@@ -40,19 +43,19 @@ $string = "encapsed variable {$value}.";
 $string = "encapsed offset {$value[0]}.";
 $string = "encapsed {$method->call()}.";
 $string = "combined ${$encapsed}.";
-// $string = "He drank some $juices[koolaid1] juice.";
+$string = "He drank some $juices[koolaid1] juice.";
 $string = "$people->john drank some $juices[0] juice.";
 $string = "This is { $great}";
 $string = "This is {$great}";
-// $string = "This square is {$square->width}00 centimeters broad.";
-// $string = "This works: {$arr['key']}";
-// $string = "This works: {$arr[4][3]}";
+$string = "This square is {$square->width}00 centimeters broad.";
+$string = "This works: {$arr['key']}";
+$string = "This works: {$arr[4][3]}";
 $string = "This works: " . $arr['foo'][3];
-// $string = "This works too: {$obj->values[3]->name}";
+$string = "This works too: {$obj->values[3]->name}";
 $string = "This is the value of the var named $name: {${$name}}";
 $string = "This is the value of the var named by the return value of getName(): {${getName()}}";
 $string = "This is the value of the var named by the return value of getName(): {${getName($arg1, $arg2, $arg3)}}";
-// $string = "This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";
+$string = "This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";
 $string = "I'd like an {${beers::softdrink}}\n";
 $string = "I'd like an {${beers::$ale}}\n";
 $test = "\\";