diff --git a/grammar/rebuildParsers.php b/grammar/rebuildParsers.php index 289c399..87c5cd5 100644 --- a/grammar/rebuildParsers.php +++ b/grammar/rebuildParsers.php @@ -165,7 +165,7 @@ function resolveMacros($code) { return 'foreach (' . $args[0] . ' as &$s) { if (is_string($s)) {' . ' $s = Node\Scalar\String_::parseEscapeSequences($s, null, ' . $args[1] . '); } }' - . ' $s = preg_replace(\'~(\r\n|\n|\r)$~\', \'\', $s);' + . ' $s = preg_replace(\'~(\r\n|\n|\r)\z~\', \'\', $s);' . ' if (\'\' === $s) array_pop(' . $args[0] . ');'; } diff --git a/lib/PhpParser/Node/Scalar/String_.php b/lib/PhpParser/Node/Scalar/String_.php index 3b32a19..604672c 100644 --- a/lib/PhpParser/Node/Scalar/String_.php +++ b/lib/PhpParser/Node/Scalar/String_.php @@ -135,7 +135,7 @@ class String_ extends Scalar */ public static function parseDocString($startToken, $str, $parseUnicodeEscape = true) { // strip last newline (thanks tokenizer for sticking it into the string!) - $str = preg_replace('~(\r\n|\n|\r)$~', '', $str); + $str = preg_replace('~(\r\n|\n|\r)\z~', '', $str); // nowdoc string if (false !== strpos($startToken, '\'')) { diff --git a/lib/PhpParser/Parser/Php5.php b/lib/PhpParser/Parser/Php5.php index 3d8e473..5398ad2 100644 --- a/lib/PhpParser/Parser/Php5.php +++ b/lib/PhpParser/Parser/Php5.php @@ -2818,7 +2818,7 @@ class Php5 extends \PhpParser\ParserAbstract } protected function reduceRule463() { - foreach ($this->semStack[$this->stackPos-(3-2)] as &$s) { if (is_string($s)) { $s = Node\Scalar\String_::parseEscapeSequences($s, null, false); } } $s = preg_replace('~(\r\n|\n|\r)$~', '', $s); if ('' === $s) array_pop($this->semStack[$this->stackPos-(3-2)]);; $this->semValue = new Scalar\Encapsed($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); + foreach ($this->semStack[$this->stackPos-(3-2)] as &$s) { if (is_string($s)) { $s = Node\Scalar\String_::parseEscapeSequences($s, null, false); } } $s = preg_replace('~(\r\n|\n|\r)\z~', '', $s); if ('' === $s) array_pop($this->semStack[$this->stackPos-(3-2)]);; $this->semValue = new Scalar\Encapsed($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); } protected function reduceRule464() { diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php index 7f1884c..bb08ec3 100644 --- a/lib/PhpParser/Parser/Php7.php +++ b/lib/PhpParser/Parser/Php7.php @@ -2406,7 +2406,7 @@ class Php7 extends \PhpParser\ParserAbstract } protected function reduceRule398() { - foreach ($this->semStack[$this->stackPos-(3-2)] as &$s) { if (is_string($s)) { $s = Node\Scalar\String_::parseEscapeSequences($s, null, true); } } $s = preg_replace('~(\r\n|\n|\r)$~', '', $s); if ('' === $s) array_pop($this->semStack[$this->stackPos-(3-2)]);; $this->semValue = new Scalar\Encapsed($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); + foreach ($this->semStack[$this->stackPos-(3-2)] as &$s) { if (is_string($s)) { $s = Node\Scalar\String_::parseEscapeSequences($s, null, true); } } $s = preg_replace('~(\r\n|\n|\r)\z~', '', $s); if ('' === $s) array_pop($this->semStack[$this->stackPos-(3-2)]);; $this->semValue = new Scalar\Encapsed($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes); } protected function reduceRule399() { diff --git a/test/code/parser/scalar/docStringNewlines.test b/test/code/parser/scalar/docStringNewlines.test new file mode 100644 index 0000000..479c995 --- /dev/null +++ b/test/code/parser/scalar/docStringNewlines.test @@ -0,0 +1,58 @@ +Trailing newlines in doc strings +----- +