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