@@ -28,17 +28,21 @@ class Parser
28
28
private $ currentLineNb = -1 ;
29
29
private $ currentLine = '' ;
30
30
private $ refs = array ();
31
+ private $ skippedLineNumbers = array ();
32
+ private $ locallySkippedLineNumbers = array ();
31
33
32
34
/**
33
35
* Constructor.
34
36
*
35
37
* @param int $offset The offset of YAML document (used for line numbers in error messages)
36
38
* @param int|null $totalNumberOfLines The overall number of lines being parsed
39
+ * @param int[] $skippedLineNumbers Number of comment lines that have been skipped by the parser
37
40
*/
38
- public function __construct ($ offset = 0 , $ totalNumberOfLines = null )
41
+ public function __construct ($ offset = 0 , $ totalNumberOfLines = null , array $ skippedLineNumbers = array () )
39
42
{
40
43
$ this ->offset = $ offset ;
41
44
$ this ->totalNumberOfLines = $ totalNumberOfLines ;
45
+ $ this ->skippedLineNumbers = $ skippedLineNumbers ;
42
46
}
43
47
44
48
/**
@@ -99,25 +103,18 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
99
103
100
104
// array
101
105
if (!isset ($ values ['value ' ]) || '' == trim ($ values ['value ' ], ' ' ) || 0 === strpos (ltrim ($ values ['value ' ], ' ' ), '# ' )) {
102
- $ c = $ this ->getRealCurrentLineNb () + 1 ;
103
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
104
- $ parser ->refs = &$ this ->refs ;
105
- $ data [] = $ parser ->parse ($ this ->getNextEmbedBlock (null , true ), $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
106
+ $ data [] = $ this ->parseBlock ($ this ->getRealCurrentLineNb () + 1 , $ this ->getNextEmbedBlock (null , true ), $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
106
107
} else {
107
108
if (isset ($ values ['leadspaces ' ])
108
109
&& preg_match ('#^(?P<key> ' .Inline::REGEX_QUOTED_STRING .'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u ' , $ values ['value ' ], $ matches )
109
110
) {
110
111
// this is a compact notation element, add to next block and parse
111
- $ c = $ this ->getRealCurrentLineNb ();
112
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
113
- $ parser ->refs = &$ this ->refs ;
114
-
115
112
$ block = $ values ['value ' ];
116
113
if ($ this ->isNextLineIndented ()) {
117
114
$ block .= "\n" .$ this ->getNextEmbedBlock ($ this ->getCurrentLineIndentation () + strlen ($ values ['leadspaces ' ]) + 1 );
118
115
}
119
116
120
- $ data [] = $ parser -> parse ( $ block , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
117
+ $ data [] = $ this -> parseBlock ( $ this -> getRealCurrentLineNb (), $ block , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
121
118
} else {
122
119
$ data [] = $ this ->parseValue ($ values ['value ' ], $ exceptionOnInvalidType , $ objectSupport , $ objectForMap , $ context );
123
120
}
@@ -173,10 +170,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
173
170
} else {
174
171
$ value = $ this ->getNextEmbedBlock ();
175
172
}
176
- $ c = $ this ->getRealCurrentLineNb () + 1 ;
177
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
178
- $ parser ->refs = &$ this ->refs ;
179
- $ parsed = $ parser ->parse ($ value , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
173
+ $ parsed = $ this ->parseBlock ($ this ->getRealCurrentLineNb () + 1 , $ value , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
180
174
181
175
if (!is_array ($ parsed )) {
182
176
throw new ParseException ('YAML merge keys used with a scalar value instead of an array. ' , $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
@@ -224,10 +218,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
224
218
$ data [$ key ] = null ;
225
219
}
226
220
} else {
227
- $ c = $ this ->getRealCurrentLineNb () + 1 ;
228
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
229
- $ parser ->refs = &$ this ->refs ;
230
- $ value = $ parser ->parse ($ this ->getNextEmbedBlock (), $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
221
+ $ value = $ this ->parseBlock ($ this ->getRealCurrentLineNb () + 1 , $ this ->getNextEmbedBlock (), $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
231
222
// Spec: Keys MUST be unique; first one wins.
232
223
// But overwriting is allowed when a merge node is used in current block.
233
224
if ($ allowOverwrite || !isset ($ data [$ key ])) {
@@ -321,14 +312,42 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
321
312
return empty ($ data ) ? null : $ data ;
322
313
}
323
314
315
+ private function parseBlock ($ offset , $ yaml , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap )
316
+ {
317
+ $ skippedLineNumbers = $ this ->skippedLineNumbers ;
318
+
319
+ foreach ($ this ->locallySkippedLineNumbers as $ lineNumber ) {
320
+ if ($ lineNumber < $ offset ) {
321
+ continue ;
322
+ }
323
+
324
+ $ skippedLineNumbers [] = $ lineNumber ;
325
+ }
326
+
327
+ $ parser = new self ($ offset , $ this ->totalNumberOfLines , $ skippedLineNumbers );
328
+ $ parser ->refs = &$ this ->refs ;
329
+
330
+ return $ parser ->parse ($ yaml , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
331
+ }
332
+
324
333
/**
325
334
* Returns the current line number (takes the offset into account).
326
335
*
327
336
* @return int The current line number
328
337
*/
329
338
private function getRealCurrentLineNb ()
330
339
{
331
- return $ this ->currentLineNb + $ this ->offset ;
340
+ $ realCurrentLineNumber = $ this ->currentLineNb + $ this ->offset ;
341
+
342
+ foreach ($ this ->skippedLineNumbers as $ skippedLineNumber ) {
343
+ if ($ skippedLineNumber > $ realCurrentLineNumber ) {
344
+ break ;
345
+ }
346
+
347
+ ++$ realCurrentLineNumber ;
348
+ }
349
+
350
+ return $ realCurrentLineNumber ;
332
351
}
333
352
334
353
/**
@@ -431,6 +450,14 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false)
431
450
432
451
// we ignore "comment" lines only when we are not inside a scalar block
433
452
if (empty ($ blockScalarIndentations ) && $ this ->isCurrentLineComment ()) {
453
+ // remember ignored comment lines (they are used later in nested
454
+ // parser calls to determine real line numbers)
455
+ //
456
+ // CAUTION: beware to not populate the global property here as it
457
+ // will otherwise influence the getRealCurrentLineNb() call here
458
+ // for consecutive comment lines and subsequent embedded blocks
459
+ $ this ->locallySkippedLineNumbers [] = $ this ->getRealCurrentLineNb ();
460
+
434
461
continue ;
435
462
}
436
463
@@ -466,10 +493,18 @@ private function moveToNextLine()
466
493
467
494
/**
468
495
* Moves the parser to the previous line.
496
+ *
497
+ * @return bool
469
498
*/
470
499
private function moveToPreviousLine ()
471
500
{
501
+ if ($ this ->currentLineNb < 1 ) {
502
+ return false ;
503
+ }
504
+
472
505
$ this ->currentLine = $ this ->lines [--$ this ->currentLineNb ];
506
+
507
+ return true ;
473
508
}
474
509
475
510
/**
0 commit comments