@@ -23,6 +23,7 @@ class Parser
23
23
const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)? ' ;
24
24
25
25
private $ offset = 0 ;
26
+ private $ totalNumberOfLines ;
26
27
private $ lines = array ();
27
28
private $ currentLineNb = -1 ;
28
29
private $ currentLine = '' ;
@@ -31,11 +32,13 @@ class Parser
31
32
/**
32
33
* Constructor.
33
34
*
34
- * @param int $offset The offset of YAML document (used for line numbers in error messages)
35
+ * @param int $offset The offset of YAML document (used for line numbers in error messages)
36
+ * @param int|null $totalNumberOfLines The overall number of lines being parsed
35
37
*/
36
- public function __construct ($ offset = 0 )
38
+ public function __construct ($ offset = 0 , $ totalNumberOfLines = null )
37
39
{
38
40
$ this ->offset = $ offset ;
41
+ $ this ->totalNumberOfLines = $ totalNumberOfLines ;
39
42
}
40
43
41
44
/**
@@ -60,6 +63,10 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
60
63
$ value = $ this ->cleanup ($ value );
61
64
$ this ->lines = explode ("\n" , $ value );
62
65
66
+ if (null === $ this ->totalNumberOfLines ) {
67
+ $ this ->totalNumberOfLines = count ($ this ->lines );
68
+ }
69
+
63
70
if (2 /* MB_OVERLOAD_STRING */ & (int ) ini_get ('mbstring.func_overload ' )) {
64
71
$ mbEncoding = mb_internal_encoding ();
65
72
mb_internal_encoding ('UTF-8 ' );
@@ -81,7 +88,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
81
88
$ isRef = $ mergeNode = false ;
82
89
if (preg_match ('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u ' , $ this ->currentLine , $ values )) {
83
90
if ($ context && 'mapping ' == $ context ) {
84
- throw new ParseException ('You cannot define a sequence item when in a mapping ' );
91
+ throw new ParseException ('You cannot define a sequence item when in a mapping ' , $ this -> getRealCurrentLineNb () + 1 , $ this -> currentLine );
85
92
}
86
93
$ context = 'sequence ' ;
87
94
@@ -93,7 +100,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
93
100
// array
94
101
if (!isset ($ values ['value ' ]) || '' == trim ($ values ['value ' ], ' ' ) || 0 === strpos (ltrim ($ values ['value ' ], ' ' ), '# ' )) {
95
102
$ c = $ this ->getRealCurrentLineNb () + 1 ;
96
- $ parser = new self ($ c );
103
+ $ parser = new self ($ c, $ this -> totalNumberOfLines );
97
104
$ parser ->refs = &$ this ->refs ;
98
105
$ data [] = $ parser ->parse ($ this ->getNextEmbedBlock (null , true ), $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
99
106
} else {
@@ -102,7 +109,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
102
109
) {
103
110
// this is a compact notation element, add to next block and parse
104
111
$ c = $ this ->getRealCurrentLineNb ();
105
- $ parser = new self ($ c );
112
+ $ parser = new self ($ c, $ this -> totalNumberOfLines );
106
113
$ parser ->refs = &$ this ->refs ;
107
114
108
115
$ block = $ values ['value ' ];
@@ -120,7 +127,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
120
127
}
121
128
} elseif (preg_match ('#^(?P<key> ' .Inline::REGEX_QUOTED_STRING .'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u ' , $ this ->currentLine , $ values ) && (false === strpos ($ values ['key ' ], ' # ' ) || in_array ($ values ['key ' ][0 ], array ('" ' , "' " )))) {
122
129
if ($ context && 'sequence ' == $ context ) {
123
- throw new ParseException ('You cannot define a mapping item when in a sequence ' );
130
+ throw new ParseException ('You cannot define a mapping item when in a sequence ' , $ this -> currentLineNb + 1 , $ this -> currentLine );
124
131
}
125
132
$ context = 'mapping ' ;
126
133
@@ -167,7 +174,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
167
174
$ value = $ this ->getNextEmbedBlock ();
168
175
}
169
176
$ c = $ this ->getRealCurrentLineNb () + 1 ;
170
- $ parser = new self ($ c );
177
+ $ parser = new self ($ c, $ this -> totalNumberOfLines );
171
178
$ parser ->refs = &$ this ->refs ;
172
179
$ parsed = $ parser ->parse ($ value , $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
173
180
@@ -218,7 +225,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
218
225
}
219
226
} else {
220
227
$ c = $ this ->getRealCurrentLineNb () + 1 ;
221
- $ parser = new self ($ c );
228
+ $ parser = new self ($ c, $ this -> totalNumberOfLines );
222
229
$ parser ->refs = &$ this ->refs ;
223
230
$ value = $ parser ->parse ($ this ->getNextEmbedBlock (), $ exceptionOnInvalidType , $ objectSupport , $ objectForMap );
224
231
// Spec: Keys MUST be unique; first one wins.
@@ -241,7 +248,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
241
248
} else {
242
249
// multiple documents are not supported
243
250
if ('--- ' === $ this ->currentLine ) {
244
- throw new ParseException ('Multiple documents are not supported. ' );
251
+ throw new ParseException ('Multiple documents are not supported. ' , $ this -> currentLineNb + 1 , $ this -> currentLine );
245
252
}
246
253
247
254
// 1-liner optionally followed by newline(s)
@@ -488,7 +495,7 @@ private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $ob
488
495
}
489
496
490
497
if (!array_key_exists ($ value , $ this ->refs )) {
491
- throw new ParseException (sprintf ('Reference "%s" does not exist. ' , $ value ), $ this ->currentLine );
498
+ throw new ParseException (sprintf ('Reference "%s" does not exist. ' , $ value ), $ this ->currentLineNb + 1 , $ this -> currentLine );
492
499
}
493
500
494
501
return $ this ->refs [$ value ];
@@ -580,6 +587,8 @@ private function parseBlockScalar($style, $chomping = '', $indentation = 0)
580
587
if ($ notEOF ) {
581
588
$ blockLines [] = '' ;
582
589
$ this ->moveToPreviousLine ();
590
+ } elseif (!$ notEOF && !$ this ->isCurrentLineLastLineInDocument ()) {
591
+ $ blockLines [] = '' ;
583
592
}
584
593
585
594
// folded style
@@ -686,6 +695,11 @@ private function isCurrentLineComment()
686
695
return '' !== $ ltrimmedLine && $ ltrimmedLine [0 ] === '# ' ;
687
696
}
688
697
698
+ private function isCurrentLineLastLineInDocument ()
699
+ {
700
+ return ($ this ->offset + $ this ->currentLineNb ) >= ($ this ->totalNumberOfLines - 1 );
701
+ }
702
+
689
703
/**
690
704
* Cleanups a YAML string to be parsed.
691
705
*
@@ -763,7 +777,7 @@ private function isNextLineUnIndentedCollection()
763
777
*/
764
778
private function isStringUnIndentedCollectionItem ()
765
779
{
766
- return 0 === strpos ($ this ->currentLine , '- ' );
780
+ return ' - ' === rtrim ( $ this -> currentLine ) || 0 === strpos ($ this ->currentLine , '- ' );
767
781
}
768
782
769
783
/**
0 commit comments