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 0e38c33

Browse filesBrowse files
committed
fix lexing nested sequences/mappings
1 parent 1f46250 commit 0e38c33
Copy full SHA for 0e38c33

File tree

2 files changed

+291
-68
lines changed
Filter options

2 files changed

+291
-68
lines changed

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

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

357357
try {
358-
return Inline::parse($this->parseQuotedString($this->currentLine), $flags, $this->refs);
358+
return Inline::parse($this->lexInlineQuotedString(), $flags, $this->refs);
359359
} catch (ParseException $e) {
360360
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
361361
$e->setSnippet($this->currentLine);
@@ -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;
@@ -1137,106 +1141,148 @@ private function getLineTag(string $value, int $flags, bool $nextLineCheck = tru
11371141
throw new ParseException(sprintf('Tags support is not enabled. You must use the flag "Yaml::PARSE_CUSTOM_TAGS" to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
11381142
}
11391143

1140-
private function parseQuotedString(string $yaml): ?string
1144+
private function lexInlineQuotedString(int &$cursor = 0): string
11411145
{
1142-
if ('' === $yaml || ('"' !== $yaml[0] && "'" !== $yaml[0])) {
1143-
throw new \InvalidArgumentException(sprintf('"%s" is not a quoted string.', $yaml));
1144-
}
1145-
1146-
$lines = [$yaml];
1146+
$quotation = $this->currentLine[$cursor];
1147+
$value = $quotation;
1148+
++$cursor;
11471149

1148-
while ($this->moveToNextLine()) {
1149-
$lines[] = $this->currentLine;
1150+
$previousLineWasNewline = true;
1151+
$previousLineWasTerminatedWithBackslash = false;
11501152

1151-
if (!$this->isCurrentLineEmpty() && $yaml[0] === $this->currentLine[-1]) {
1152-
break;
1153-
}
1154-
}
1155-
1156-
$value = '';
1157-
1158-
for ($i = 0, $linesCount = \count($lines), $previousLineWasNewline = false, $previousLineWasTerminatedWithBackslash = false; $i < $linesCount; ++$i) {
1159-
if ('' === trim($lines[$i])) {
1153+
do {
1154+
if ($this->isCurrentLineBlank()) {
11601155
$value .= "\n";
11611156
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
11621157
$value .= ' ';
11631158
}
11641159

1165-
if ('' !== trim($lines[$i]) && '\\' === substr($lines[$i], -1)) {
1166-
$value .= ltrim(substr($lines[$i], 0, -1));
1167-
} elseif ('' !== trim($lines[$i])) {
1168-
$value .= trim($lines[$i]);
1160+
for (; \strlen($this->currentLine) > $cursor; ++$cursor) {
1161+
switch ($this->currentLine[$cursor]) {
1162+
case '\\':
1163+
if (isset($this->currentLine[++$cursor])) {
1164+
$value .= '\\'.$this->currentLine[$cursor];
1165+
}
1166+
1167+
break;
1168+
case $quotation:
1169+
++$cursor;
1170+
1171+
if ("'" === $quotation && isset($this->currentLine[$cursor]) && "'" === $this->currentLine[$cursor]) {
1172+
$value .= "''";
1173+
break;
1174+
}
1175+
1176+
return $value.$quotation;
1177+
default:
1178+
$value .= $this->currentLine[$cursor];
1179+
}
11691180
}
11701181

1171-
if ('' === trim($lines[$i])) {
1182+
if (isset($this->currentLine[$cursor]) && $this->currentLine[$cursor] === $quotation) {
1183+
++$cursor;
1184+
1185+
return $value.$quotation;
1186+
}
1187+
1188+
if ($this->isCurrentLineBlank()) {
11721189
$previousLineWasNewline = true;
11731190
$previousLineWasTerminatedWithBackslash = false;
1174-
} elseif ('\\' === substr($lines[$i], -1)) {
1191+
} elseif ('\\' === $this->currentLine[-1]) {
11751192
$previousLineWasNewline = false;
11761193
$previousLineWasTerminatedWithBackslash = true;
11771194
} else {
11781195
$previousLineWasNewline = false;
11791196
$previousLineWasTerminatedWithBackslash = false;
11801197
}
1181-
}
1198+
1199+
$cursor = 0;
1200+
} while ($this->moveToNextLine());
11821201

11831202
return $value;
11841203
}
11851204

1186-
private function lexInlineMapping(string $yaml): string
1205+
private function lexUnquotedString(int &$cursor): string
11871206
{
1188-
if ('' === $yaml || '{' !== $yaml[0]) {
1189-
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
1190-
}
1191-
1192-
for ($i = 1; isset($yaml[$i]) && '}' !== $yaml[$i]; ++$i) {
1193-
}
1194-
1195-
if (isset($yaml[$i]) && '}' === $yaml[$i]) {
1196-
return $yaml;
1197-
}
1198-
1199-
$lines = [$yaml];
1200-
1201-
while ($this->moveToNextLine()) {
1202-
$lines[] = $this->currentLine;
1203-
}
1207+
$offset = $cursor;
1208+
$cursor += strcspn($this->currentLine, '[]{},: ', $cursor);
12041209

1205-
return implode("\n", $lines);
1210+
return substr($this->currentLine, $offset, $cursor - $offset);
12061211
}
12071212

1208-
private function lexInlineSequence(string $yaml): string
1213+
private function lexInlineMapping(int &$cursor = 0): string
12091214
{
1210-
if ('' === $yaml || '[' !== $yaml[0]) {
1211-
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
1212-
}
1215+
return $this->lexInlineStructure($cursor, '}');
1216+
}
12131217

1214-
for ($i = 1; isset($yaml[$i]) && ']' !== $yaml[$i]; ++$i) {
1215-
}
1218+
private function lexInlineSequence(int &$cursor = 0): string
1219+
{
1220+
return $this->lexInlineStructure($cursor, ']');
1221+
}
12161222

1217-
if (isset($yaml[$i]) && ']' === $yaml[$i]) {
1218-
return $yaml;
1219-
}
1223+
private function lexInlineStructure(int &$cursor, string $closingTag): string
1224+
{
1225+
$value = $this->currentLine[$cursor];
1226+
++$cursor;
12201227

1221-
$value = $yaml;
1228+
do {
1229+
$this->consumeWhitespaces($cursor);
1230+
1231+
while (isset($this->currentLine[$cursor])) {
1232+
switch ($this->currentLine[$cursor]) {
1233+
case '"':
1234+
case "'":
1235+
$value .= $this->lexInlineQuotedString($cursor);
1236+
break;
1237+
case ':':
1238+
case ',':
1239+
$value .= $this->currentLine[$cursor];
1240+
++$cursor;
1241+
break;
1242+
case '{':
1243+
$value .= $this->lexInlineMapping($cursor);
1244+
break;
1245+
case '[':
1246+
$value .= $this->lexInlineSequence($cursor);
1247+
break;
1248+
case $closingTag:
1249+
$value .= $this->currentLine[$cursor];
1250+
++$cursor;
1251+
1252+
return $value;
1253+
case '#':
1254+
break 2;
1255+
default:
1256+
$value .= $this->lexUnquotedString($cursor);
1257+
}
12221258

1223-
while ($this->moveToNextLine()) {
1224-
for ($i = 1; isset($this->currentLine[$i]) && ']' !== $this->currentLine[$i]; ++$i) {
1259+
if ($this->consumeWhitespaces($cursor)) {
1260+
$value .= ' ';
1261+
}
12251262
}
12261263

1227-
$trimmedValue = trim($this->currentLine);
1264+
$cursor = 0;
1265+
} while ($this->moveToNextLine());
12281266

1229-
if ('' !== $trimmedValue && '#' === $trimmedValue[0]) {
1230-
continue;
1231-
}
1267+
return $value;
1268+
}
1269+
1270+
private function consumeWhitespaces(int &$cursor): bool
1271+
{
1272+
$whitespacesConsumed = 0;
12321273

1233-
$value .= $trimmedValue;
1274+
do {
1275+
$whitespaceOnlyTokenLength = strspn($this->currentLine, ' ', $cursor);
1276+
$whitespacesConsumed += $whitespaceOnlyTokenLength;
1277+
$cursor += $whitespaceOnlyTokenLength;
12341278

1235-
if (isset($this->currentLine[$i]) && ']' === $this->currentLine[$i]) {
1236-
break;
1279+
if (isset($this->currentLine[$cursor])) {
1280+
return 0 < $whitespacesConsumed;
12371281
}
1238-
}
12391282

1240-
return $value;
1283+
$cursor = 0;
1284+
} while ($this->moveToNextLine());
1285+
1286+
return 0 < $whitespacesConsumed;
12411287
}
12421288
}

0 commit comments

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