annotate vendor/nikic/php-parser/lib/PhpParser/JsonDecoder.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 5fb285c0d0e3
children
rev   line source
Chris@13 1 <?php declare(strict_types=1);
Chris@13 2
Chris@13 3 namespace PhpParser;
Chris@13 4
Chris@13 5 class JsonDecoder
Chris@13 6 {
Chris@13 7 /** @var \ReflectionClass[] Node type to reflection class map */
Chris@13 8 private $reflectionClassCache;
Chris@13 9
Chris@13 10 public function decode(string $json) {
Chris@13 11 $value = json_decode($json, true);
Chris@13 12 if (json_last_error()) {
Chris@13 13 throw new \RuntimeException('JSON decoding error: ' . json_last_error_msg());
Chris@13 14 }
Chris@13 15
Chris@13 16 return $this->decodeRecursive($value);
Chris@13 17 }
Chris@13 18
Chris@13 19 private function decodeRecursive($value) {
Chris@13 20 if (\is_array($value)) {
Chris@13 21 if (isset($value['nodeType'])) {
Chris@13 22 if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') {
Chris@13 23 return $this->decodeComment($value);
Chris@13 24 }
Chris@13 25 return $this->decodeNode($value);
Chris@13 26 }
Chris@13 27 return $this->decodeArray($value);
Chris@13 28 }
Chris@13 29 return $value;
Chris@13 30 }
Chris@13 31
Chris@13 32 private function decodeArray(array $array) : array {
Chris@13 33 $decodedArray = [];
Chris@13 34 foreach ($array as $key => $value) {
Chris@13 35 $decodedArray[$key] = $this->decodeRecursive($value);
Chris@13 36 }
Chris@13 37 return $decodedArray;
Chris@13 38 }
Chris@13 39
Chris@13 40 private function decodeNode(array $value) : Node {
Chris@13 41 $nodeType = $value['nodeType'];
Chris@13 42 if (!\is_string($nodeType)) {
Chris@13 43 throw new \RuntimeException('Node type must be a string');
Chris@13 44 }
Chris@13 45
Chris@13 46 $reflectionClass = $this->reflectionClassFromNodeType($nodeType);
Chris@13 47 /** @var Node $node */
Chris@13 48 $node = $reflectionClass->newInstanceWithoutConstructor();
Chris@13 49
Chris@13 50 if (isset($value['attributes'])) {
Chris@13 51 if (!\is_array($value['attributes'])) {
Chris@13 52 throw new \RuntimeException('Attributes must be an array');
Chris@13 53 }
Chris@13 54
Chris@13 55 $node->setAttributes($this->decodeArray($value['attributes']));
Chris@13 56 }
Chris@13 57
Chris@13 58 foreach ($value as $name => $subNode) {
Chris@13 59 if ($name === 'nodeType' || $name === 'attributes') {
Chris@13 60 continue;
Chris@13 61 }
Chris@13 62
Chris@13 63 $node->$name = $this->decodeRecursive($subNode);
Chris@13 64 }
Chris@13 65
Chris@13 66 return $node;
Chris@13 67 }
Chris@13 68
Chris@13 69 private function decodeComment(array $value) : Comment {
Chris@13 70 $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
Chris@13 71 if (!isset($value['text'])) {
Chris@13 72 throw new \RuntimeException('Comment must have text');
Chris@13 73 }
Chris@13 74
Chris@13 75 return new $className(
Chris@13 76 $value['text'], $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1
Chris@13 77 );
Chris@13 78 }
Chris@13 79
Chris@13 80 private function reflectionClassFromNodeType(string $nodeType) : \ReflectionClass {
Chris@13 81 if (!isset($this->reflectionClassCache[$nodeType])) {
Chris@13 82 $className = $this->classNameFromNodeType($nodeType);
Chris@13 83 $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className);
Chris@13 84 }
Chris@13 85 return $this->reflectionClassCache[$nodeType];
Chris@13 86 }
Chris@13 87
Chris@13 88 private function classNameFromNodeType(string $nodeType) : string {
Chris@13 89 $className = 'PhpParser\\Node\\' . strtr($nodeType, '_', '\\');
Chris@13 90 if (class_exists($className)) {
Chris@13 91 return $className;
Chris@13 92 }
Chris@13 93
Chris@13 94 $className .= '_';
Chris@13 95 if (class_exists($className)) {
Chris@13 96 return $className;
Chris@13 97 }
Chris@13 98
Chris@13 99 throw new \RuntimeException("Unknown node type \"$nodeType\"");
Chris@13 100 }
Chris@13 101 }