Mercurial > hg > cmmr2012-drupal-site
comparison vendor/symfony/yaml/Parser.php @ 4:a9cd425dd02b
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:11:55 +0000 |
parents | c75dbcec494b |
children | 12f9dff5fda9 |
comparison
equal
deleted
inserted
replaced
3:307d7a7fd348 | 4:a9cd425dd02b |
---|---|
27 const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?'; | 27 const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?'; |
28 | 28 |
29 private $filename; | 29 private $filename; |
30 private $offset = 0; | 30 private $offset = 0; |
31 private $totalNumberOfLines; | 31 private $totalNumberOfLines; |
32 private $lines = array(); | 32 private $lines = []; |
33 private $currentLineNb = -1; | 33 private $currentLineNb = -1; |
34 private $currentLine = ''; | 34 private $currentLine = ''; |
35 private $refs = array(); | 35 private $refs = []; |
36 private $skippedLineNumbers = array(); | 36 private $skippedLineNumbers = []; |
37 private $locallySkippedLineNumbers = array(); | 37 private $locallySkippedLineNumbers = []; |
38 private $refsBeingParsed = []; | |
38 | 39 |
39 public function __construct() | 40 public function __construct() |
40 { | 41 { |
41 if (func_num_args() > 0) { | 42 if (\func_num_args() > 0) { |
42 @trigger_error(sprintf('The constructor arguments $offset, $totalNumberOfLines, $skippedLineNumbers of %s are deprecated and will be removed in 4.0', self::class), E_USER_DEPRECATED); | 43 @trigger_error(sprintf('The constructor arguments $offset, $totalNumberOfLines, $skippedLineNumbers of %s are deprecated and will be removed in 4.0', self::class), E_USER_DEPRECATED); |
43 | 44 |
44 $this->offset = func_get_arg(0); | 45 $this->offset = func_get_arg(0); |
45 if (func_num_args() > 1) { | 46 if (\func_num_args() > 1) { |
46 $this->totalNumberOfLines = func_get_arg(1); | 47 $this->totalNumberOfLines = func_get_arg(1); |
47 } | 48 } |
48 if (func_num_args() > 2) { | 49 if (\func_num_args() > 2) { |
49 $this->skippedLineNumbers = func_get_arg(2); | 50 $this->skippedLineNumbers = func_get_arg(2); |
50 } | 51 } |
51 } | 52 } |
52 } | 53 } |
53 | 54 |
90 * | 91 * |
91 * @throws ParseException If the YAML is not valid | 92 * @throws ParseException If the YAML is not valid |
92 */ | 93 */ |
93 public function parse($value, $flags = 0) | 94 public function parse($value, $flags = 0) |
94 { | 95 { |
95 if (is_bool($flags)) { | 96 if (\is_bool($flags)) { |
96 @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); | 97 @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); |
97 | 98 |
98 if ($flags) { | 99 if ($flags) { |
99 $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE; | 100 $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE; |
100 } else { | 101 } else { |
101 $flags = 0; | 102 $flags = 0; |
102 } | 103 } |
103 } | 104 } |
104 | 105 |
105 if (func_num_args() >= 3) { | 106 if (\func_num_args() >= 3) { |
106 @trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED); | 107 @trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED); |
107 | 108 |
108 if (func_get_arg(2)) { | 109 if (func_get_arg(2)) { |
109 $flags |= Yaml::PARSE_OBJECT; | 110 $flags |= Yaml::PARSE_OBJECT; |
110 } | 111 } |
111 } | 112 } |
112 | 113 |
113 if (func_num_args() >= 4) { | 114 if (\func_num_args() >= 4) { |
114 @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED); | 115 @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED); |
115 | 116 |
116 if (func_get_arg(3)) { | 117 if (func_get_arg(3)) { |
117 $flags |= Yaml::PARSE_OBJECT_FOR_MAP; | 118 $flags |= Yaml::PARSE_OBJECT_FOR_MAP; |
118 } | 119 } |
124 | 125 |
125 if (false === preg_match('//u', $value)) { | 126 if (false === preg_match('//u', $value)) { |
126 throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename); | 127 throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename); |
127 } | 128 } |
128 | 129 |
129 $this->refs = array(); | 130 $this->refs = []; |
130 | 131 |
131 $mbEncoding = null; | 132 $mbEncoding = null; |
132 $e = null; | 133 $e = null; |
133 $data = null; | 134 $data = null; |
134 | 135 |
145 | 146 |
146 if (null !== $mbEncoding) { | 147 if (null !== $mbEncoding) { |
147 mb_internal_encoding($mbEncoding); | 148 mb_internal_encoding($mbEncoding); |
148 } | 149 } |
149 | 150 |
150 $this->lines = array(); | 151 $this->lines = []; |
151 $this->currentLine = ''; | 152 $this->currentLine = ''; |
152 $this->refs = array(); | 153 $this->refs = []; |
153 $this->skippedLineNumbers = array(); | 154 $this->skippedLineNumbers = []; |
154 $this->locallySkippedLineNumbers = array(); | 155 $this->locallySkippedLineNumbers = []; |
155 | 156 |
156 if (null !== $e) { | 157 if (null !== $e) { |
157 throw $e; | 158 throw $e; |
158 } | 159 } |
159 | 160 |
164 { | 165 { |
165 $this->currentLineNb = -1; | 166 $this->currentLineNb = -1; |
166 $this->currentLine = ''; | 167 $this->currentLine = ''; |
167 $value = $this->cleanup($value); | 168 $value = $this->cleanup($value); |
168 $this->lines = explode("\n", $value); | 169 $this->lines = explode("\n", $value); |
169 $this->locallySkippedLineNumbers = array(); | 170 $this->locallySkippedLineNumbers = []; |
170 | 171 |
171 if (null === $this->totalNumberOfLines) { | 172 if (null === $this->totalNumberOfLines) { |
172 $this->totalNumberOfLines = count($this->lines); | 173 $this->totalNumberOfLines = \count($this->lines); |
173 } | 174 } |
174 | 175 |
175 if (!$this->moveToNextLine()) { | 176 if (!$this->moveToNextLine()) { |
176 return null; | 177 return null; |
177 } | 178 } |
178 | 179 |
179 $data = array(); | 180 $data = []; |
180 $context = null; | 181 $context = null; |
181 $allowOverwrite = false; | 182 $allowOverwrite = false; |
182 | 183 |
183 while ($this->isCurrentLineEmpty()) { | 184 while ($this->isCurrentLineEmpty()) { |
184 if (!$this->moveToNextLine()) { | 185 if (!$this->moveToNextLine()) { |
210 } | 211 } |
211 $context = 'sequence'; | 212 $context = 'sequence'; |
212 | 213 |
213 if (isset($values['value']) && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) { | 214 if (isset($values['value']) && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) { |
214 $isRef = $matches['ref']; | 215 $isRef = $matches['ref']; |
216 $this->refsBeingParsed[] = $isRef; | |
215 $values['value'] = $matches['value']; | 217 $values['value'] = $matches['value']; |
216 } | 218 } |
217 | 219 |
218 if (isset($values['value'][1]) && '?' === $values['value'][0] && ' ' === $values['value'][1]) { | 220 if (isset($values['value'][1]) && '?' === $values['value'][0] && ' ' === $values['value'][1]) { |
219 @trigger_error($this->getDeprecationMessage('Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.'), E_USER_DEPRECATED); | 221 @trigger_error($this->getDeprecationMessage('Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.'), E_USER_DEPRECATED); |
232 && self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches) | 234 && self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches) |
233 ) { | 235 ) { |
234 // this is a compact notation element, add to next block and parse | 236 // this is a compact notation element, add to next block and parse |
235 $block = $values['value']; | 237 $block = $values['value']; |
236 if ($this->isNextLineIndented()) { | 238 if ($this->isNextLineIndented()) { |
237 $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values['leadspaces']) + 1); | 239 $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + \strlen($values['leadspaces']) + 1); |
238 } | 240 } |
239 | 241 |
240 $data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags); | 242 $data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags); |
241 } else { | 243 } else { |
242 $data[] = $this->parseValue($values['value'], $flags, $context); | 244 $data[] = $this->parseValue($values['value'], $flags, $context); |
243 } | 245 } |
244 } | 246 } |
245 if ($isRef) { | 247 if ($isRef) { |
246 $this->refs[$isRef] = end($data); | 248 $this->refs[$isRef] = end($data); |
249 array_pop($this->refsBeingParsed); | |
247 } | 250 } |
248 } elseif ( | 251 } elseif ( |
249 self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values) | 252 self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values) |
250 && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'"))) | 253 && (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"])) |
251 ) { | 254 ) { |
252 if ($context && 'sequence' == $context) { | 255 if ($context && 'sequence' == $context) { |
253 throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine, $this->filename); | 256 throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine, $this->filename); |
254 } | 257 } |
255 $context = 'mapping'; | 258 $context = 'mapping'; |
269 $e->setSnippet($this->currentLine); | 272 $e->setSnippet($this->currentLine); |
270 | 273 |
271 throw $e; | 274 throw $e; |
272 } | 275 } |
273 | 276 |
274 if (!is_string($key) && !is_int($key)) { | 277 if (!\is_string($key) && !\is_int($key)) { |
275 $keyType = is_numeric($key) ? 'numeric key' : 'non-string key'; | 278 $keyType = is_numeric($key) ? 'numeric key' : 'non-string key'; |
276 @trigger_error($this->getDeprecationMessage(sprintf('Implicit casting of %s to string is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.', $keyType)), E_USER_DEPRECATED); | 279 @trigger_error($this->getDeprecationMessage(sprintf('Implicit casting of %s to string is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.', $keyType)), E_USER_DEPRECATED); |
277 } | 280 } |
278 | 281 |
279 // Convert float keys to strings, to avoid being converted to integers by PHP | 282 // Convert float keys to strings, to avoid being converted to integers by PHP |
280 if (is_float($key)) { | 283 if (\is_float($key)) { |
281 $key = (string) $key; | 284 $key = (string) $key; |
282 } | 285 } |
283 | 286 |
284 if ('<<' === $key && (!isset($values['value']) || !self::preg_match('#^&(?P<ref>[^ ]+)#u', $values['value'], $refMatches))) { | 287 if ('<<' === $key && (!isset($values['value']) || !self::preg_match('#^&(?P<ref>[^ ]+)#u', $values['value'], $refMatches))) { |
285 $mergeNode = true; | 288 $mergeNode = true; |
286 $allowOverwrite = true; | 289 $allowOverwrite = true; |
287 if (isset($values['value'][0]) && '*' === $values['value'][0]) { | 290 if (isset($values['value'][0]) && '*' === $values['value'][0]) { |
288 $refName = substr(rtrim($values['value']), 1); | 291 $refName = substr(rtrim($values['value']), 1); |
289 if (!array_key_exists($refName, $this->refs)) { | 292 if (!array_key_exists($refName, $this->refs)) { |
293 if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) { | |
294 throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename); | |
295 } | |
296 | |
290 throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); | 297 throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); |
291 } | 298 } |
292 | 299 |
293 $refValue = $this->refs[$refName]; | 300 $refValue = $this->refs[$refName]; |
294 | 301 |
295 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $refValue instanceof \stdClass) { | 302 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $refValue instanceof \stdClass) { |
296 $refValue = (array) $refValue; | 303 $refValue = (array) $refValue; |
297 } | 304 } |
298 | 305 |
299 if (!is_array($refValue)) { | 306 if (!\is_array($refValue)) { |
300 throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); | 307 throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); |
301 } | 308 } |
302 | 309 |
303 $data += $refValue; // array union | 310 $data += $refValue; // array union |
304 } else { | 311 } else { |
311 | 318 |
312 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsed instanceof \stdClass) { | 319 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsed instanceof \stdClass) { |
313 $parsed = (array) $parsed; | 320 $parsed = (array) $parsed; |
314 } | 321 } |
315 | 322 |
316 if (!is_array($parsed)) { | 323 if (!\is_array($parsed)) { |
317 throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); | 324 throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); |
318 } | 325 } |
319 | 326 |
320 if (isset($parsed[0])) { | 327 if (isset($parsed[0])) { |
321 // If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes | 328 // If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes |
324 foreach ($parsed as $parsedItem) { | 331 foreach ($parsed as $parsedItem) { |
325 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsedItem instanceof \stdClass) { | 332 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsedItem instanceof \stdClass) { |
326 $parsedItem = (array) $parsedItem; | 333 $parsedItem = (array) $parsedItem; |
327 } | 334 } |
328 | 335 |
329 if (!is_array($parsedItem)) { | 336 if (!\is_array($parsedItem)) { |
330 throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem, $this->filename); | 337 throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem, $this->filename); |
331 } | 338 } |
332 | 339 |
333 $data += $parsedItem; // array union | 340 $data += $parsedItem; // array union |
334 } | 341 } |
338 $data += $parsed; // array union | 345 $data += $parsed; // array union |
339 } | 346 } |
340 } | 347 } |
341 } elseif ('<<' !== $key && isset($values['value']) && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) { | 348 } elseif ('<<' !== $key && isset($values['value']) && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) { |
342 $isRef = $matches['ref']; | 349 $isRef = $matches['ref']; |
350 $this->refsBeingParsed[] = $isRef; | |
343 $values['value'] = $matches['value']; | 351 $values['value'] = $matches['value']; |
344 } | 352 } |
345 | 353 |
346 $subTag = null; | 354 $subTag = null; |
347 if ($mergeNode) { | 355 if ($mergeNode) { |
393 @trigger_error($this->getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED); | 401 @trigger_error($this->getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED); |
394 } | 402 } |
395 } | 403 } |
396 if ($isRef) { | 404 if ($isRef) { |
397 $this->refs[$isRef] = $data[$key]; | 405 $this->refs[$isRef] = $data[$key]; |
406 array_pop($this->refsBeingParsed); | |
398 } | 407 } |
399 } else { | 408 } else { |
400 // multiple documents are not supported | 409 // multiple documents are not supported |
401 if ('---' === $this->currentLine) { | 410 if ('---' === $this->currentLine) { |
402 throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename); | 411 throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename); |
405 if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) { | 414 if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) { |
406 @trigger_error($this->getDeprecationMessage('Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.'), E_USER_DEPRECATED); | 415 @trigger_error($this->getDeprecationMessage('Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.'), E_USER_DEPRECATED); |
407 } | 416 } |
408 | 417 |
409 // 1-liner optionally followed by newline(s) | 418 // 1-liner optionally followed by newline(s) |
410 if (is_string($value) && $this->lines[0] === trim($value)) { | 419 if (\is_string($value) && $this->lines[0] === trim($value)) { |
411 try { | 420 try { |
412 $value = Inline::parse($this->lines[0], $flags, $this->refs); | 421 $value = Inline::parse($this->lines[0], $flags, $this->refs); |
413 } catch (ParseException $e) { | 422 } catch (ParseException $e) { |
414 $e->setParsedLine($this->getRealCurrentLineNb() + 1); | 423 $e->setParsedLine($this->getRealCurrentLineNb() + 1); |
415 $e->setSnippet($this->currentLine); | 424 $e->setSnippet($this->currentLine); |
468 | 477 |
469 if (null !== $tag) { | 478 if (null !== $tag) { |
470 $data = new TaggedValue($tag, $data); | 479 $data = new TaggedValue($tag, $data); |
471 } | 480 } |
472 | 481 |
473 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && !is_object($data) && 'mapping' === $context) { | 482 if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && !\is_object($data) && 'mapping' === $context) { |
474 $object = new \stdClass(); | 483 $object = new \stdClass(); |
475 | 484 |
476 foreach ($data as $key => $value) { | 485 foreach ($data as $key => $value) { |
477 $object->$key = $value; | 486 $object->$key = $value; |
478 } | 487 } |
498 $parser = new self(); | 507 $parser = new self(); |
499 $parser->offset = $offset; | 508 $parser->offset = $offset; |
500 $parser->totalNumberOfLines = $this->totalNumberOfLines; | 509 $parser->totalNumberOfLines = $this->totalNumberOfLines; |
501 $parser->skippedLineNumbers = $skippedLineNumbers; | 510 $parser->skippedLineNumbers = $skippedLineNumbers; |
502 $parser->refs = &$this->refs; | 511 $parser->refs = &$this->refs; |
512 $parser->refsBeingParsed = $this->refsBeingParsed; | |
503 | 513 |
504 return $parser->doParse($yaml, $flags); | 514 return $parser->doParse($yaml, $flags); |
505 } | 515 } |
506 | 516 |
507 /** | 517 /** |
531 * | 541 * |
532 * @return int The current line indentation | 542 * @return int The current line indentation |
533 */ | 543 */ |
534 private function getCurrentLineIndentation() | 544 private function getCurrentLineIndentation() |
535 { | 545 { |
536 return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' ')); | 546 return \strlen($this->currentLine) - \strlen(ltrim($this->currentLine, ' ')); |
537 } | 547 } |
538 | 548 |
539 /** | 549 /** |
540 * Returns the next embed block of YAML. | 550 * Returns the next embed block of YAML. |
541 * | 551 * |
547 * @throws ParseException When indentation problem are detected | 557 * @throws ParseException When indentation problem are detected |
548 */ | 558 */ |
549 private function getNextEmbedBlock($indentation = null, $inSequence = false) | 559 private function getNextEmbedBlock($indentation = null, $inSequence = false) |
550 { | 560 { |
551 $oldLineIndentation = $this->getCurrentLineIndentation(); | 561 $oldLineIndentation = $this->getCurrentLineIndentation(); |
552 $blockScalarIndentations = array(); | |
553 | |
554 if ($this->isBlockScalarHeader()) { | |
555 $blockScalarIndentations[] = $oldLineIndentation; | |
556 } | |
557 | 562 |
558 if (!$this->moveToNextLine()) { | 563 if (!$this->moveToNextLine()) { |
559 return; | 564 return; |
560 } | 565 } |
561 | 566 |
589 } | 594 } |
590 } else { | 595 } else { |
591 $newIndent = $indentation; | 596 $newIndent = $indentation; |
592 } | 597 } |
593 | 598 |
594 $data = array(); | 599 $data = []; |
595 if ($this->getCurrentLineIndentation() >= $newIndent) { | 600 if ($this->getCurrentLineIndentation() >= $newIndent) { |
596 $data[] = substr($this->currentLine, $newIndent); | 601 $data[] = substr($this->currentLine, $newIndent); |
597 } elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) { | 602 } elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) { |
598 $data[] = $this->currentLine; | 603 $data[] = $this->currentLine; |
599 } else { | 604 } else { |
610 return; | 615 return; |
611 } | 616 } |
612 | 617 |
613 $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); | 618 $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); |
614 | 619 |
615 if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) { | |
616 $blockScalarIndentations[] = $this->getCurrentLineIndentation(); | |
617 } | |
618 | |
619 $previousLineIndentation = $this->getCurrentLineIndentation(); | |
620 | |
621 while ($this->moveToNextLine()) { | 620 while ($this->moveToNextLine()) { |
622 $indent = $this->getCurrentLineIndentation(); | 621 $indent = $this->getCurrentLineIndentation(); |
623 | |
624 // terminate all block scalars that are more indented than the current line | |
625 if (!empty($blockScalarIndentations) && $indent < $previousLineIndentation && '' !== trim($this->currentLine)) { | |
626 foreach ($blockScalarIndentations as $key => $blockScalarIndentation) { | |
627 if ($blockScalarIndentation >= $indent) { | |
628 unset($blockScalarIndentations[$key]); | |
629 } | |
630 } | |
631 } | |
632 | |
633 if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) { | |
634 $blockScalarIndentations[] = $indent; | |
635 } | |
636 | |
637 $previousLineIndentation = $indent; | |
638 | 622 |
639 if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { | 623 if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { |
640 $this->moveToPreviousLine(); | 624 $this->moveToPreviousLine(); |
641 break; | 625 break; |
642 } | 626 } |
667 * | 651 * |
668 * @return bool | 652 * @return bool |
669 */ | 653 */ |
670 private function moveToNextLine() | 654 private function moveToNextLine() |
671 { | 655 { |
672 if ($this->currentLineNb >= count($this->lines) - 1) { | 656 if ($this->currentLineNb >= \count($this->lines) - 1) { |
673 return false; | 657 return false; |
674 } | 658 } |
675 | 659 |
676 $this->currentLine = $this->lines[++$this->currentLineNb]; | 660 $this->currentLine = $this->lines[++$this->currentLineNb]; |
677 | 661 |
713 } else { | 697 } else { |
714 $value = substr($value, 1); | 698 $value = substr($value, 1); |
715 } | 699 } |
716 | 700 |
717 if (!array_key_exists($value, $this->refs)) { | 701 if (!array_key_exists($value, $this->refs)) { |
702 if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) { | |
703 throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); | |
704 } | |
705 | |
718 throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); | 706 throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); |
719 } | 707 } |
720 | 708 |
721 return $this->refs[$value]; | 709 return $this->refs[$value]; |
722 } | 710 } |
745 // do not take following lines into account when the current line is a quoted single line value | 733 // do not take following lines into account when the current line is a quoted single line value |
746 if (null !== $quotation && self::preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) { | 734 if (null !== $quotation && self::preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) { |
747 return Inline::parse($value, $flags, $this->refs); | 735 return Inline::parse($value, $flags, $this->refs); |
748 } | 736 } |
749 | 737 |
750 $lines = array(); | 738 $lines = []; |
751 | 739 |
752 while ($this->moveToNextLine()) { | 740 while ($this->moveToNextLine()) { |
753 // unquoted strings end before the first unindented line | 741 // unquoted strings end before the first unindented line |
754 if (null === $quotation && 0 === $this->getCurrentLineIndentation()) { | 742 if (null === $quotation && 0 === $this->getCurrentLineIndentation()) { |
755 $this->moveToPreviousLine(); | 743 $this->moveToPreviousLine(); |
763 if ('' !== $this->currentLine && substr($this->currentLine, -1) === $quotation) { | 751 if ('' !== $this->currentLine && substr($this->currentLine, -1) === $quotation) { |
764 break; | 752 break; |
765 } | 753 } |
766 } | 754 } |
767 | 755 |
768 for ($i = 0, $linesCount = count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) { | 756 for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) { |
769 if ('' === $lines[$i]) { | 757 if ('' === $lines[$i]) { |
770 $value .= "\n"; | 758 $value .= "\n"; |
771 $previousLineBlank = true; | 759 $previousLineBlank = true; |
772 } elseif ($previousLineBlank) { | 760 } elseif ($previousLineBlank) { |
773 $value .= $lines[$i]; | 761 $value .= $lines[$i]; |
780 | 768 |
781 Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); | 769 Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); |
782 | 770 |
783 $parsedValue = Inline::parse($value, $flags, $this->refs); | 771 $parsedValue = Inline::parse($value, $flags, $this->refs); |
784 | 772 |
785 if ('mapping' === $context && is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) { | 773 if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) { |
786 throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename); | 774 throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename); |
787 } | 775 } |
788 | 776 |
789 return $parsedValue; | 777 return $parsedValue; |
790 } catch (ParseException $e) { | 778 } catch (ParseException $e) { |
810 if (!$notEOF) { | 798 if (!$notEOF) { |
811 return ''; | 799 return ''; |
812 } | 800 } |
813 | 801 |
814 $isCurrentLineBlank = $this->isCurrentLineBlank(); | 802 $isCurrentLineBlank = $this->isCurrentLineBlank(); |
815 $blockLines = array(); | 803 $blockLines = []; |
816 | 804 |
817 // leading blank lines are consumed before determining indentation | 805 // leading blank lines are consumed before determining indentation |
818 while ($notEOF && $isCurrentLineBlank) { | 806 while ($notEOF && $isCurrentLineBlank) { |
819 // newline only if not EOF | 807 // newline only if not EOF |
820 if ($notEOF = $this->moveToNextLine()) { | 808 if ($notEOF = $this->moveToNextLine()) { |
824 } | 812 } |
825 | 813 |
826 // determine indentation if not specified | 814 // determine indentation if not specified |
827 if (0 === $indentation) { | 815 if (0 === $indentation) { |
828 if (self::preg_match('/^ +/', $this->currentLine, $matches)) { | 816 if (self::preg_match('/^ +/', $this->currentLine, $matches)) { |
829 $indentation = strlen($matches[0]); | 817 $indentation = \strlen($matches[0]); |
830 } | 818 } |
831 } | 819 } |
832 | 820 |
833 if ($indentation > 0) { | 821 if ($indentation > 0) { |
834 $pattern = sprintf('/^ {%d}(.*)$/', $indentation); | 822 $pattern = sprintf('/^ {%d}(.*)$/', $indentation); |
837 $notEOF && ( | 825 $notEOF && ( |
838 $isCurrentLineBlank || | 826 $isCurrentLineBlank || |
839 self::preg_match($pattern, $this->currentLine, $matches) | 827 self::preg_match($pattern, $this->currentLine, $matches) |
840 ) | 828 ) |
841 ) { | 829 ) { |
842 if ($isCurrentLineBlank && strlen($this->currentLine) > $indentation) { | 830 if ($isCurrentLineBlank && \strlen($this->currentLine) > $indentation) { |
843 $blockLines[] = substr($this->currentLine, $indentation); | 831 $blockLines[] = substr($this->currentLine, $indentation); |
844 } elseif ($isCurrentLineBlank) { | 832 } elseif ($isCurrentLineBlank) { |
845 $blockLines[] = ''; | 833 $blockLines[] = ''; |
846 } else { | 834 } else { |
847 $blockLines[] = $matches[1]; | 835 $blockLines[] = $matches[1]; |
867 if ('>' === $style) { | 855 if ('>' === $style) { |
868 $text = ''; | 856 $text = ''; |
869 $previousLineIndented = false; | 857 $previousLineIndented = false; |
870 $previousLineBlank = false; | 858 $previousLineBlank = false; |
871 | 859 |
872 for ($i = 0, $blockLinesCount = count($blockLines); $i < $blockLinesCount; ++$i) { | 860 for ($i = 0, $blockLinesCount = \count($blockLines); $i < $blockLinesCount; ++$i) { |
873 if ('' === $blockLines[$i]) { | 861 if ('' === $blockLines[$i]) { |
874 $text .= "\n"; | 862 $text .= "\n"; |
875 $previousLineIndented = false; | 863 $previousLineIndented = false; |
876 $previousLineBlank = true; | 864 $previousLineBlank = true; |
877 } elseif (' ' === $blockLines[$i][0]) { | 865 } elseif (' ' === $blockLines[$i][0]) { |
982 * | 970 * |
983 * @return string A cleaned up YAML string | 971 * @return string A cleaned up YAML string |
984 */ | 972 */ |
985 private function cleanup($value) | 973 private function cleanup($value) |
986 { | 974 { |
987 $value = str_replace(array("\r\n", "\r"), "\n", $value); | 975 $value = str_replace(["\r\n", "\r"], "\n", $value); |
988 | 976 |
989 // strip YAML header | 977 // strip YAML header |
990 $count = 0; | 978 $count = 0; |
991 $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u', '', $value, -1, $count); | 979 $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u', '', $value, -1, $count); |
992 $this->offset += $count; | 980 $this->offset += $count; |
1050 * @return bool Returns true if the string is un-indented collection item, false otherwise | 1038 * @return bool Returns true if the string is un-indented collection item, false otherwise |
1051 */ | 1039 */ |
1052 private function isStringUnIndentedCollectionItem() | 1040 private function isStringUnIndentedCollectionItem() |
1053 { | 1041 { |
1054 return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- '); | 1042 return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- '); |
1055 } | |
1056 | |
1057 /** | |
1058 * Tests whether or not the current line is the header of a block scalar. | |
1059 * | |
1060 * @return bool | |
1061 */ | |
1062 private function isBlockScalarHeader() | |
1063 { | |
1064 return (bool) self::preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine); | |
1065 } | 1043 } |
1066 | 1044 |
1067 /** | 1045 /** |
1068 * A local wrapper for `preg_match` which will throw a ParseException if there | 1046 * A local wrapper for `preg_match` which will throw a ParseException if there |
1069 * is an internal error in the PCRE engine. | 1047 * is an internal error in the PCRE engine. |