@@ -358,7 +358,7 @@ private function doParse(string $value, int $flags)
358358 }
359359
360360 try {
361- return Inline::parse ($ this ->parseQuotedString ( $ this -> currentLine ), $ flags , $ this ->refs );
361+ return Inline::parse ($ this ->lexInlineQuotedString ( ), $ flags , $ this ->refs );
362362 } catch (ParseException $ e ) {
363363 $ e ->setParsedLine ($ this ->getRealCurrentLineNb () + 1 );
364364 $ e ->setSnippet ($ this ->currentLine );
@@ -371,7 +371,7 @@ private function doParse(string $value, int $flags)
371371 }
372372
373373 try {
374- $ parsedMapping = Inline::parse ($ this ->lexInlineMapping ($ this -> currentLine ), $ flags , $ this ->refs );
374+ $ parsedMapping = Inline::parse ($ this ->lexInlineMapping (), $ flags , $ this ->refs );
375375
376376 while ($ this ->moveToNextLine ()) {
377377 if (!$ this ->isCurrentLineEmpty ()) {
@@ -392,7 +392,7 @@ private function doParse(string $value, int $flags)
392392 }
393393
394394 try {
395- $ parsedSequence = Inline::parse ($ this ->lexInlineSequence ($ this -> currentLine ), $ flags , $ this ->refs );
395+ $ parsedSequence = Inline::parse ($ this ->lexInlineSequence (), $ flags , $ this ->refs );
396396
397397 while ($ this ->moveToNextLine ()) {
398398 if (!$ this ->isCurrentLineEmpty ()) {
@@ -667,6 +667,11 @@ private function getNextEmbedBlock(int $indentation = null, bool $inSequence = f
667667 return implode ("\n" , $ data );
668668 }
669669
670+ private function hasMoreLines (): bool
671+ {
672+ return (\count ($ this ->lines ) - 1 ) > $ this ->currentLineNb ;
673+ }
674+
670675 /**
671676 * Moves the parser to the next line.
672677 */
@@ -744,9 +749,13 @@ private function parseValue(string $value, int $flags, string $context)
744749
745750 try {
746751 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 );
748755 } 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 );
750759 }
751760
752761 $ quotation = '' !== $ value && ('" ' === $ value [0 ] || "' " === $ value [0 ]) ? $ value [0 ] : null ;
@@ -1145,107 +1154,148 @@ private function getLineTag(string $value, int $flags, bool $nextLineCheck = tru
11451154 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 );
11461155 }
11471156
1148- private function parseQuotedString ( string $ yaml ): ? string
1157+ private function lexInlineQuotedString ( int & $ cursor = 0 ): string
11491158 {
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 ;
11531162
1154- $ lines = [$ yaml ];
1155-
1156- while ($ this ->moveToNextLine ()) {
1157- $ lines [] = $ this ->currentLine ;
1163+ $ previousLineWasNewline = true ;
1164+ $ previousLineWasTerminatedWithBackslash = false ;
11581165
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 ()) {
11691168 $ value .= "\n" ;
11701169 } elseif (!$ previousLineWasNewline && !$ previousLineWasTerminatedWithBackslash ) {
11711170 $ value .= ' ' ;
11721171 }
11731172
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+ }
11781193 }
11791194
1180- if ('' === $ trimmedLine ) {
1195+ if ($ this -> isCurrentLineBlank () ) {
11811196 $ previousLineWasNewline = true ;
11821197 $ previousLineWasTerminatedWithBackslash = false ;
1183- } elseif ('\\' === $ lines [ $ i ] [-1 ]) {
1198+ } elseif ('\\' === $ this -> currentLine [-1 ]) {
11841199 $ previousLineWasNewline = false ;
11851200 $ previousLineWasTerminatedWithBackslash = true ;
11861201 } else {
11871202 $ previousLineWasNewline = false ;
11881203 $ previousLineWasTerminatedWithBackslash = false ;
11891204 }
1190- }
11911205
1192- return $ value ;
1206+ if ($ this ->hasMoreLines ()) {
1207+ $ cursor = 0 ;
1208+ }
1209+ } while ($ this ->moveToNextLine ());
1210+
1211+ throw new ParseException ('Malformed inline YAML string ' );
11931212 }
11941213
1195- private function lexInlineMapping ( string $ yaml ): string
1214+ private function lexUnquotedString ( int & $ cursor ): string
11961215 {
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 );
12031218
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+ }
12131221
3E14
1214- return implode ("\n" , $ lines );
1222+ private function lexInlineMapping (int &$ cursor = 0 ): string
1223+ {
1224+ return $ this ->lexInlineStructure ($ cursor , '} ' );
12151225 }
12161226
1217- private function lexInlineSequence (string $ yaml ): string
1227+ private function lexInlineSequence (int & $ cursor = 0 ): string
12181228 {
1219- if ('' === $ yaml || '[ ' !== $ yaml [0 ]) {
1220- throw new \InvalidArgumentException (sprintf ('"%s" is not a sequence. ' , $ yaml ));
1221- }
1229+ return $ this ->lexInlineStructure ($ cursor , '] ' );
1230+ }
12221231
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 ;
12251236
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+ }
12291267
1230- $ value = $ yaml ;
1268+ if ($ this ->consumeWhitespaces ($ cursor )) {
1269+ $ value .= ' ' ;
1270+ }
1271+ }
12311272
1232- while ($ this ->moveToNextLine ()) {
1233- for ( $ i = 1 ; isset ( $ this -> currentLine [ $ i ]) && ' ] ' !== $ this -> currentLine [ $ i ]; ++ $ i ) {
1273+ if ($ this ->hasMoreLines ()) {
1274+ $ cursor = 0 ;
12341275 }
1276+ } while ($ this ->moveToNextLine ());
12351277
1236- $ trimmedValue = trim ($ this ->currentLine );
1278+ throw new ParseException ('Malformed inline YAML string ' );
1279+ }
12371280
1238- if ( '' !== $ trimmedValue && ' # ' === $ trimmedValue [ 0 ]) {
1239- continue ;
1240- }
1281+ private function consumeWhitespaces ( int & $ cursor ): bool
1282+ {
1283+ $ whitespacesConsumed = 0 ;
12411284
1242- $ value .= $ trimmedValue ;
1285+ do {
1286+ $ whitespaceOnlyTokenLength = strspn ($ this ->currentLine , ' ' , $ cursor );
1287+ $ whitespacesConsumed += $ whitespaceOnlyTokenLength ;
1288+ $ cursor += $ whitespaceOnlyTokenLength ;
12431289
1244- if (isset ($ this ->currentLine [$ i ]) && ' ] ' === $ this -> currentLine [ $ i ] ) {
1245- break ;
1290+ if (isset ($ this ->currentLine [$ cursor ]) ) {
1291+ return 0 < $ whitespacesConsumed ;
12461292 }
1247- }
12481293
1249- return $ value ;
1294+ if ($ this ->hasMoreLines ()) {
1295+ $ cursor = 0 ;
1296+ }
1297+ } while ($ this ->moveToNextLine ());
1298+
1299+ return 0 <
3D27
$ whitespacesConsumed ;
12501300 }
12511301}
0 commit comments