Skip to content

Commit 18bba0c

Browse files
Merge branch '2.8' into 3.0
* 2.8: (22 commits) Fix merge [HttpFoundation] Use UPSERT for sessions stored in PgSql >= 9.5 [Console] fixed PHPDoc [travis] HHVM 3.12 LTS Fix feature detection for IE [Form] Fixed collapsed choice attributes [Console] added explanation of messages usage in a progress bar force enabling the external XML entity loaders [Yaml] properly count skipped comment lines [WebProfilerBundle] Fix invalid CSS style Added progressive jpeg to mime types guesser [Yaml] Fix wrong line number when comments are inserted in the middle of a block. Fixed singular of committee Do not inject web debug toolbar on attachments bumped Symfony version to 2.8.8 updated VERSION for 2.8.7 updated CHANGELOG for 2.8.7 bumped Symfony version to 2.7.15 updated VERSION for 2.7.14 update CONTRIBUTORS for 2.7.14 ... Conflicts: CHANGELOG-2.7.md CHANGELOG-3.0.md src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php src/Symfony/Component/HttpKernel/Kernel.php
2 parents fd2f945 + 8c157a6 commit 18bba0c

File tree

2 files changed

+141
-19
lines changed

2 files changed

+141
-19
lines changed

Parser.php

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,21 @@ class Parser
2828
private $currentLineNb = -1;
2929
private $currentLine = '';
3030
private $refs = array();
31+
private $skippedLineNumbers = array();
32+
private $locallySkippedLineNumbers = array();
3133

3234
/**
3335
* Constructor.
3436
*
3537
* @param int $offset The offset of YAML document (used for line numbers in error messages)
3638
* @param int|null $totalNumberOfLines The overall number of lines being parsed
39+
* @param int[] $skippedLineNumbers Number of comment lines that have been skipped by the parser
3740
*/
38-
public function __construct($offset = 0, $totalNumberOfLines = null)
41+
public function __construct($offset = 0, $totalNumberOfLines = null, array $skippedLineNumbers = array())
3942
{
4043
$this->offset = $offset;
4144
$this->totalNumberOfLines = $totalNumberOfLines;
45+
$this->skippedLineNumbers = $skippedLineNumbers;
4246
}
4347

4448
/**
@@ -99,25 +103,18 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
99103

100104
// array
101105
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
102-
$c = $this->getRealCurrentLineNb() + 1;
103-
$parser = new self($c, $this->totalNumberOfLines);
104-
$parser->refs = &$this->refs;
105-
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap);
106+
$data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap);
106107
} else {
107108
if (isset($values['leadspaces'])
108109
&& preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
109110
) {
110111
// this is a compact notation element, add to next block and parse
111-
$c = $this->getRealCurrentLineNb();
112-
$parser = new self($c, $this->totalNumberOfLines);
113-
$parser->refs = &$this->refs;
114-
115112
$block = $values['value'];
116113
if ($this->isNextLineIndented()) {
117114
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values['leadspaces']) + 1);
118115
}
119116

120-
$data[] = $parser->parse($block, $exceptionOnInvalidType, $objectSupport, $objectForMap);
117+
$data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $exceptionOnInvalidType, $objectSupport, $objectForMap);
121118
} else {
122119
$data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
123120
}
@@ -173,10 +170,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
173170
} else {
174171
$value = $this->getNextEmbedBlock();
175172
}
176-
$c = $this->getRealCurrentLineNb() + 1;
177-
$parser = new self($c, $this->totalNumberOfLines);
178-
$parser->refs = &$this->refs;
179-
$parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap);
173+
$parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $exceptionOnInvalidType, $objectSupport, $objectForMap);
180174

181175
if (!is_array($parsed)) {
182176
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
@@ -224,10 +218,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
224218
$data[$key] = null;
225219
}
226220
} else {
227-
$c = $this->getRealCurrentLineNb() + 1;
228-
$parser = new self($c, $this->totalNumberOfLines);
229-
$parser->refs = &$this->refs;
230-
$value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport, $objectForMap);
221+
$value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport, $objectForMap);
231222
// Spec: Keys MUST be unique; first one wins.
232223
// But overwriting is allowed when a merge node is used in current block.
233224
if ($allowOverwrite || !isset($data[$key])) {
@@ -321,14 +312,42 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
321312
return empty($data) ? null : $data;
322313
}
323314

315+
private function parseBlock($offset, $yaml, $exceptionOnInvalidType, $objectSupport, $objectForMap)
316+
{
317+
$skippedLineNumbers = $this->skippedLineNumbers;
318+
319+
foreach ($this->locallySkippedLineNumbers as $lineNumber) {
320+
if ($lineNumber < $offset) {
321+
continue;
322+
}
323+
324+
$skippedLineNumbers[] = $lineNumber;
325+
}
326+
327+
$parser = new self($offset, $this->totalNumberOfLines, $skippedLineNumbers);
328+
$parser->refs = &$this->refs;
329+
330+
return $parser->parse($yaml, $exceptionOnInvalidType, $objectSupport, $objectForMap);
331+
}
332+
324333
/**
325334
* Returns the current line number (takes the offset into account).
326335
*
327336
* @return int The current line number
328337
*/
329338
private function getRealCurrentLineNb()
330339
{
331-
return $this->currentLineNb + $this->offset;
340+
$realCurrentLineNumber = $this->currentLineNb + $this->offset;
341+
342+
foreach ($this->skippedLineNumbers as $skippedLineNumber) {
343+
if ($skippedLineNumber > $realCurrentLineNumber) {
344+
break;
345+
}
346+
347+
++$realCurrentLineNumber;
348+
}
349+
350+
return $realCurrentLineNumber;
332351
}
333352

334353
/**
@@ -431,6 +450,14 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false)
431450

432451
// we ignore "comment" lines only when we are not inside a scalar block
433452
if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) {
453+
// remember ignored comment lines (they are used later in nested
454+
// parser calls to determine real line numbers)
455+
//
456+
// CAUTION: beware to not populate the global property here as it
457+
// will otherwise influence the getRealCurrentLineNb() call here
458+
// for consecutive comment lines and subsequent embedded blocks
459+
$this->locallySkippedLineNumbers[] = $this->getRealCurrentLineNb();
460+
434461
continue;
435462
}
436463

@@ -466,10 +493,18 @@ private function moveToNextLine()
466493

467494
/**
468495
* Moves the parser to the previous line.
496+
*
497+
* @return bool
469498
*/
470499
private function moveToPreviousLine()
471500
{
501+
if ($this->currentLineNb < 1) {
502+
return false;
503+
}
504+
472505
$this->currentLine = $this->lines[--$this->currentLineNb];
506+
507+
return true;
473508
}
474509

475510
/**

Tests/ParserTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,25 @@ public function testSequenceInMappingStartedBySingleDashLine()
656656
$this->assertSame($expected, $this->parser->parse($yaml));
657657
}
658658

659+
public function testSequenceFollowedByCommentEmbeddedInMapping()
660+
{
661+
$yaml = <<<EOT
662+
a:
663+
b:
664+
- c
665+
# comment
666+
d: e
667+
EOT;
668+
$expected = array(
669+
'a' => array(
670+
'b' => array('c'),
671+
'd' => 'e',
672+
),
673+
);
674+
675+
$this->assertSame($expected, $this->parser->parse($yaml));
676+
}
677+
659678
/**
660679
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
661680
*/
@@ -1112,6 +1131,74 @@ public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks()
11121131
$this->parser->parse($yaml)
11131132
);
11141133
}
1134+
1135+
/**
1136+
* @param $lineNumber
1137+
* @param $yaml
1138+
* @dataProvider parserThrowsExceptionWithCorrectLineNumberProvider
1139+
*/
1140+
public function testParserThrowsExceptionWithCorrectLineNumber($lineNumber, $yaml)
1141+
{
1142+
$this->setExpectedException(
1143+
'\Symfony\Component\Yaml\Exception\ParseException',
1144+
sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber)
1145+
);
1146+
1147+
$this->parser->parse($yaml);
1148+
}
1149+
1150+
public function parserThrowsExceptionWithCorrectLineNumberProvider()
1151+
{
1152+
return array(
1153+
array(
1154+
4,
1155+
<<<YAML
1156+
foo:
1157+
-
1158+
# bar
1159+
bar: "123",
1160+
YAML
1161+
),
1162+
array(
1163+
5,
1164+
<<<YAML
1165+
foo:
1166+
-
1167+
# bar
1168+
# bar
1169+
bar: "123",
1170+
YAML
1171+
),
1172+
array(
1173+
8,
1174+
<<<YAML
1175+
foo:
1176+
-
1177+
# foobar
1178+
baz: 123
1179+
bar:
1180+
-
1181+
# bar
1182+
bar: "123",
1183+
YAML
1184+
),
1185+
array(
1186+
10,
1187+
<<<YAML
1188+
foo:
1189+
-
1190+
# foobar
1191+
# foobar
1192+
baz: 123
1193+
bar:
1194+
-
1195+
# bar
1196+
# bar
1197+
bar: "123",
1198+
YAML
1199+
),
1200+
);
1201+
}
11151202
}
11161203

11171204
class B

0 commit comments

Comments
 (0)