@@ -358,7 +358,7 @@ private function doParse(string $value, int $flags)
358
358
}
359
359
360
360
try {
361
- return Inline::parse ($ this ->parseQuotedString ( $ this -> currentLine ), $ flags , $ this ->refs );
361
+ return Inline::parse ($ this ->lexInlineQuotedString ( ), $ flags , $ this ->refs );
362
362
} catch (ParseException $ e ) {
363
363
$ e ->setParsedLine ($ this ->getRealCurrentLineNb () + 1 );
364
364
$ e ->setSnippet ($ this ->currentLine );
@@ -371,7 +371,7 @@ private function doParse(string $value, int $flags)
371
371
}
372
372
373
373
try {
374
- $ parsedMapping = Inline::parse ($ this ->lexInlineMapping ($ this -> currentLine ), $ flags , $ this ->refs );
374
+ $ parsedMapping = Inline::parse ($ this ->lexInlineMapping (), $ flags , $ this ->refs );
375
375
376
376
while ($ this ->moveToNextLine ()) {
377
377
if (!$ this ->isCurrentLineEmpty ()) {
@@ -392,7 +392,7 @@ private function doParse(string $value, int $flags)
392
392
}
393
393
394
394
try {
395
- $ parsedSequence = Inline::parse ($ this ->lexInlineSequence ($ this -> currentLine ), $ flags , $ this ->refs );
395
+ $ parsedSequence = Inline::parse ($ this ->lexInlineSequence (), $ flags , $ this ->refs );
396
396
397
397
while ($ this ->moveToNextLine ()) {
398
398
if (!$ this ->isCurrentLineEmpty ()) {
@@ -667,6 +667,11 @@ private function getNextEmbedBlock(int $indentation = null, bool $inSequence = f
667
667
return implode ("\n" , $ data );
668
668
}
669
669
670
+ private function hasMoreLines (): bool
671
+ {
672
+ return (\count ($ this ->lines ) - 1 ) > $ this ->currentLineNb ;
673
+ }
674
+
670
675
/**
671
676
* Moves the parser to the next line.
672
677
*/
@@ -744,9 +749,13 @@ private function parseValue(string $value, int $flags, string $context)
744
749
745
750
try {
746
751
if ('' !== $ value && '{ ' === $ value [0 ]) {
747
- return Inline::parse ($ this ->lexInlineMapping ($ value ), $ flags , $ this ->refs );
752
+ $ cursor = \strlen ($ this ->currentLine ) - \strlen ($ value );
753
+
754
+ return Inline::parse ($ this ->lexInlineMapping ($ cursor ), $ flags , $ this ->refs );
748
755
} elseif ('' !== $ value && '[ ' === $ value [0 ]) {
749
- return Inline::parse ($ this ->lexInlineSequence ($ value ), $ flags , $ this ->refs );
756
+ $ cursor = \strlen ($ this ->currentLine ) - \strlen ($ value );
757
+
758
+ return Inline::parse ($ this ->lexInlineSequence ($ cursor ), $ flags , $ this ->refs );
750
759
}
751
760
752
761
$ quotation = '' !== $ value && ('" ' === $ value [0 ] || "' " === $ value [0 ]) ? $ value [0 ] : null ;
@@ -1145,107 +1154,148 @@ private function getLineTag(string $value, int $flags, bool $nextLineCheck = tru
1145
1154
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 );
1146
1155
}
1147
1156
1148
- private function parseQuotedString ( string $ yaml ): ? string
1157
+ private function lexInlineQuotedString ( int & $ cursor = 0 ): string
1149
1158
{
1150
- if ( '' === $ yaml || ( ' " ' !== $ yaml [ 0 ] && " ' " !== $ yaml [ 0 ])) {
1151
- throw new \ InvalidArgumentException ( sprintf ( ' "%s" is not a quoted string. ' , $ yaml )) ;
1152
- }
1159
+ $ quotation = $ this -> currentLine [ $ cursor ];
1160
+ $ value = $ quotation ;
1161
+ ++ $ cursor ;
1153
1162
1154
- $ lines = [$ yaml ];
1155
-
1156
- while ($ this ->moveToNextLine ()) {
1157
- $ lines [] = $ this ->currentLine ;
1163
+ $ previousLineWasNewline = true ;
1164
+ $ previousLineWasTerminatedWithBackslash = false ;
1158
1165
1159
- if (!$ this ->isCurrentLineEmpty () && $ yaml [0 ] === $ this ->currentLine [-1 ]) {
1160
- break ;
1161
- }
1162
- }
1163
-
1164
- $ value = '' ;
1165
-
1166
- for ($ i = 0 , $ linesCount = \count ($ lines ), $ previousLineWasNewline = false , $ previousLineWasTerminatedWithBackslash = false ; $ i < $ linesCount ; ++$ i ) {
1167
- $ trimmedLine = trim ($ lines [$ i ]);
1168
- if ('' === $ trimmedLine ) {
1166
+ do {
1167
+ if ($ this ->isCurrentLineBlank ()) {
1169
1168
$ value .= "\n" ;
1170
1169
} elseif (!$ previousLineWasNewline && !$ previousLineWasTerminatedWithBackslash ) {
1171
1170
$ value .= ' ' ;
1172
1171
}
1173
1172
1174
- if ('' !== $ trimmedLine && '\\' === $ lines [$ i ][-1 ]) {
1175
- $ value .= ltrim (substr ($ lines [$ i ], 0 , -1 ));
1176
- } elseif ('' !== $ trimmedLine ) {
1177
- $ value .= $ trimmedLine ;
1173
+ for (; \strlen ($ this ->currentLine ) > $ cursor ; ++$ cursor ) {
1174
+ switch ($ this ->currentLine [$ cursor ]) {
1175
+ case '\\' :
1176
+ if (isset ($ this ->currentLine [++$ cursor ])) {
1177
+ $ value .= '\\' .$ this ->currentLine [$ cursor ];
1178
+ }
1179
+
1180
+ break ;
1181
+ case $ quotation :
1182
+ ++$ cursor ;
1183
+
1184
+ if ("' " === $ quotation && isset ($ this ->currentLine [$ cursor ]) && "' " === $ this ->currentLine [$ cursor ]) {
1185
+ $ value .= "'' " ;
1186
+ break ;
1187
+ }
1188
+
1189
+ return $ value .$ quotation ;
1190
+ default :
1191
+ $ value .= $ this ->currentLine [$ cursor ];
1192
+ }
1178
1193
}
1179
1194
1180
- if ('' === $ trimmedLine ) {
1195
+ if ($ this -> isCurrentLineBlank () ) {
1181
1196
$ previousLineWasNewline = true ;
1182
1197
$ previousLineWasTerminatedWithBackslash = false ;
1183
- } elseif ('\\' === $ lines [ $ i ] [-1 ]) {
1198
+ } elseif ('\\' === $ this -> currentLine [-1 ]) {
1184
1199
$ previousLineWasNewline = false ;
1185
1200
$ previousLineWasTerminatedWithBackslash = true ;
1186
1201
} else {
1187
1202
$ previousLineWasNewline = false ;
1188
1203
$ previousLineWasTerminatedWithBackslash = false ;
1189
1204
}
1190
- }
1191
1205
1192
- return $ value ;
1206
+ if ($ this ->hasMoreLines ()) {
1207
+ $ cursor = 0 ;
1208
+ }
1209
+ } while ($ this ->moveToNextLine ());
1210
+
1211
+ throw new ParseException ('Malformed inline YAML string ' );
1193
1212
}
1194
1213
1195
- private function lexInlineMapping ( string $ yaml ): string
1214
+ private function lexUnquotedString ( int & $ cursor ): string
1196
1215
{
1197
- if ('' === $ yaml || '{ ' !== $ yaml [0 ]) {
1198
- throw new \InvalidArgumentException (sprintf ('"%s" is not a sequence. ' , $ yaml ));
1199
- }
1200
-
1201
- for ($ i = 1 ; isset ($ yaml [$ i ]) && '} ' !== $ yaml [$ i ]; ++$ i ) {
1202
- }
1216
+ $ offset = $ cursor ;
1217
+ $ cursor += strcspn ($ this ->currentLine , '[]{},: ' , $ cursor );
1203
1218
1204
- if (isset ($ yaml [$ i ]) && '} ' === $ yaml [$ i ]) {
1205
- return $ yaml ;
1206
- }
1207
-
1208
- $ lines = [$ yaml ];
1209
-
1210
- while ($ this ->moveToNextLine ()) {
1211
- $ lines [] = $ this ->currentLine ;
1212
- }
1219
+ return substr ($ this ->currentLine , $ offset , $ cursor - $ offset );
1220
+ }
1213
1221
1214
- return implode ("\n" , $ lines );
1222
+ private function lexInlineMapping (int &$ cursor = 0 ): string
1223
+ {
1224
+ return $ this ->lexInlineStructure ($ cursor , '} ' );
1215
1225
}
1216
1226
1217
- private function lexInlineSequence (string $ yaml ): string
1227
+ private function lexInlineSequence (int & $ cursor = 0 ): string
1218
1228
{
1219
- if ('' === $ yaml || '[ ' !== $ yaml [0 ]) {
1220
- throw new \InvalidArgumentException (sprintf ('"%s" is not a sequence. ' , $ yaml ));
1221
- }
1229
+ return $ this ->lexInlineStructure ($ cursor , '] ' );
1230
+ }
1222
1231
1223
- for ($ i = 1 ; isset ($ yaml [$ i ]) && '] ' !== $ yaml [$ i ]; ++$ i ) {
1224
- }
1232
+ private function lexInlineStructure (int &$ cursor , string $ closingTag ): string
1233
+ {
1234
+ $ value = $ this ->currentLine [$ cursor ];
1235
+ ++$ cursor ;
1225
1236
1226
- if (isset ($ yaml [$ i ]) && '] ' === $ yaml [$ i ]) {
1227
- return $ yaml ;
1228
- }
1237
+ do {
1238
+ $ this ->consumeWhitespaces ($ cursor );
1239
+
1240
+ while (isset ($ this ->currentLine [$ cursor ])) {
1241
+ switch ($ this ->currentLine [$ cursor ]) {
1242
+ case '" ' :
1243
+ case "' " :
1244
+ $ value .= $ this ->lexInlineQuotedString ($ cursor );
1245
+ break ;
1246
+ case ': ' :
1247
+ case ', ' :
1248
+ $ value .= $ this ->currentLine [$ cursor ];
1249
+ ++$ cursor ;
1250
+ break ;
1251
+ case '{ ' :
1252
+ $ value .= $ this ->lexInlineMapping ($ cursor );
1253
+ break ;
1254
+ case '[ ' :
1255
+ $ value .= $ this ->lexInlineSequence ($ cursor );
1256
+ break ;
1257
+ case $ closingTag :
1258
+ $ value .= $ this ->currentLine [$ cursor ];
1259
+ ++$ cursor ;
1260
+
1261
+ return $ value ;
1262
+ case '# ' :
1263
+ break 2 ;
1264
+ default :
1265
+ $ value .= $ this ->lexUnquotedString ($ cursor );
1266
+ }
1229
1267
1230
- $ value = $ yaml ;
1268
+ if ($ this ->consumeWhitespaces ($ cursor )) {
1269
+ $ value .= ' ' ;
1270
+ }
1271
+ }
1231
1272
1232
- while ($ this ->moveToNextLine ()) {
1233
- for ( $ i = 1 ; isset ( $ this -> currentLine [ $ i ]) && ' ] ' !== $ this -> currentLine [ $ i ]; ++ $ i ) {
1273
+ if ($ this ->hasMoreLines ()) {
1274
+ $ cursor = 0 ;
1234
1275
}
1276
+ } while ($ this ->moveToNextLine ());
1235
1277
1236
- $ trimmedValue = trim ($ this ->currentLine );
1278
+ throw new ParseException ('Malformed inline YAML string ' );
1279
+ }
1237
1280
1238
- if ( '' !== $ trimmedValue && ' # ' === $ trimmedValue [ 0 ]) {
1239
- continue ;
1240
- }
1281
+ private function consumeWhitespaces ( int & $ cursor ): bool
1282
+ {
1283
+ $ whitespacesConsumed = 0 ;
1241
1284
1242
- $ value .= $ trimmedValue ;
1285
+ do {
1286
+ $ whitespaceOnlyTokenLength = strspn ($ this ->currentLine , ' ' , $ cursor );
1287
+ $ whitespacesConsumed += $ whitespaceOnlyTokenLength ;
1288
+ $ cursor += $ whitespaceOnlyTokenLength ;
1243
1289
1244
- if (isset ($ this ->currentLine [$ i ]) && ' ] ' === $ this -> currentLine [ $ i ] ) {
1245
- break ;
1290
+ if (isset ($ this ->currentLine [$ cursor ]) ) {
1291
+ return 0 < $ whitespacesConsumed ;
1246
1292
}
1247
- }
1248
1293
1249
- return $ value ;
1294
+ if ($ this ->hasMoreLines ()) {
1295
+ $ cursor = 0 ;
1296
+ }
1297
+ } while ($ this ->moveToNextLine ());
1298
+
1299
+ return 0 < $ whitespacesConsumed ;
1250
1300
}
1251
1301
}