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 52dedfe078..a37e3e6948 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -303,7 +303,11 @@ class Parser 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 @@ class Parser $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); - if (!$insideBlockScalar) { - $insideBlockScalar = $this->isBlockScalarHeader(); + if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) { + $blockScalarIndentations[] = $this->getCurrentLineIndentation(); } $previousLineIndentation = $this->getCurrentLineIndentation(); @@ -349,8 +353,17 @@ class Parser 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 @@ class Parser } // 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 @@ class Parser $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 @@ class Parser //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 7a1485eb2d..9d6d42befe 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -737,7 +737,9 @@ EOF; public function getCommentLikeStringInScalarBlockData() { - $yaml1 = <<<'EOT' + $tests = array(); + + $yaml = <<<'EOT' pages: - title: some title @@ -752,7 +754,7 @@ pages: footer # comment3 EOT; - $expected1 = array( + $expected = array( 'pages' => array( array( 'title' => 'some title', @@ -771,8 +773,9 @@ EOT ), ), ); + $tests[] = array($yaml, $expected); - $yaml2 = <<<'EOT' + $yaml = <<<'EOT' test: | foo # bar @@ -787,7 +790,7 @@ collection: # bar baz EOT; - $expected2 = array( + $expected = array( 'test' => <<<'EOT' foo # bar @@ -814,11 +817,47 @@ EOT ), ), ); + $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()