Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace PhpParser;
|
Chris@0
|
4
|
Chris@0
|
5 use PhpParser\Comment;
|
Chris@0
|
6 use PhpParser\Node\Expr;
|
Chris@0
|
7 use PhpParser\Node\Name;
|
Chris@0
|
8 use PhpParser\Node\NullableType;
|
Chris@0
|
9 use PhpParser\Node\Scalar;
|
Chris@0
|
10 use PhpParser\Node\Stmt;
|
Chris@0
|
11
|
Chris@0
|
12 abstract class BuilderAbstract implements Builder {
|
Chris@0
|
13 /**
|
Chris@0
|
14 * Normalizes a node: Converts builder objects to nodes.
|
Chris@0
|
15 *
|
Chris@0
|
16 * @param Node|Builder $node The node to normalize
|
Chris@0
|
17 *
|
Chris@0
|
18 * @return Node The normalized node
|
Chris@0
|
19 */
|
Chris@0
|
20 protected function normalizeNode($node) {
|
Chris@0
|
21 if ($node instanceof Builder) {
|
Chris@0
|
22 return $node->getNode();
|
Chris@0
|
23 } elseif ($node instanceof Node) {
|
Chris@0
|
24 return $node;
|
Chris@0
|
25 }
|
Chris@0
|
26
|
Chris@0
|
27 throw new \LogicException('Expected node or builder object');
|
Chris@0
|
28 }
|
Chris@0
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * Normalizes a name: Converts plain string names to PhpParser\Node\Name.
|
Chris@0
|
32 *
|
Chris@0
|
33 * @param Name|string $name The name to normalize
|
Chris@0
|
34 *
|
Chris@0
|
35 * @return Name The normalized name
|
Chris@0
|
36 */
|
Chris@0
|
37 protected function normalizeName($name) {
|
Chris@0
|
38 if ($name instanceof Name) {
|
Chris@0
|
39 return $name;
|
Chris@0
|
40 } elseif (is_string($name)) {
|
Chris@0
|
41 if (!$name) {
|
Chris@0
|
42 throw new \LogicException('Name cannot be empty');
|
Chris@0
|
43 }
|
Chris@0
|
44
|
Chris@0
|
45 if ($name[0] == '\\') {
|
Chris@0
|
46 return new Name\FullyQualified(substr($name, 1));
|
Chris@0
|
47 } elseif (0 === strpos($name, 'namespace\\')) {
|
Chris@0
|
48 return new Name\Relative(substr($name, strlen('namespace\\')));
|
Chris@0
|
49 } else {
|
Chris@0
|
50 return new Name($name);
|
Chris@0
|
51 }
|
Chris@0
|
52 }
|
Chris@0
|
53
|
Chris@0
|
54 throw new \LogicException('Name must be a string or an instance of PhpParser\Node\Name');
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 /**
|
Chris@0
|
58 * Normalizes a type: Converts plain-text type names into proper AST representation.
|
Chris@0
|
59 *
|
Chris@0
|
60 * In particular, builtin types are left as strings, custom types become Names and nullables
|
Chris@0
|
61 * are wrapped in NullableType nodes.
|
Chris@0
|
62 *
|
Chris@0
|
63 * @param Name|string|NullableType $type The type to normalize
|
Chris@0
|
64 *
|
Chris@0
|
65 * @return Name|string|NullableType The normalized type
|
Chris@0
|
66 */
|
Chris@0
|
67 protected function normalizeType($type) {
|
Chris@0
|
68 if (!is_string($type)) {
|
Chris@0
|
69 if (!$type instanceof Name && !$type instanceof NullableType) {
|
Chris@0
|
70 throw new \LogicException(
|
Chris@0
|
71 'Type must be a string, or an instance of Name or NullableType');
|
Chris@0
|
72 }
|
Chris@0
|
73 return $type;
|
Chris@0
|
74 }
|
Chris@0
|
75
|
Chris@0
|
76 $nullable = false;
|
Chris@0
|
77 if (strlen($type) > 0 && $type[0] === '?') {
|
Chris@0
|
78 $nullable = true;
|
Chris@0
|
79 $type = substr($type, 1);
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 $builtinTypes = array(
|
Chris@0
|
83 'array', 'callable', 'string', 'int', 'float', 'bool', 'iterable', 'void', 'object'
|
Chris@0
|
84 );
|
Chris@0
|
85
|
Chris@0
|
86 $lowerType = strtolower($type);
|
Chris@0
|
87 if (in_array($lowerType, $builtinTypes)) {
|
Chris@0
|
88 $type = $lowerType;
|
Chris@0
|
89 } else {
|
Chris@0
|
90 $type = $this->normalizeName($type);
|
Chris@0
|
91 }
|
Chris@0
|
92
|
Chris@0
|
93 if ($nullable && $type === 'void') {
|
Chris@0
|
94 throw new \LogicException('void type cannot be nullable');
|
Chris@0
|
95 }
|
Chris@0
|
96
|
Chris@0
|
97 return $nullable ? new Node\NullableType($type) : $type;
|
Chris@0
|
98 }
|
Chris@0
|
99
|
Chris@0
|
100 /**
|
Chris@0
|
101 * Normalizes a value: Converts nulls, booleans, integers,
|
Chris@0
|
102 * floats, strings and arrays into their respective nodes
|
Chris@0
|
103 *
|
Chris@0
|
104 * @param mixed $value The value to normalize
|
Chris@0
|
105 *
|
Chris@0
|
106 * @return Expr The normalized value
|
Chris@0
|
107 */
|
Chris@0
|
108 protected function normalizeValue($value) {
|
Chris@0
|
109 if ($value instanceof Node) {
|
Chris@0
|
110 return $value;
|
Chris@0
|
111 } elseif (is_null($value)) {
|
Chris@0
|
112 return new Expr\ConstFetch(
|
Chris@0
|
113 new Name('null')
|
Chris@0
|
114 );
|
Chris@0
|
115 } elseif (is_bool($value)) {
|
Chris@0
|
116 return new Expr\ConstFetch(
|
Chris@0
|
117 new Name($value ? 'true' : 'false')
|
Chris@0
|
118 );
|
Chris@0
|
119 } elseif (is_int($value)) {
|
Chris@0
|
120 return new Scalar\LNumber($value);
|
Chris@0
|
121 } elseif (is_float($value)) {
|
Chris@0
|
122 return new Scalar\DNumber($value);
|
Chris@0
|
123 } elseif (is_string($value)) {
|
Chris@0
|
124 return new Scalar\String_($value);
|
Chris@0
|
125 } elseif (is_array($value)) {
|
Chris@0
|
126 $items = array();
|
Chris@0
|
127 $lastKey = -1;
|
Chris@0
|
128 foreach ($value as $itemKey => $itemValue) {
|
Chris@0
|
129 // for consecutive, numeric keys don't generate keys
|
Chris@0
|
130 if (null !== $lastKey && ++$lastKey === $itemKey) {
|
Chris@0
|
131 $items[] = new Expr\ArrayItem(
|
Chris@0
|
132 $this->normalizeValue($itemValue)
|
Chris@0
|
133 );
|
Chris@0
|
134 } else {
|
Chris@0
|
135 $lastKey = null;
|
Chris@0
|
136 $items[] = new Expr\ArrayItem(
|
Chris@0
|
137 $this->normalizeValue($itemValue),
|
Chris@0
|
138 $this->normalizeValue($itemKey)
|
Chris@0
|
139 );
|
Chris@0
|
140 }
|
Chris@0
|
141 }
|
Chris@0
|
142
|
Chris@0
|
143 return new Expr\Array_($items);
|
Chris@0
|
144 } else {
|
Chris@0
|
145 throw new \LogicException('Invalid value');
|
Chris@0
|
146 }
|
Chris@0
|
147 }
|
Chris@0
|
148
|
Chris@0
|
149 /**
|
Chris@0
|
150 * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc.
|
Chris@0
|
151 *
|
Chris@0
|
152 * @param Comment\Doc|string $docComment The doc comment to normalize
|
Chris@0
|
153 *
|
Chris@0
|
154 * @return Comment\Doc The normalized doc comment
|
Chris@0
|
155 */
|
Chris@0
|
156 protected function normalizeDocComment($docComment) {
|
Chris@0
|
157 if ($docComment instanceof Comment\Doc) {
|
Chris@0
|
158 return $docComment;
|
Chris@0
|
159 } else if (is_string($docComment)) {
|
Chris@0
|
160 return new Comment\Doc($docComment);
|
Chris@0
|
161 } else {
|
Chris@0
|
162 throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
|
Chris@0
|
163 }
|
Chris@0
|
164 }
|
Chris@0
|
165
|
Chris@0
|
166 /**
|
Chris@0
|
167 * Sets a modifier in the $this->type property.
|
Chris@0
|
168 *
|
Chris@0
|
169 * @param int $modifier Modifier to set
|
Chris@0
|
170 */
|
Chris@0
|
171 protected function setModifier($modifier) {
|
Chris@0
|
172 Stmt\Class_::verifyModifier($this->flags, $modifier);
|
Chris@0
|
173 $this->flags |= $modifier;
|
Chris@0
|
174 }
|
Chris@0
|
175 }
|