@@ -29,17 +29,21 @@ class Parser
29
29
private $ currentLineNb = -1 ;
30
30
private $ currentLine = '' ;
31
31
private $ refs = array ();
32
+ private $ skippedLineNumbers = array ();
33
+ private $ locallySkippedLineNumbers = array ();
32
34
33
35
/**
34
36
* Constructor.
35
37
*
36
38
* @param int $offset The offset of YAML document (used for line numbers in error messages)
37
39
* @param int|null $totalNumberOfLines The overall number of lines being parsed
40
+ * @param int[] $skippedLineNumbers Number of comment lines that have been skipped by the parser
38
41
*/
39
- public function __construct ($ offset = 0 , $ totalNumberOfLines = null )
42
+ public function __construct ($ offset = 0 , $ totalNumberOfLines = null , array $ skippedLineNumbers = array () )
40
43
{
41
44
$ this ->offset = $ offset ;
42
45
$ this ->totalNumberOfLines = $ totalNumberOfLines ;
46
+ $ this ->skippedLineNumbers = $ skippedLineNumbers ;
43
47
}
44
48
45
49
/**
@@ -124,25 +128,18 @@ public function parse($value, $flags = 0)
124
128
125
129
// array
126
130
if (!isset ($ values ['value ' ]) || '' == trim ($ values ['value ' ], ' ' ) || 0 === strpos (ltrim ($ values ['value ' ], ' ' ), '# ' )) {
127
- $ c = $ this ->getRealCurrentLineNb () + 1 ;
128
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
129
- $ parser ->refs = &$ this ->refs ;
130
- $ data [] = $ parser ->parse ($ this ->getNextEmbedBlock (null , true ), $ flags );
131
+ $ data [] = $ this ->parseBlock ($ this ->getRealCurrentLineNb () + 1 , $ this ->getNextEmbedBlock (null , true ), $ flags );
131
132
} else {
132
133
if (isset ($ values ['leadspaces ' ])
133
134
&& preg_match ('#^(?P<key> ' .Inline::REGEX_QUOTED_STRING .'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u ' , $ values ['value ' ], $ matches )
134
135
) {
135
136
// this is a compact notation element, add to next block and parse
136
- $ c = $ this ->getRealCurrentLineNb ();
137
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
138
- $ parser ->refs = &$ this ->refs ;
139
-
140
137
$ block = $ values ['value ' ];
141
138
if ($ this ->isNextLineIndented ()) {
142
139
$ block .= "\n" .$ this ->getNextEmbedBlock ($ this ->getCurrentLineIndentation () + strlen ($ values ['leadspaces ' ]) + 1 );
143
140
}
144
141
145
- $ data [] = $ parser -> parse ( $ block , $ flags );
142
+ $ data [] = $ this -> parseBlock ( $ this -> getRealCurrentLineNb (), $ block , $ flags );
146
143
} else {
147
144
$ data [] = $ this ->parseValue ($ values ['value ' ], $ flags , $ context );
148
145
}
@@ -198,10 +195,7 @@ public function parse($value, $flags = 0)
198
195
} else {
199
196
$ value = $ this ->getNextEmbedBlock ();
200
197
}
201
- $ c = $ this ->getRealCurrentLineNb () + 1 ;
202
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
203
- $ parser ->refs = &$ this ->refs ;
204
- $ parsed = $ parser ->parse ($ value , $ flags );
198
+ $ parsed = $ this ->parseBlock ($ this ->getRealCurrentLineNb () + 1 , $ value , $ flags );
205
199
206
200
if (!is_array ($ parsed )) {
207
201
throw new ParseException ('YAML merge keys used with a scalar value instead of an array. ' , $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
@@ -249,10 +243,7 @@ public function parse($value, $flags = 0)
249
243
$ data [$ key ] = null ;
250
244
}
251
245
} else {
252
- $ c = $ this ->getRealCurrentLineNb () + 1 ;
253
- $ parser = new self ($ c , $ this ->totalNumberOfLines );
254
- $ parser ->refs = &$ this ->refs ;
255
- $ value = $ parser ->parse ($ this ->getNextEmbedBlock (), $ flags );
246
+ $ value = $ this ->parseBlock ($ this ->getRealCurrentLineNb () + 1 , $ this ->getNextEmbedBlock (), $ flags );
256
247
// Spec: Keys MUST be unique; first one wins.
257
248
// But overwriting is allowed when a merge node is used in current block.
258
249
if ($ allowOverwrite || !isset ($ data [$ key ])) {
@@ -346,14 +337,42 @@ public function parse($value, $flags = 0)
346
337
return empty ($ data ) ? null : $ data ;
347
338
}
348
339
340
+ private function parseBlock ($ offset , $ yaml , $ flags )
341
+ {
342
+ $ skippedLineNumbers = $ this ->skippedLineNumbers ;
343
+
344
+ foreach ($ this ->locallySkippedLineNumbers as $ lineNumber ) {
345
+ if ($ lineNumber < $ offset ) {
346
+ continue ;
347
+ }
348
+
349
+ $ skippedLineNumbers [] = $ lineNumber ;
350
+ }
351
+
352
+ $ parser = new self ($ offset , $ this ->totalNumberOfLines , $ skippedLineNumbers );
353
+ $ parser ->refs = &$ this ->refs ;
354
+
355
+ return $ parser ->parse ($ yaml , $ flags );
356
+ }
357
+
349
358
/**
350
359
* Returns the current line number (takes the offset into account).
351
360
*
352
361
* @return int The current line number
353
362
*/
354
363
private function getRealCurrentLineNb ()
355
364
{
356
- return $ this ->currentLineNb + $ this ->offset ;
365
+ $ realCurrentLineNumber = $ this ->currentLineNb + $ this ->offset ;
366
+
367
+ foreach ($ this ->skippedLineNumbers as $ skippedLineNumber ) {
368
+ if ($ skippedLineNumber > $ realCurrentLineNumber ) {
369
+ break ;
370
+ }
371
+
372
+ ++$ realCurrentLineNumber ;
373
+ }
374
+
375
+ return $ realCurrentLineNumber ;
357
376
}
358
377
359
378
/**
@@ -456,6 +475,14 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false)
456
475
457
476
// we ignore "comment" lines only when we are not inside a scalar block
458
477
if (empty ($ blockScalarIndentations ) && $ this ->isCurrentLineComment ()) {
478
+ // remember ignored comment lines (they are used later in nested
479
+ // parser calls to determine real line numbers)
480
+ //
481
+ // CAUTION: beware to not populate the global property here as it
482
+ // will otherwise influence the getRealCurrentLineNb() call here
483
+ // for consecutive comment lines and subsequent embedded blocks
484
+ $ this ->locallySkippedLineNumbers [] = $ this ->getRealCurrentLineNb ();
485
+
459
486
continue ;
460
487
}
461
488
@@ -491,10 +518,18 @@ private function moveToNextLine()
491
518
492
519
/**
493
520
* Moves the parser to the previous line.
521
+ *
522
+ * @return bool
494
523
*/
495
524
private function moveToPreviousLine ()
496
525
{
526
+ if ($ this ->currentLineNb < 1 ) {
527
+ return false ;
528
+ }
529
+
497
530
$ this ->currentLine = $ this ->lines [--$ this ->currentLineNb ];
531
+
532
+ return true ;
498
533
}
499
534
500
535
/**
0 commit comments