Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 800a703

Browse filesBrowse files
committed
fix lexing nested sequences/mappings
1 parent c72f853 commit 800a703
Copy full SHA for 800a703

File tree

Expand file treeCollapse file tree

2 files changed

+196
-41
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+196
-41
lines changed

‎src/Symfony/Component/Yaml/Parser.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Parser.php
+123-41Lines changed: 123 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ private function doParse(string $value, int $flags)
368368
}
369369

370370
try {
371-
$parsedMapping = Inline::parse($this->lexInlineMapping($this->currentLine), $flags, $this->refs);
371+
$parsedMapping = Inline::parse($this->lexInlineMapping(), $flags, $this->refs);
372372

373373
while ($this->moveToNextLine()) {
374374
if (!$this->isCurrentLineEmpty()) {
@@ -389,7 +389,7 @@ private function doParse(string $value, int $flags)
389389
}
390390

391391
try {
392-
$parsedSequence = Inline::parse($this->lexInlineSequence($this->currentLine), $flags, $this->refs);
392+
$parsedSequence = Inline::parse($this->lexInlineSequence(), $flags, $this->refs);
393393

394394
while ($this->moveToNextLine()) {
395395
if (!$this->isCurrentLineEmpty()) {
@@ -736,9 +736,13 @@ private function parseValue(string $value, int $flags, string $context)
736736

737737
try {
738738
if ('' !== $value && '{' === $value[0]) {
739-
return Inline::parse($this->lexInlineMapping($value), $flags, $this->refs);
739+
$cursor = \strlen($this->currentLine) - \strlen($value);
740+
741+
return Inline::parse($this->lexInlineMapping($cursor), $flags, $this->refs);
740742
} elseif ('' !== $value && '[' === $value[0]) {
741-
return Inline::parse($this->lexInlineSequence($value), $flags, $this->refs);
743+
$cursor = \strlen($this->currentLine) - \strlen($value);
744+
745+
return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs);
742746
}
743747

744748
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
@@ -1204,60 +1208,138 @@ private function parseQuotedString(string $yaml): ?string
12041208
}
12051209
}
12061210

1207-
private function lexInlineMapping(string $yaml): string
1211+
private function lexInlineQuotedString(int &$cursor): string
12081212
{
1209-
if ('' === $yaml || '{' !== $yaml[0]) {
1210-
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
1211-
}
1212-
1213-
for ($i = 1; isset($yaml[$i]) && '}' !== $yaml[$i]; ++$i) {
1214-
}
1215-
1216-
if (isset($yaml[$i]) && '}' === $yaml[$i]) {
1217-
return $yaml;
1218-
}
1213+
$quotedStringOffset = $cursor;
1214+
$cursor += strcspn($this->currentLine, $this->currentLine[$cursor], $cursor + 1) + 2;
12191215

1220-
$lines = [$yaml];
1216+
return substr($this->currentLine, $quotedStringOffset, $cursor - $quotedStringOffset);
1217+
}
12211218

1222-
while ($this->moveToNextLine()) {
1223-
$lines[] = $this->currentLine;
1224-
}
1219+
private function lexUnquotedString(int &$cursor): string
1220+
{
1221+
$offset = $cursor;
1222+
$cursor += strcspn($this->currentLine, '[]{},: ', $cursor);
12251223

1226-
return implode("\n", $lines);
1224+
return substr($this->currentLine, $offset, $cursor - $offset);
12271225
}
12281226

1229-
private function lexInlineSequence(string $yaml): string
1227+
private function lexInlineMapping(int &$cursor = 0): string
12301228
{
1231-
if ('' === $yaml || '[' !== $yaml[0]) {
1232-
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
1233-
}
1229+
$value = $this->currentLine[$cursor];
1230+
++$cursor;
12341231

1235-
for ($i = 1; isset($yaml[$i]) && ']' !== $yaml[$i]; ++$i) {
1236-
}
1232+
do {
1233+
$this->consumeWhitespaces($cursor);
1234+
1235+
while (isset($this->currentLine[$cursor])) {
1236+
switch ($this->currentLine[$cursor]) {
1237+
case '"':
1238+
case "'":
1239+
$value .= $this->lexInlineQuotedString($cursor);
1240+
1241+
break;
1242+
case ':':
1243+
case ',':
1244+
$value .= $this->currentLine[$cursor];
1245+
++$cursor;
1246+
1247+
break;
1248+
case '{':
1249+
$value .= $this->lexInlineMapping($cursor);
1250+
1251+
break;
1252+
case '}':
1253+
$value .= '}';
1254+
++$cursor;
1255+
1256+
return $value;
1257+
case '[':
1258+
$value .= $this->lexInlineSequence($cursor);
1259+
1260+
break;
1261+
default:
1262+
$value .= $this->lexUnquotedString($cursor);
1263+
}
12371264

1238-
if (isset($yaml[$i]) && ']' === $yaml[$i]) {
1239-
return $yaml;
1240-
}
1265+
if ($this->consumeWhitespaces($cursor)) {
1266+
$value .= ' ';
1267+
}
1268+
}
1269+
1270+
$cursor = 0;
1271+
} while ($this->moveToNextLine());
12411272

1242-
$value = $yaml;
1273+
return $value;
1274+
}
12431275

1244-
while ($this->moveToNextLine()) {
1245-
for ($i = 1; isset($this->currentLine[$i]) && ']' !== $this->currentLine[$i]; ++$i) {
1246-
}
1276+
private function lexInlineSequence(int &$cursor = 0): string
1277+
{
1278+
$value = $this->currentLine[$cursor];
1279+
++$cursor;
12471280

1248-
$trimmedValue = trim($this->currentLine);
1281+
do {
1282+
$this->consumeWhitespaces($cursor);
1283+
1284+
while (isset($this->currentLine[$cursor])) {
1285+
switch ($this->currentLine[$cursor]) {
1286+
case '"':
1287+
case "'":
1288+
$value .= $this->lexInlineQuotedString($cursor);
1289+
1290+
break;
1291+
case ':':
1292+
case ',':
1293+
$value .= $this->currentLine[$cursor];
1294+
++$cursor;
1295+
1296+
break;
1297+
case '[':
1298+
$value .= $this->lexInlineSequence($cursor);
1299+
1300+
break;
1301+
case ']':
1302+
$value .= ']';
1303+
++$cursor;
1304+
1305+
return $value;
1306+
case '{':
1307+
$value .= $this->lexInlineMapping($cursor);
1308+
1309+
break;
1310+
case '#':
1311+
break 2;
1312+
default:
1313+
$value .= $this->lexUnquotedString($cursor);
1314+
}
12491315

1250-
if ('' !== $trimmedValue && '#' === $trimmedValue[0]) {
1251-
continue;
1316+
if ($this->consumeWhitespaces($cursor)) {
1317+
$value .= ' ';
1318+
}
12521319
}
12531320

1254-
$value .= $trimmedValue;
1321+
$cursor = 0;
1322+
} while ($this->moveToNextLine());
12551323

1256-
if (isset($this->currentLine[$i]) && ']' === $this->currentLine[$i]) {
1257-
break;
1324+
return $value;
1325+
}
1326+
1327+
private function consumeWhitespaces(int &$cursor): bool
1328+
{
1329+
$whitespacesConsumed = 0;
1330+
1331+
do {
1332+
$whitespaceOnlyTokenLength = strspn($this->currentLine, ' ', $cursor);
1333+
$whitespacesConsumed += $whitespaceOnlyTokenLength;
1334+
$cursor += $whitespaceOnlyTokenLength;
1335+
1336+
if (isset($this->currentLine[$cursor])) {
1337+
return 0 < $whitespacesConsumed;
12581338
}
1259-
}
12601339

1261-
return $value;
1340+
$cursor = 0;
1341+
} while ($this->moveToNextLine());
1342+
1343+
return 0 < $whitespacesConsumed;
12621344
}
12631345
}

‎src/Symfony/Component/Yaml/Tests/ParserTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/ParserTest.php
+73Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,16 @@ public function inlineNotationSpanningMultipleLinesProvider(): array
16601660
'foo': 'bar',
16611661
'bar': 'baz'
16621662
}
1663+
YAML
1664+
,
1665+
],
1666+
'mapping with unquoted strings and values' => [
1667+
['foo' => 'bar', 'bar' => 'baz'],
1668+
<<<YAML
1669+
{
1670+
foo: bar,
1671+
bar: baz
1672+
}
16631673
YAML
16641674
,
16651675
],
@@ -1673,6 +1683,53 @@ public function inlineNotationSpanningMultipleLinesProvider(): array
16731683
YAML
16741684
,
16751685
],
1686+
'sequence with unquoted items' => [
1687+
['foo', 'bar'],
1688+
<<<YAML
1689+
[
1690+
foo,
1691+
bar
1692+
]
1693+
YAML
1694+
,
1695+
],
1696+
'nested mapping terminating at end of line' => [
1697+
[
1698+
'foo' => [
1699+
'bar' => 'foobar',
1700+
],
1701+
],
1702+
<<<YAML
1703+
{ foo: { bar: foobar }
1704+
}
1705+
YAML
1706+
,
1707+
],
1708+
'nested sequence terminating at end of line' => [
1709+
[
1710+
'foo',
1711+
[
1712+
'bar',
1713+
'baz',
1714+
],
1715+
],
1716+
<<<YAML
1717+
[ foo, [bar, baz]
1718+
]
1719+
YAML
1720+
],
1721+
'nested sequence spanning multiple lines' => [
1722+
[
1723+
['entry1', []],
1724+
['entry2'],
1725+
],
1726+
<<<YAML
1727+
[
1728+
['entry1', {}],
1729+
['entry2']
1730+
]
1731+
YAML
1732+
],
16761733
'sequence nested in mapping' => [
16771734
['foo' => ['bar', 'foobar'], 'bar' => ['baz']],
16781735
<<<YAML
@@ -1699,6 +1756,22 @@ public function inlineNotationSpanningMultipleLinesProvider(): array
16991756
YAML
17001757
,
17011758
],
1759+
'sequence spanning multiple lines nested in mapping with a following mapping' => [
1760+
[
1761+
'foobar' => [
1762+
'foo',
1763+
'bar',
1764+
],
1765+
'bar' => 'baz',
1766+
],
1767+
<<<YAML
1768+
foobar: [
1769+
foo,
1770+
bar,
1771+
]
1772+
bar: baz
1773+
YAML
1774+
],
17021775
'nested sequence nested in mapping starting on the same line' => [
17031776
[
17041777
'foo' => [

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.