1: <?php
2: namespace Pharborist;
3:
4: use Pharborist\Types\ArrayNode;
5:
6: 7: 8: 9:
10: class CommaListNode extends ParentNode {
11: 12: 13:
14: public function getItems() {
15: $items = [];
16: $child = $this->head;
17: while ($child) {
18: if ($child instanceof HiddenNode) {
19:
20: }
21: elseif ($child instanceof TokenNode && $child->getType() === ',') {
22:
23: }
24: else {
25: $items[] = $child;
26: }
27: $child = $child->next;
28: }
29: return new NodeCollection($items, FALSE);
30: }
31:
32: 33: 34: 35: 36: 37:
38: public function getItem($index) {
39: if ($index < 0) {
40: throw new \OutOfBoundsException('Index is out of bounds');
41: }
42: $i = 0;
43: $child = $this->head;
44: while ($child) {
45: if ($child instanceof HiddenNode) {
46:
47: }
48: elseif ($child instanceof TokenNode && $child->getType() === ',') {
49:
50: }
51: else {
52: if ($i === $index) {
53: return $child;
54: }
55: $i++;
56: }
57: $child = $child->next;
58: }
59: throw new \OutOfBoundsException('Index is out of bounds');
60: }
61:
62: 63: 64: 65: 66: 67:
68: public function prependItem(Node $item) {
69: if ($this->getItems()->isEmpty()) {
70: $this->append($item);
71: }
72: else {
73: $this->prepend([
74: $item,
75: Token::comma(),
76: Token::space(),
77: ]);
78: }
79: return $this;
80: }
81:
82: 83: 84: 85: 86: 87:
88: public function appendItem(Node $item) {
89: if ($this->getItems()->isEmpty()) {
90: $this->append($item);
91: }
92: else {
93: $this->append([
94: Token::comma(),
95: Token::space(),
96: $item,
97: ]);
98: }
99: return $this;
100: }
101:
102: 103: 104: 105: 106: 107: 108: 109: 110:
111: public function insertItem(Node $item, $index) {
112: $items = $this->getItems();
113: if ($items->isEmpty()) {
114: if ($index !== 0) {
115: throw new \OutOfBoundsException('index out of bounds');
116: }
117: $this->append($item);
118: }
119: else {
120: $max_index = count($items) - 1;
121: if ($index < 0 || $index > $max_index) {
122: throw new \OutOfBoundsException('index out of bounds');
123: }
124: $items[$index]->before([
125: $item,
126: Token::comma(),
127: Token::space(),
128: ]);
129: }
130: return $this;
131: }
132:
133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143:
144: public function removeItem($item) {
145: if (is_int($item)) {
146: $index = $item;
147: if ($index < 0) {
148: throw new \OutOfBoundsException('index out of bounds');
149: }
150: $items = $this->getItems();
151: if ($index >= count($items)) {
152: throw new \OutOfBoundsException('index out of bounds');
153: }
154: $item = $items[$index];
155: $is_last = $index === count($items) - 1;
156: }
157: else {
158: if ($item->parent() !== $this) {
159: throw new \InvalidArgumentException('invalid item');
160: }
161: $items = $this->getItems();
162: $last_index = count($items) - 1;
163: $last_item = $items[$last_index];
164: $is_last = $last_item === $item;
165: }
166: if (count($items) === 1) {
167:
168: }
169: elseif ($is_last) {
170: $item->previousUntil(function ($node) {
171: if ($node instanceof HiddenNode) {
172: return FALSE;
173: }
174: if ($node instanceof TokenNode && $node->getType() === ',') {
175: return FALSE;
176: }
177: return TRUE;
178: })->remove();
179: }
180: else {
181: $item->nextUntil(function ($node) {
182: if ($node instanceof HiddenNode) {
183: return FALSE;
184: }
185: if ($node instanceof TokenNode && $node->getType() === ',') {
186: return FALSE;
187: }
188: return TRUE;
189: })->remove();
190: }
191: $item->remove();
192: return $this;
193: }
194:
195: 196: 197: 198: 199: 200:
201: public function pop() {
202: $items = $this->getItems();
203: if ($items->isEmpty()) {
204: return NULL;
205: }
206: if (count($items) === 1) {
207: $pop_item = $items[0];
208: $pop_item->remove();
209: return $pop_item;
210: }
211: $pop_item = $items[count($items) - 1];
212: $pop_item->previousUntil(function ($node) {
213: if ($node instanceof HiddenNode) {
214: return FALSE;
215: }
216: if ($node instanceof TokenNode && $node->getType() === ',') {
217: return FALSE;
218: }
219: return TRUE;
220: })->remove();
221: $pop_item->remove();
222: return $pop_item;
223: }
224:
225: 226: 227: 228: 229: 230:
231: public function shift() {
232: $items = $this->getItems();
233: if ($items->isEmpty()) {
234: return NULL;
235: }
236: if (count($items) === 1) {
237: $pop_item = $items[0];
238: $pop_item->remove();
239: return $pop_item;
240: }
241: $pop_item = $items[0];
242: $pop_item->nextUntil(function ($node) {
243: if ($node instanceof HiddenNode) {
244: return FALSE;
245: }
246: if ($node instanceof TokenNode && $node->getType() === ',') {
247: return FALSE;
248: }
249: return TRUE;
250: })->remove();
251: $pop_item->remove();
252: return $pop_item;
253: }
254:
255: 256: 257: 258: 259:
260: public function toArrayNode() {
261: return ($this->parent instanceof ArrayNode) ? clone $this->parent : Parser::parseExpression('[' . $this->getText() . ']');
262: }
263: }
264: