From 3a2216559bc10e35f012112345e0b9ef823d07c4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 28 Dec 2015 15:55:02 +0100 Subject: [PATCH] [Yaml] recognize when a block scalar is left The parser did not recognize when the block scalar was completely parsed and thus treated following comments as they need to be kept leading to parse errors on the following lines. --- src/Symfony/Component/Yaml/Parser.php | 29 +++++++--- .../Component/Yaml/Tests/ParserTest.php | 53 ++++++++++++++++--- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 52dedfe07851a..a37e3e69484cb 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -303,7 +303,11 @@ private function getCurrentLineIndentation() private function getNextEmbedBlock($indentation = null, $inSequence = false) { $oldLineIndentation = $this->getCurrentLineIndentation(); - $insideBlockScalar = $this->isBlockScalarHeader(); + $blockScalarIndentations = array(); + + if ($this->isBlockScalarHeader()) { + $blockScalarIndentations[] = $this->getCurrentLineIndentation(); + } if (!$this->moveToNextLine()) { return; @@ -340,8 +344,8 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); - if (!$insideBlockScalar) { - $insideBlockScalar = $this->isBlockScalarHeader(); + if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) { + $blockScalarIndentations[] = $this->getCurrentLineIndentation(); } $previousLineIndentation = $this->getCurrentLineIndentation(); @@ -349,8 +353,17 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) while ($this->moveToNextLine()) { $indent = $this->getCurrentLineIndentation(); - if (!$insideBlockScalar && $indent === $previousLineIndentation) { - $insideBlockScalar = $this->isBlockScalarHeader(); + // terminate all block scalars that are more indented than the current line + if (!empty($blockScalarIndentations) && $indent < $previousLineIndentation && trim($this->currentLine) !== '') { + foreach ($blockScalarIndentations as $key => $blockScalarIndentation) { + if ($blockScalarIndentation >= $this->getCurrentLineIndentation()) { + unset($blockScalarIndentations[$key]); + } + } + } + + if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) { + $blockScalarIndentations[] = $this->getCurrentLineIndentation(); } $previousLineIndentation = $indent; @@ -366,7 +379,7 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false) } // we ignore "comment" lines only when we are not inside a scalar block - if (!$insideBlockScalar && $this->isCurrentLineComment()) { + if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) { continue; } @@ -523,7 +536,7 @@ private function parseBlockScalar($style, $chomping = '', $indentation = 0) $previousLineIndented = false; $previousLineBlank = false; - for ($i = 0; $i < count($blockLines); $i++) { + for ($i = 0; $i < count($blockLines); ++$i) { if ('' === $blockLines[$i]) { $text .= "\n"; $previousLineIndented = false; @@ -618,7 +631,7 @@ private function isCurrentLineComment() //checking explicitly the first char of the trim is faster than loops or strpos $ltrimmedLine = ltrim($this->currentLine, ' '); - return $ltrimmedLine[0] === '#'; + return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#'; } /** diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 7a1485eb2dd83..9d6d42befe94c 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -737,7 +737,9 @@ public function testCommentLikeStringsAreNotStrippedInBlockScalars($yaml, $expec public function getCommentLikeStringInScalarBlockData() { - $yaml1 = <<<'EOT' + $tests = array(); + + $yaml = <<<'EOT' pages: - title: some title @@ -752,7 +754,7 @@ public function getCommentLikeStringInScalarBlockData() footer # comment3 EOT; - $expected1 = array( + $expected = array( 'pages' => array( array( 'title' => 'some title', @@ -771,8 +773,9 @@ public function getCommentLikeStringInScalarBlockData() ), ), ); + $tests[] = array($yaml, $expected); - $yaml2 = <<<'EOT' + $yaml = <<<'EOT' test: | foo # bar @@ -787,7 +790,7 @@ public function getCommentLikeStringInScalarBlockData() # bar baz EOT; - $expected2 = array( + $expected = array( 'test' => <<<'EOT' foo # bar @@ -814,11 +817,47 @@ public function getCommentLikeStringInScalarBlockData() ), ), ); + $tests[] = array($yaml, $expected); - return array( - array($yaml1, $expected1), - array($yaml2, $expected2), + $yaml = << + line1 + line2> + baz: +# comment + foobar: ~ +EOT; + $expected = array( + 'foo' => array( + 'bar' => array( + 'scalar-block' => 'line1 line2>', + ), + 'baz' => array( + 'foobar' => null, + ), + ), ); + $tests[] = array($yaml, $expected); + + $yaml = <<<'EOT' +a: + b: hello +# c: | +# first row +# second row + d: hello +EOT; + $expected = array( + 'a' => array( + 'b' => 'hello', + 'd' => 'hello', + ), + ); + $tests[] = array($yaml, $expected); + + return $tests; } public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks()