@@ -30,17 +30,21 @@ class Parser
3030private $ currentLineNb = -1 ;
3131private $ currentLine ='' ;
3232private $ refs =array ();
33+ private $ skippedLineNumbers =array ();
34+ private $ locallySkippedLineNumbers =array ();
3335
3436/**
3537 * Constructor.
3638 *
3739 * @param int $offset The offset of YAML document (used for line numbers in error messages)
3840 * @param int|null $totalNumberOfLines The overall number of lines being parsed
41+ * @param int[] $skippedLineNumbers Number of comment lines that have been skipped by the parser
3942 */
40- public function __construct ($ offset =0 ,$ totalNumberOfLines =null )
43+ public function __construct ($ offset =0 ,$ totalNumberOfLines =null , array $ skippedLineNumbers = array () )
4144 {
4245$ this ->offset =$ offset ;
4346$ this ->totalNumberOfLines =$ totalNumberOfLines ;
47+ $ this ->skippedLineNumbers =$ skippedLineNumbers ;
4448 }
4549
4650/**
@@ -101,25 +105,18 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
101105
102106// array
103107if (!isset ($ values ['value ' ]) ||'' ==trim ($ values ['value ' ],' ' ) ||0 ===strpos (ltrim ($ values ['value ' ],' ' ),'# ' )) {
104- $ c =$ this ->getRealCurrentLineNb () +1 ;
105- $ parser =new self ($ c ,$ this ->totalNumberOfLines );
106- $ parser ->refs = &$ this ->refs ;
107- $ data [] =$ parser ->parse ($ this ->getNextEmbedBlock (null ,true ),$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
108+ $ data [] =$ this ->parseBlock ($ this ->getRealCurrentLineNb () +1 ,$ this ->getNextEmbedBlock (null ,true ),$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
108109 }else {
109110if (isset ($ values ['leadspaces ' ])
110111 &&preg_match ('#^(?P<key> ' .Inline::REGEX_QUOTED_STRING .'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u ' ,$ values ['value ' ],$ matches )
111112 ) {
112113// this is a compact notation element, add to next block and parse
113- $ c =$ this ->getRealCurrentLineNb ();
114- $ parser =new self ($ c ,$ this ->totalNumberOfLines );
115- $ parser ->refs = &$ this ->refs ;
116-
117114$ block =$ values ['value ' ];
118115if ($ this ->isNextLineIndented ()) {
119116$ block .="\n" .$ this ->getNextEmbedBlock ($ this ->getCurrentLineIndentation () +strlen ($ values ['leadspaces ' ]) +1 );
120117 }
121118
122- $ data [] =$ parser -> parse ( $ block ,$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
119+ $ data [] =$ this -> parseBlock ( $ this -> getRealCurrentLineNb (), $ block ,$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
123120 }else {
124121$ data [] =$ this ->parseValue ($ values ['value ' ],$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
125122 }
@@ -175,10 +172,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
175172 }else {
176173$ value =$ this ->getNextEmbedBlock ();
177174 }
178- $ c =$ this ->getRealCurrentLineNb () +1 ;
179- $ parser =new self ($ c ,$ this ->totalNumberOfLines );
180- $ parser ->refs = &$ this ->refs ;
181- $ parsed =$ parser ->parse ($ value ,$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
175+ $ parsed =$ this ->parseBlock ($ this ->getRealCurrentLineNb () +1 ,$ value ,$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
182176
183177if (!is_array ($ parsed )) {
184178throw new ParseException ('YAML merge keys used with a scalar value instead of an array. ' ,$ this ->getRealCurrentLineNb () +1 ,$ this ->currentLine );
@@ -226,10 +220,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
226220$ data [$ key ] =null ;
227221 }
228222 }else {
229- $ c =$ this ->getRealCurrentLineNb () +1 ;
230- $ parser =new self ($ c ,$ this ->totalNumberOfLines );
231- $ parser ->refs = &$ this ->refs ;
232- $ value =$ parser ->parse ($ this ->getNextEmbedBlock (),$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
223+ $ value =$ this ->parseBlock ($ this ->getRealCurrentLineNb () +1 ,$ this ->getNextEmbedBlock (),$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
233224// Spec: Keys MUST be unique; first one wins.
234225// But overwriting is allowed when a merge node is used in current block.
235226if ($ allowOverwrite || !isset ($ data [$ key ])) {
@@ -317,14 +308,42 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
317308return empty ($ data ) ?null :$ data ;
318309 }
319310
311+ private function parseBlock ($ offset ,$ yaml ,$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap )
312+ {
313+ $ skippedLineNumbers =$ this ->skippedLineNumbers ;
314+
315+ foreach ($ this ->locallySkippedLineNumbers as $ lineNumber ) {
316+ if ($ lineNumber <$ offset ) {
317+ continue ;
318+ }
319+
320+ $ skippedLineNumbers [] =$ lineNumber ;
321+ }
322+
323+ $ parser =new self ($ offset ,$ this ->totalNumberOfLines ,$ skippedLineNumbers );
324+ $ parser ->refs = &$ this ->refs ;
325+
326+ return $ parser ->parse ($ yaml ,$ exceptionOnInvalidType ,$ objectSupport ,$ objectForMap );
327+ }
328+
320329/**
321330 * Returns the current line number (takes the offset into account).
322331 *
323332 * @return int The current line number
324333 */
325334private function getRealCurrentLineNb ()
326335 {
327- return $ this ->currentLineNb +$ this ->offset ;
336+ $ realCurrentLineNumber =$ this ->currentLineNb +$ this ->offset ;
337+
338+ foreach ($ this ->skippedLineNumbers as $ skippedLineNumber ) {
339+ if ($ skippedLineNumber >$ realCurrentLineNumber ) {
340+ break ;
341+ }
342+
343+ ++$ realCurrentLineNumber ;
344+ }
345+
346+ return $ realCurrentLineNumber ;
328347 }
329348
330349/**
@@ -426,7 +445,15 @@ private function getNextEmbedBlock($indentation = null, $inSequence = false)
426445 }
427446
428447// we ignore "comment" lines only when we are not inside a scalar block
429- if (empty ($ blockScalarIndentations ) &&$ this ->isCurrentLineComment () &&false ===$ this ->checkIfPreviousNonCommentLineIsCollectionItem ()) {
448+ if (empty ($ blockScalarIndentations ) &&$ this ->isCurrentLineComment ()) {
449+ // remember ignored comment lines (they are used later in nested
450+ // parser calls to determine real line numbers)
451+ //
452+ // CAUTION: beware to not populate the global property here as it
453+ // will otherwise influence the getRealCurrentLineNb() call here
454+ // for consecutive comment lines and subsequent embedded blocks
455+ $ this ->locallySkippedLineNumbers [] =$ this ->getRealCurrentLineNb ();
456+
430457continue ;
431458 }
432459
@@ -786,44 +813,4 @@ private function isBlockScalarHeader()
786813 {
787814return (bool )preg_match ('~ ' .self ::BLOCK_SCALAR_HEADER_PATTERN .'$~ ' ,$ this ->currentLine );
788815 }
789-
790- /**
791- * Returns true if the current line is a collection item.
792- *
793- * @return bool
794- */
795- private function isCurrentLineCollectionItem ()
796- {
797- $ ltrimmedLine =ltrim ($ this ->currentLine ,' ' );
798-
799- return '' !==$ ltrimmedLine &&'- ' ===$ ltrimmedLine [0 ];
800- }
801-
802- /**
803- * Tests whether the current comment line is in a collection.
804- *
805- * @return bool
806- */
807- private function checkIfPreviousNonCommentLineIsCollectionItem ()
808- {
809- $ isCollectionItem =false ;
810- $ moves =0 ;
811- while ($ this ->moveToPreviousLine ()) {
812- ++$ moves ;
813- // If previous line is a comment, move back again.
814- if ($ this ->isCurrentLineComment ()) {
815- continue ;
816- }
817- $ isCollectionItem =$ this ->isCurrentLineCollectionItem ();
818- break ;
819- }
820-
821- // Move parser back to previous line.
822- while ($ moves >0 ) {
823- $ this ->moveToNextLine ();
824- --$ moves ;
825- }
826-
827- return $ isCollectionItem ;
828- }
829816}