xref: /PHP-8.0/Zend/zend_ast.c (revision 9e3e8345)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Bob Weinand <bwoebi@php.net>                                |
16    |          Dmitry Stogov <dmitry@php.net>                              |
17    +----------------------------------------------------------------------+
18 */
19 
20 #include "zend_ast.h"
21 #include "zend_API.h"
22 #include "zend_operators.h"
23 #include "zend_language_parser.h"
24 #include "zend_smart_str.h"
25 #include "zend_exceptions.h"
26 #include "zend_constants.h"
27 
28 ZEND_API zend_ast_process_t zend_ast_process = NULL;
29 
zend_ast_alloc(size_t size)30 static inline void *zend_ast_alloc(size_t size) {
31 	return zend_arena_alloc(&CG(ast_arena), size);
32 }
33 
zend_ast_realloc(void * old,size_t old_size,size_t new_size)34 static inline void *zend_ast_realloc(void *old, size_t old_size, size_t new_size) {
35 	void *new = zend_ast_alloc(new_size);
36 	memcpy(new, old, old_size);
37 	return new;
38 }
39 
zend_ast_size(uint32_t children)40 static inline size_t zend_ast_size(uint32_t children) {
41 	return sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children;
42 }
43 
zend_ast_list_size(uint32_t children)44 static inline size_t zend_ast_list_size(uint32_t children) {
45 	return sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * children;
46 }
47 
zend_ast_create_znode(znode * node)48 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(znode *node) {
49 	zend_ast_znode *ast;
50 
51 	ast = zend_ast_alloc(sizeof(zend_ast_znode));
52 	ast->kind = ZEND_AST_ZNODE;
53 	ast->attr = 0;
54 	ast->lineno = CG(zend_lineno);
55 	ast->node = *node;
56 	return (zend_ast *) ast;
57 }
58 
zend_ast_create_zval_int(zval * zv,uint32_t attr,uint32_t lineno)59 static zend_always_inline zend_ast * zend_ast_create_zval_int(zval *zv, uint32_t attr, uint32_t lineno) {
60 	zend_ast_zval *ast;
61 
62 	ast = zend_ast_alloc(sizeof(zend_ast_zval));
63 	ast->kind = ZEND_AST_ZVAL;
64 	ast->attr = attr;
65 	ZVAL_COPY_VALUE(&ast->val, zv);
66 	Z_LINENO(ast->val) = lineno;
67 	return (zend_ast *) ast;
68 }
69 
zend_ast_create_zval_with_lineno(zval * zv,uint32_t lineno)70 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_with_lineno(zval *zv, uint32_t lineno) {
71 	return zend_ast_create_zval_int(zv, 0, lineno);
72 }
73 
zend_ast_create_zval_ex(zval * zv,zend_ast_attr attr)74 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr) {
75 	return zend_ast_create_zval_int(zv, attr, CG(zend_lineno));
76 }
77 
zend_ast_create_zval(zval * zv)78 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval(zval *zv) {
79 	return zend_ast_create_zval_int(zv, 0, CG(zend_lineno));
80 }
81 
zend_ast_create_zval_from_str(zend_string * str)82 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_from_str(zend_string *str) {
83 	zval zv;
84 	ZVAL_STR(&zv, str);
85 	return zend_ast_create_zval_int(&zv, 0, CG(zend_lineno));
86 }
87 
zend_ast_create_zval_from_long(zend_long lval)88 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_from_long(zend_long lval) {
89 	zval zv;
90 	ZVAL_LONG(&zv, lval);
91 	return zend_ast_create_zval_int(&zv, 0, CG(zend_lineno));
92 }
93 
zend_ast_create_constant(zend_string * name,zend_ast_attr attr)94 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_constant(zend_string *name, zend_ast_attr attr) {
95 	zend_ast_zval *ast;
96 
97 	ast = zend_ast_alloc(sizeof(zend_ast_zval));
98 	ast->kind = ZEND_AST_CONSTANT;
99 	ast->attr = attr;
100 	ZVAL_STR(&ast->val, name);
101 	Z_LINENO(ast->val) = CG(zend_lineno);
102 	return (zend_ast *) ast;
103 }
104 
zend_ast_create_class_const_or_name(zend_ast * class_name,zend_ast * name)105 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast *class_name, zend_ast *name) {
106 	zend_string *name_str = zend_ast_get_str(name);
107 	if (zend_string_equals_literal_ci(name_str, "class")) {
108 		zend_string_release(name_str);
109 		return zend_ast_create(ZEND_AST_CLASS_NAME, class_name);
110 	} else {
111 		return zend_ast_create(ZEND_AST_CLASS_CONST, class_name, name);
112 	}
113 }
114 
zend_ast_create_decl(zend_ast_kind kind,uint32_t flags,uint32_t start_lineno,zend_string * doc_comment,zend_string * name,zend_ast * child0,zend_ast * child1,zend_ast * child2,zend_ast * child3,zend_ast * child4)115 ZEND_API zend_ast *zend_ast_create_decl(
116 	zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
117 	zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4
118 ) {
119 	zend_ast_decl *ast;
120 
121 	ast = zend_ast_alloc(sizeof(zend_ast_decl));
122 	ast->kind = kind;
123 	ast->attr = 0;
124 	ast->start_lineno = start_lineno;
125 	ast->end_lineno = CG(zend_lineno);
126 	ast->flags = flags;
127 	ast->lex_pos = LANG_SCNG(yy_text);
128 	ast->doc_comment = doc_comment;
129 	ast->name = name;
130 	ast->child[0] = child0;
131 	ast->child[1] = child1;
132 	ast->child[2] = child2;
133 	ast->child[3] = child3;
134 	ast->child[4] = child4;
135 
136 	return (zend_ast *) ast;
137 }
138 
139 #if ZEND_AST_SPEC
zend_ast_create_0(zend_ast_kind kind)140 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_0(zend_ast_kind kind) {
141 	zend_ast *ast;
142 
143 	ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 0);
144 	ast = zend_ast_alloc(zend_ast_size(0));
145 	ast->kind = kind;
146 	ast->attr = 0;
147 	ast->lineno = CG(zend_lineno);
148 
149 	return ast;
150 }
151 
zend_ast_create_1(zend_ast_kind kind,zend_ast * child)152 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_1(zend_ast_kind kind, zend_ast *child) {
153 	zend_ast *ast;
154 	uint32_t lineno;
155 
156 	ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 1);
157 	ast = zend_ast_alloc(zend_ast_size(1));
158 	ast->kind = kind;
159 	ast->attr = 0;
160 	ast->child[0] = child;
161 	if (child) {
162 		lineno = zend_ast_get_lineno(child);
163 	} else {
164 		lineno = CG(zend_lineno);
165 	}
166 	ast->lineno = lineno;
167 
168 	return ast;
169 }
170 
zend_ast_create_2(zend_ast_kind kind,zend_ast * child1,zend_ast * child2)171 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2) {
172 	zend_ast *ast;
173 	uint32_t lineno;
174 
175 	ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 2);
176 	ast = zend_ast_alloc(zend_ast_size(2));
177 	ast->kind = kind;
178 	ast->attr = 0;
179 	ast->child[0] = child1;
180 	ast->child[1] = child2;
181 	if (child1) {
182 		lineno = zend_ast_get_lineno(child1);
183 	} else if (child2) {
184 		lineno = zend_ast_get_lineno(child2);
185 	} else {
186 		lineno = CG(zend_lineno);
187 	}
188 	ast->lineno = lineno;
189 
190 	return ast;
191 }
192 
zend_ast_create_3(zend_ast_kind kind,zend_ast * child1,zend_ast * child2,zend_ast * child3)193 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_3(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3) {
194 	zend_ast *ast;
195 	uint32_t lineno;
196 
197 	ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 3);
198 	ast = zend_ast_alloc(zend_ast_size(3));
199 	ast->kind = kind;
200 	ast->attr = 0;
201 	ast->child[0] = child1;
202 	ast->child[1] = child2;
203 	ast->child[2] = child3;
204 	if (child1) {
205 		lineno = zend_ast_get_lineno(child1);
206 	} else if (child2) {
207 		lineno = zend_ast_get_lineno(child2);
208 	} else if (child3) {
209 		lineno = zend_ast_get_lineno(child3);
210 	} else {
211 		lineno = CG(zend_lineno);
212 	}
213 	ast->lineno = lineno;
214 
215 	return ast;
216 }
217 
zend_ast_create_4(zend_ast_kind kind,zend_ast * child1,zend_ast * child2,zend_ast * child3,zend_ast * child4)218 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_4(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4) {
219 	zend_ast *ast;
220 	uint32_t lineno;
221 
222 	ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 4);
223 	ast = zend_ast_alloc(zend_ast_size(4));
224 	ast->kind = kind;
225 	ast->attr = 0;
226 	ast->child[0] = child1;
227 	ast->child[1] = child2;
228 	ast->child[2] = child3;
229 	ast->child[3] = child4;
230 	if (child1) {
231 		lineno = zend_ast_get_lineno(child1);
232 	} else if (child2) {
233 		lineno = zend_ast_get_lineno(child2);
234 	} else if (child3) {
235 		lineno = zend_ast_get_lineno(child3);
236 	} else if (child4) {
237 		lineno = zend_ast_get_lineno(child4);
238 	} else {
239 		lineno = CG(zend_lineno);
240 	}
241 	ast->lineno = lineno;
242 
243 	return ast;
244 }
245 
zend_ast_create_5(zend_ast_kind kind,zend_ast * child1,zend_ast * child2,zend_ast * child3,zend_ast * child4,zend_ast * child5)246 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_5(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4, zend_ast *child5) {
247 	zend_ast *ast;
248 	uint32_t lineno;
249 
250 	ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 5);
251 	ast = zend_ast_alloc(zend_ast_size(5));
252 	ast->kind = kind;
253 	ast->attr = 0;
254 	ast->child[0] = child1;
255 	ast->child[1] = child2;
256 	ast->child[2] = child3;
257 	ast->child[3] = child4;
258 	ast->child[4] = child5;
259 	if (child1) {
260 		lineno = zend_ast_get_lineno(child1);
261 	} else if (child2) {
262 		lineno = zend_ast_get_lineno(child2);
263 	} else if (child3) {
264 		lineno = zend_ast_get_lineno(child3);
265 	} else if (child4) {
266 		lineno = zend_ast_get_lineno(child4);
267 	} else if (child5) {
268 		lineno = zend_ast_get_lineno(child5);
269 	} else {
270 		lineno = CG(zend_lineno);
271 	}
272 	ast->lineno = lineno;
273 
274 	return ast;
275 }
276 
zend_ast_create_list_0(zend_ast_kind kind)277 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_0(zend_ast_kind kind) {
278 	zend_ast *ast;
279 	zend_ast_list *list;
280 
281 	ast = zend_ast_alloc(zend_ast_list_size(4));
282 	list = (zend_ast_list *) ast;
283 	list->kind = kind;
284 	list->attr = 0;
285 	list->lineno = CG(zend_lineno);
286 	list->children = 0;
287 
288 	return ast;
289 }
290 
zend_ast_create_list_1(zend_ast_kind kind,zend_ast * child)291 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_1(zend_ast_kind kind, zend_ast *child) {
292 	zend_ast *ast;
293 	zend_ast_list *list;
294 	uint32_t lineno;
295 
296 	ast = zend_ast_alloc(zend_ast_list_size(4));
297 	list = (zend_ast_list *) ast;
298 	list->kind = kind;
299 	list->attr = 0;
300 	list->children = 1;
301 	list->child[0] = child;
302 	if (child) {
303 		lineno = zend_ast_get_lineno(child);
304 		if (lineno > CG(zend_lineno)) {
305 			lineno = CG(zend_lineno);
306 		}
307 	} else {
308 		lineno = CG(zend_lineno);
309 	}
310 	list->lineno = lineno;
311 
312 	return ast;
313 }
314 
zend_ast_create_list_2(zend_ast_kind kind,zend_ast * child1,zend_ast * child2)315 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2) {
316 	zend_ast *ast;
317 	zend_ast_list *list;
318 	uint32_t lineno;
319 
320 	ast = zend_ast_alloc(zend_ast_list_size(4));
321 	list = (zend_ast_list *) ast;
322 	list->kind = kind;
323 	list->attr = 0;
324 	list->children = 2;
325 	list->child[0] = child1;
326 	list->child[1] = child2;
327 	if (child1) {
328 		lineno = zend_ast_get_lineno(child1);
329 		if (lineno > CG(zend_lineno)) {
330 			lineno = CG(zend_lineno);
331 		}
332 	} else if (child2) {
333 		lineno = zend_ast_get_lineno(child2);
334 		if (lineno > CG(zend_lineno)) {
335 			lineno = CG(zend_lineno);
336 		}
337 	} else {
338 		list->children = 0;
339 		lineno = CG(zend_lineno);
340 	}
341 	list->lineno = lineno;
342 
343 	return ast;
344 }
345 #else
zend_ast_create_from_va_list(zend_ast_kind kind,zend_ast_attr attr,va_list va)346 static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) {
347 	uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT;
348 	zend_ast *ast;
349 
350 	ast = zend_ast_alloc(zend_ast_size(children));
351 	ast->kind = kind;
352 	ast->attr = attr;
353 	ast->lineno = (uint32_t) -1;
354 
355 	for (i = 0; i < children; ++i) {
356 		ast->child[i] = va_arg(va, zend_ast *);
357 		if (ast->child[i] != NULL) {
358 			uint32_t lineno = zend_ast_get_lineno(ast->child[i]);
359 			if (lineno < ast->lineno) {
360 				ast->lineno = lineno;
361 			}
362 		}
363 	}
364 
365 	if (ast->lineno == UINT_MAX) {
366 		ast->lineno = CG(zend_lineno);
367 	}
368 
369 	return ast;
370 }
371 
zend_ast_create_ex(zend_ast_kind kind,zend_ast_attr attr,...)372 ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, ...) {
373 	va_list va;
374 	zend_ast *ast;
375 
376 	va_start(va, attr);
377 	ast = zend_ast_create_from_va_list(kind, attr, va);
378 	va_end(va);
379 
380 	return ast;
381 }
382 
zend_ast_create(zend_ast_kind kind,...)383 ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...) {
384 	va_list va;
385 	zend_ast *ast;
386 
387 	va_start(va, kind);
388 	ast = zend_ast_create_from_va_list(kind, 0, va);
389 	va_end(va);
390 
391 	return ast;
392 }
393 
zend_ast_create_list(uint32_t init_children,zend_ast_kind kind,...)394 ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind kind, ...) {
395 	zend_ast *ast;
396 	zend_ast_list *list;
397 
398 	ast = zend_ast_alloc(zend_ast_list_size(4));
399 	list = (zend_ast_list *) ast;
400 	list->kind = kind;
401 	list->attr = 0;
402 	list->lineno = CG(zend_lineno);
403 	list->children = 0;
404 
405 	{
406 		va_list va;
407 		uint32_t i;
408 		va_start(va, kind);
409 		for (i = 0; i < init_children; ++i) {
410 			zend_ast *child = va_arg(va, zend_ast *);
411 			ast = zend_ast_list_add(ast, child);
412 			if (child != NULL) {
413 				uint32_t lineno = zend_ast_get_lineno(child);
414 				if (lineno < ast->lineno) {
415 					ast->lineno = lineno;
416 				}
417 			}
418 		}
419 		va_end(va);
420 	}
421 
422 	return ast;
423 }
424 #endif
425 
is_power_of_two(uint32_t n)426 static inline zend_bool is_power_of_two(uint32_t n) {
427 	return ((n != 0) && (n == (n & (~n + 1))));
428 }
429 
zend_ast_list_add(zend_ast * ast,zend_ast * op)430 ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *ast, zend_ast *op) {
431 	zend_ast_list *list = zend_ast_get_list(ast);
432 	if (list->children >= 4 && is_power_of_two(list->children)) {
433 			list = zend_ast_realloc(list,
434 			zend_ast_list_size(list->children), zend_ast_list_size(list->children * 2));
435 	}
436 	list->child[list->children++] = op;
437 	return (zend_ast *) list;
438 }
439 
zend_ast_add_array_element(zval * result,zval * offset,zval * expr)440 static zend_result zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
441 {
442 	switch (Z_TYPE_P(offset)) {
443 		case IS_UNDEF:
444 			if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), expr)) {
445 				zend_throw_error(NULL,
446 					"Cannot add element to the array as the next element is already occupied");
447 				return FAILURE;
448 			}
449 			break;
450 		case IS_STRING:
451 			zend_symtable_update(Z_ARRVAL_P(result), Z_STR_P(offset), expr);
452 			zval_ptr_dtor_str(offset);
453 			break;
454 		case IS_NULL:
455 			zend_symtable_update(Z_ARRVAL_P(result), ZSTR_EMPTY_ALLOC(), expr);
456 			break;
457 		case IS_LONG:
458 			zend_hash_index_update(Z_ARRVAL_P(result), Z_LVAL_P(offset), expr);
459 			break;
460 		case IS_FALSE:
461 			zend_hash_index_update(Z_ARRVAL_P(result), 0, expr);
462 			break;
463 		case IS_TRUE:
464 			zend_hash_index_update(Z_ARRVAL_P(result), 1, expr);
465 			break;
466 		case IS_DOUBLE:
467 			zend_hash_index_update(Z_ARRVAL_P(result), zend_dval_to_lval(Z_DVAL_P(offset)), expr);
468 			break;
469 		case IS_RESOURCE:
470 			zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
471 			zend_hash_index_update(Z_ARRVAL_P(result), Z_RES_HANDLE_P(offset), expr);
472 			break;
473 		default:
474 			zend_type_error("Illegal offset type");
475 			return FAILURE;
476  	}
477 	return SUCCESS;
478 }
479 
zend_ast_add_unpacked_element(zval * result,zval * expr)480 static zend_result zend_ast_add_unpacked_element(zval *result, zval *expr) {
481 	if (EXPECTED(Z_TYPE_P(expr) == IS_ARRAY)) {
482 		HashTable *ht = Z_ARRVAL_P(expr);
483 		zval *val;
484 		zend_string *key;
485 
486 		ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
487 			if (key) {
488 				zend_throw_error(NULL, "Cannot unpack array with string keys");
489 				return FAILURE;
490 			} else {
491 				if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), val)) {
492 					zend_throw_error(NULL,
493 						"Cannot add element to the array as the next element is already occupied");
494 					return FAILURE;
495 				}
496 				Z_TRY_ADDREF_P(val);
497 			}
498 		} ZEND_HASH_FOREACH_END();
499 		return SUCCESS;
500 	}
501 
502 	/* Objects or references cannot occur in a constant expression. */
503 	zend_throw_error(NULL, "Only arrays and Traversables can be unpacked");
504 	return FAILURE;
505 }
506 
zend_ast_evaluate(zval * result,zend_ast * ast,zend_class_entry * scope)507 ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
508 {
509 	zval op1, op2;
510 	zend_result ret = SUCCESS;
511 
512 	switch (ast->kind) {
513 		case ZEND_AST_BINARY_OP:
514 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
515 				ret = FAILURE;
516 			} else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
517 				zval_ptr_dtor_nogc(&op1);
518 				ret = FAILURE;
519 			} else {
520 				binary_op_type op = get_binary_op(ast->attr);
521 				ret = op(result, &op1, &op2);
522 				zval_ptr_dtor_nogc(&op1);
523 				zval_ptr_dtor_nogc(&op2);
524 			}
525 			break;
526 		case ZEND_AST_GREATER:
527 		case ZEND_AST_GREATER_EQUAL:
528 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
529 				ret = FAILURE;
530 			} else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
531 				zval_ptr_dtor_nogc(&op1);
532 				ret = FAILURE;
533 			} else {
534 				/* op1 > op2 is the same as op2 < op1 */
535 				binary_op_type op = ast->kind == ZEND_AST_GREATER
536 					? is_smaller_function : is_smaller_or_equal_function;
537 				ret = op(result, &op2, &op1);
538 				zval_ptr_dtor_nogc(&op1);
539 				zval_ptr_dtor_nogc(&op2);
540 			}
541 			break;
542 		case ZEND_AST_UNARY_OP:
543 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
544 				ret = FAILURE;
545 			} else {
546 				unary_op_type op = get_unary_op(ast->attr);
547 				ret = op(result, &op1);
548 				zval_ptr_dtor_nogc(&op1);
549 			}
550 			break;
551 		case ZEND_AST_ZVAL:
552 		{
553 			zval *zv = zend_ast_get_zval(ast);
554 
555 			ZVAL_COPY(result, zv);
556 			break;
557 		}
558 		case ZEND_AST_CONSTANT:
559 		{
560 			zend_string *name = zend_ast_get_constant_name(ast);
561 			zval *zv = zend_get_constant_ex(name, scope, ast->attr);
562 
563 			if (UNEXPECTED(zv == NULL)) {
564 				ZVAL_UNDEF(result);
565 				return FAILURE;
566 			}
567 			ZVAL_COPY_OR_DUP(result, zv);
568 			break;
569 		}
570 		case ZEND_AST_CONSTANT_CLASS:
571 			if (scope) {
572 				ZVAL_STR_COPY(result, scope->name);
573 			} else {
574 				ZVAL_EMPTY_STRING(result);
575 			}
576 			break;
577 		case ZEND_AST_CLASS_NAME:
578 			if (!scope) {
579 				zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active");
580 				return FAILURE;
581 			}
582 			if (ast->attr == ZEND_FETCH_CLASS_SELF) {
583 				ZVAL_STR_COPY(result, scope->name);
584 			} else if (ast->attr == ZEND_FETCH_CLASS_PARENT) {
585 				if (!scope->parent) {
586 					zend_throw_error(NULL,
587 						"Cannot use \"parent\" when current class scope has no parent");
588 					return FAILURE;
589 				}
590 				ZVAL_STR_COPY(result, scope->parent->name);
591 			} else {
592 				ZEND_ASSERT(0 && "Should have errored during compilation");
593 			}
594 			break;
595 		case ZEND_AST_AND:
596 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
597 				ret = FAILURE;
598 				break;
599 			}
600 			if (zend_is_true(&op1)) {
601 				if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
602 					zval_ptr_dtor_nogc(&op1);
603 					ret = FAILURE;
604 					break;
605 				}
606 				ZVAL_BOOL(result, zend_is_true(&op2));
607 				zval_ptr_dtor_nogc(&op2);
608 			} else {
609 				ZVAL_FALSE(result);
610 			}
611 			zval_ptr_dtor_nogc(&op1);
612 			break;
613 		case ZEND_AST_OR:
614 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
615 				ret = FAILURE;
616 				break;
617 			}
618 			if (zend_is_true(&op1)) {
619 				ZVAL_TRUE(result);
620 			} else {
621 				if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
622 					zval_ptr_dtor_nogc(&op1);
623 					ret = FAILURE;
624 					break;
625 				}
626 				ZVAL_BOOL(result, zend_is_true(&op2));
627 				zval_ptr_dtor_nogc(&op2);
628 			}
629 			zval_ptr_dtor_nogc(&op1);
630 			break;
631 		case ZEND_AST_CONDITIONAL:
632 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
633 				ret = FAILURE;
634 				break;
635 			}
636 			if (zend_is_true(&op1)) {
637 				if (!ast->child[1]) {
638 					*result = op1;
639 				} else {
640 					if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) {
641 						zval_ptr_dtor_nogc(&op1);
642 						ret = FAILURE;
643 						break;
644 					}
645 					zval_ptr_dtor_nogc(&op1);
646 				}
647 			} else {
648 				if (UNEXPECTED(zend_ast_evaluate(result, ast->child[2], scope) != SUCCESS)) {
649 					zval_ptr_dtor_nogc(&op1);
650 					ret = FAILURE;
651 					break;
652 				}
653 				zval_ptr_dtor_nogc(&op1);
654 			}
655 			break;
656 		case ZEND_AST_COALESCE:
657 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
658 				ret = FAILURE;
659 				break;
660 			}
661 			if (Z_TYPE(op1) > IS_NULL) {
662 				*result = op1;
663 			} else {
664 				if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) {
665 					zval_ptr_dtor_nogc(&op1);
666 					ret = FAILURE;
667 					break;
668 				}
669 				zval_ptr_dtor_nogc(&op1);
670 			}
671 			break;
672 		case ZEND_AST_UNARY_PLUS:
673 			if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) {
674 				ret = FAILURE;
675 			} else {
676 				ZVAL_LONG(&op1, 0);
677 				ret = add_function(result, &op1, &op2);
678 				zval_ptr_dtor_nogc(&op2);
679 			}
680 			break;
681 		case ZEND_AST_UNARY_MINUS:
682 			if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) {
683 				ret = FAILURE;
684 			} else {
685 				ZVAL_LONG(&op1, 0);
686 				ret = sub_function(result, &op1, &op2);
687 				zval_ptr_dtor_nogc(&op2);
688 			}
689 			break;
690 		case ZEND_AST_ARRAY:
691 			{
692 				uint32_t i;
693 				zend_ast_list *list = zend_ast_get_list(ast);
694 
695 				if (!list->children) {
696 					ZVAL_EMPTY_ARRAY(result);
697 					break;
698 				}
699 				array_init(result);
700 				for (i = 0; i < list->children; i++) {
701 					zend_ast *elem = list->child[i];
702 					if (elem->kind == ZEND_AST_UNPACK) {
703 						if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[0], scope) != SUCCESS)) {
704 							zval_ptr_dtor_nogc(result);
705 							return FAILURE;
706 						}
707 						if (UNEXPECTED(zend_ast_add_unpacked_element(result, &op1) != SUCCESS)) {
708 							zval_ptr_dtor_nogc(&op1);
709 							zval_ptr_dtor_nogc(result);
710 							return FAILURE;
711 						}
712 						zval_ptr_dtor_nogc(&op1);
713 						continue;
714 					}
715 					if (elem->child[1]) {
716 						if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[1], scope) != SUCCESS)) {
717 							zval_ptr_dtor_nogc(result);
718 							return FAILURE;
719 						}
720 					} else {
721 						ZVAL_UNDEF(&op1);
722 					}
723 					if (UNEXPECTED(zend_ast_evaluate(&op2, elem->child[0], scope) != SUCCESS)) {
724 						zval_ptr_dtor_nogc(&op1);
725 						zval_ptr_dtor_nogc(result);
726 						return FAILURE;
727 					}
728 					if (UNEXPECTED(zend_ast_add_array_element(result, &op1, &op2) != SUCCESS)) {
729 						zval_ptr_dtor_nogc(&op1);
730 						zval_ptr_dtor_nogc(&op2);
731 						zval_ptr_dtor_nogc(result);
732 						return FAILURE;
733 					}
734 				}
735 			}
736 			break;
737 		case ZEND_AST_DIM:
738 			if (ast->child[1] == NULL) {
739 				zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
740 			}
741 
742 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
743 				ret = FAILURE;
744 			} else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
745 				zval_ptr_dtor_nogc(&op1);
746 				ret = FAILURE;
747 			} else {
748 				zend_fetch_dimension_const(result, &op1, &op2, (ast->attr & ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
749 
750 				zval_ptr_dtor_nogc(&op1);
751 				zval_ptr_dtor_nogc(&op2);
752 				if (UNEXPECTED(EG(exception))) {
753 					return FAILURE;
754 				}
755 			}
756 			break;
757 		default:
758 			zend_throw_error(NULL, "Unsupported constant expression");
759 			ret = FAILURE;
760 	}
761 	return ret;
762 }
763 
zend_ast_tree_size(zend_ast * ast)764 static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
765 {
766 	size_t size;
767 
768 	if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
769 		size = sizeof(zend_ast_zval);
770 	} else if (zend_ast_is_list(ast)) {
771 		uint32_t i;
772 		zend_ast_list *list = zend_ast_get_list(ast);
773 
774 		size = zend_ast_list_size(list->children);
775 		for (i = 0; i < list->children; i++) {
776 			if (list->child[i]) {
777 				size += zend_ast_tree_size(list->child[i]);
778 			}
779 		}
780 	} else {
781 		uint32_t i, children = zend_ast_get_num_children(ast);
782 
783 		size = zend_ast_size(children);
784 		for (i = 0; i < children; i++) {
785 			if (ast->child[i]) {
786 				size += zend_ast_tree_size(ast->child[i]);
787 			}
788 		}
789 	}
790 	return size;
791 }
792 
zend_ast_tree_copy(zend_ast * ast,void * buf)793 static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
794 {
795 	if (ast->kind == ZEND_AST_ZVAL) {
796 		zend_ast_zval *new = (zend_ast_zval*)buf;
797 		new->kind = ZEND_AST_ZVAL;
798 		new->attr = ast->attr;
799 		ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
800 		buf = (void*)((char*)buf + sizeof(zend_ast_zval));
801 	} else if (ast->kind == ZEND_AST_CONSTANT) {
802 		zend_ast_zval *new = (zend_ast_zval*)buf;
803 		new->kind = ZEND_AST_CONSTANT;
804 		new->attr = ast->attr;
805 		ZVAL_STR_COPY(&new->val, zend_ast_get_constant_name(ast));
806 		buf = (void*)((char*)buf + sizeof(zend_ast_zval));
807 	} else if (zend_ast_is_list(ast)) {
808 		zend_ast_list *list = zend_ast_get_list(ast);
809 		zend_ast_list *new = (zend_ast_list*)buf;
810 		uint32_t i;
811 		new->kind = list->kind;
812 		new->attr = list->attr;
813 		new->children = list->children;
814 		buf = (void*)((char*)buf + zend_ast_list_size(list->children));
815 		for (i = 0; i < list->children; i++) {
816 			if (list->child[i]) {
817 				new->child[i] = (zend_ast*)buf;
818 				buf = zend_ast_tree_copy(list->child[i], buf);
819 			} else {
820 				new->child[i] = NULL;
821 			}
822 		}
823 	} else {
824 		uint32_t i, children = zend_ast_get_num_children(ast);
825 		zend_ast *new = (zend_ast*)buf;
826 		new->kind = ast->kind;
827 		new->attr = ast->attr;
828 		buf = (void*)((char*)buf + zend_ast_size(children));
829 		for (i = 0; i < children; i++) {
830 			if (ast->child[i]) {
831 				new->child[i] = (zend_ast*)buf;
832 				buf = zend_ast_tree_copy(ast->child[i], buf);
833 			} else {
834 				new->child[i] = NULL;
835 			}
836 		}
837 	}
838 	return buf;
839 }
840 
zend_ast_copy(zend_ast * ast)841 ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast)
842 {
843 	size_t tree_size;
844 	zend_ast_ref *ref;
845 
846 	ZEND_ASSERT(ast != NULL);
847 	tree_size = zend_ast_tree_size(ast) + sizeof(zend_ast_ref);
848 	ref = emalloc(tree_size);
849 	zend_ast_tree_copy(ast, GC_AST(ref));
850 	GC_SET_REFCOUNT(ref, 1);
851 	GC_TYPE_INFO(ref) = GC_CONSTANT_AST;
852 	return ref;
853 }
854 
zend_ast_destroy(zend_ast * ast)855 ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
856 {
857 tail_call:
858 	if (!ast) {
859 		return;
860 	}
861 
862 	if (EXPECTED(ast->kind >= ZEND_AST_VAR)) {
863 		uint32_t i, children = zend_ast_get_num_children(ast);
864 
865 		for (i = 1; i < children; i++) {
866 			zend_ast_destroy(ast->child[i]);
867 		}
868 		ast = ast->child[0];
869 		goto tail_call;
870 	} else if (EXPECTED(ast->kind == ZEND_AST_ZVAL)) {
871 		zval_ptr_dtor_nogc(zend_ast_get_zval(ast));
872 	} else if (EXPECTED(zend_ast_is_list(ast))) {
873 		zend_ast_list *list = zend_ast_get_list(ast);
874 		if (list->children) {
875 			uint32_t i;
876 
877 			for (i = 1; i < list->children; i++) {
878 				zend_ast_destroy(list->child[i]);
879 			}
880 			ast = list->child[0];
881 			goto tail_call;
882 		}
883 	} else if (EXPECTED(ast->kind == ZEND_AST_CONSTANT)) {
884 		zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
885 	} else if (EXPECTED(ast->kind >= ZEND_AST_FUNC_DECL)) {
886 		zend_ast_decl *decl = (zend_ast_decl *) ast;
887 
888 		if (decl->name) {
889 		    zend_string_release_ex(decl->name, 0);
890 		}
891 		if (decl->doc_comment) {
892 			zend_string_release_ex(decl->doc_comment, 0);
893 		}
894 		zend_ast_destroy(decl->child[0]);
895 		zend_ast_destroy(decl->child[1]);
896 		zend_ast_destroy(decl->child[2]);
897 		zend_ast_destroy(decl->child[3]);
898 		ast = decl->child[4];
899 		goto tail_call;
900 	}
901 }
902 
zend_ast_ref_destroy(zend_ast_ref * ast)903 ZEND_API void ZEND_FASTCALL zend_ast_ref_destroy(zend_ast_ref *ast)
904 {
905 	zend_ast_destroy(GC_AST(ast));
906 	efree(ast);
907 }
908 
zend_ast_apply(zend_ast * ast,zend_ast_apply_func fn)909 ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn) {
910 	if (zend_ast_is_list(ast)) {
911 		zend_ast_list *list = zend_ast_get_list(ast);
912 		uint32_t i;
913 		for (i = 0; i < list->children; ++i) {
914 			fn(&list->child[i]);
915 		}
916 	} else {
917 		uint32_t i, children = zend_ast_get_num_children(ast);
918 		for (i = 0; i < children; ++i) {
919 			fn(&ast->child[i]);
920 		}
921 	}
922 }
923 
924 /*
925  * Operator Precedence
926  * ====================
927  * priority  associativity  operators
928  * ----------------------------------
929  *   10     left            include, include_once, eval, require, require_once
930  *   20     left            ,
931  *   30     left            or
932  *   40     left            xor
933  *   50     left            and
934  *   60     right           print
935  *   70     right           yield
936  *   80     right           =>
937  *   85     right           yield from
938  *   90     right           = += -= *= /= .= %= &= |= ^= <<= >>= **=
939  *  100     left            ? :
940  *  110     right           ??
941  *  120     left            ||
942  *  130     left            &&
943  *  140     left            |
944  *  150     left            ^
945  *  160     left            &
946  *  170     non-associative == != === !==
947  *  180     non-associative < <= > >= <=>
948  *  185     left            .
949  *  190     left            << >>
950  *  200     left            + -
951  *  210     left            * / %
952  *  220     right           !
953  *  230     non-associative instanceof
954  *  240     right           + - ++ -- ~ (type) @
955  *  250     right           **
956  *  260     left            [
957  *  270     non-associative clone new
958  */
959 
960 static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent);
961 
zend_ast_export_str(smart_str * str,zend_string * s)962 static ZEND_COLD void zend_ast_export_str(smart_str *str, zend_string *s)
963 {
964 	size_t i;
965 
966 	for (i = 0; i < ZSTR_LEN(s); i++) {
967 		unsigned char c = ZSTR_VAL(s)[i];
968 		if (c == '\'' || c == '\\') {
969 			smart_str_appendc(str, '\\');
970 			smart_str_appendc(str, c);
971 		} else {
972 			smart_str_appendc(str, c);
973 		}
974 	}
975 }
976 
zend_ast_export_qstr(smart_str * str,char quote,zend_string * s)977 static ZEND_COLD void zend_ast_export_qstr(smart_str *str, char quote, zend_string *s)
978 {
979 	size_t i;
980 
981 	for (i = 0; i < ZSTR_LEN(s); i++) {
982 		unsigned char c = ZSTR_VAL(s)[i];
983 		if (c < ' ') {
984 			switch (c) {
985 				case '\n':
986 					smart_str_appends(str, "\\n");
987 					break;
988 				case '\r':
989 					smart_str_appends(str, "\\r");
990 					break;
991 				case '\t':
992 					smart_str_appends(str, "\\t");
993 					break;
994 				case '\f':
995 					smart_str_appends(str, "\\f");
996 					break;
997 				case '\v':
998 					smart_str_appends(str, "\\v");
999 					break;
1000 #ifdef ZEND_WIN32
1001 				case VK_ESCAPE:
1002 #else
1003 				case '\e':
1004 #endif
1005 					smart_str_appends(str, "\\e");
1006 					break;
1007 				default:
1008 					smart_str_appends(str, "\\0");
1009 					smart_str_appendc(str, '0' + (c / 8));
1010 					smart_str_appendc(str, '0' + (c % 8));
1011 					break;
1012 			}
1013 		} else {
1014 			if (c == quote || c == '$' || c == '\\') {
1015 				smart_str_appendc(str, '\\');
1016 			}
1017 			smart_str_appendc(str, c);
1018 		}
1019 	}
1020 }
1021 
zend_ast_export_indent(smart_str * str,int indent)1022 static ZEND_COLD void zend_ast_export_indent(smart_str *str, int indent)
1023 {
1024 	while (indent > 0) {
1025 		smart_str_appends(str, "    ");
1026 		indent--;
1027 	}
1028 }
1029 
zend_ast_export_name(smart_str * str,zend_ast * ast,int priority,int indent)1030 static ZEND_COLD void zend_ast_export_name(smart_str *str, zend_ast *ast, int priority, int indent)
1031 {
1032 	if (ast->kind == ZEND_AST_ZVAL) {
1033 		zval *zv = zend_ast_get_zval(ast);
1034 
1035 		if (Z_TYPE_P(zv) == IS_STRING) {
1036 			smart_str_append(str, Z_STR_P(zv));
1037 			return;
1038 		}
1039 	}
1040 	zend_ast_export_ex(str, ast, priority, indent);
1041 }
1042 
zend_ast_export_ns_name(smart_str * str,zend_ast * ast,int priority,int indent)1043 static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int priority, int indent)
1044 {
1045 	if (ast->kind == ZEND_AST_ZVAL) {
1046 		zval *zv = zend_ast_get_zval(ast);
1047 
1048 		if (Z_TYPE_P(zv) == IS_STRING) {
1049 		    if (ast->attr == ZEND_NAME_FQ) {
1050 				smart_str_appendc(str, '\\');
1051 		    } else if (ast->attr == ZEND_NAME_RELATIVE) {
1052 				smart_str_appends(str, "namespace\\");
1053 		    }
1054 			smart_str_append(str, Z_STR_P(zv));
1055 			return;
1056 		}
1057 	}
1058 	zend_ast_export_ex(str, ast, priority, indent);
1059 }
1060 
zend_ast_valid_var_char(char ch)1061 static ZEND_COLD bool zend_ast_valid_var_char(char ch)
1062 {
1063 	unsigned char c = (unsigned char)ch;
1064 
1065 	if (c != '_' && c < 127 &&
1066 	    (c < '0' || c > '9') &&
1067 	    (c < 'A' || c > 'Z') &&
1068 	    (c < 'a' || c > 'z')) {
1069 		return 0;
1070 	}
1071 	return 1;
1072 }
1073 
zend_ast_valid_var_name(const char * s,size_t len)1074 static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len)
1075 {
1076 	unsigned char c;
1077 	size_t i;
1078 
1079 	if (len == 0) {
1080 		return 0;
1081 	}
1082 	c = (unsigned char)s[0];
1083 	if (c != '_' && c < 127 &&
1084 	    (c < 'A' || c > 'Z') &&
1085 	    (c < 'a' || c > 'z')) {
1086 		return 0;
1087 	}
1088 	for (i = 1; i < len; i++) {
1089 		c = (unsigned char)s[i];
1090 		if (c != '_' && c < 127 &&
1091 		    (c < '0' || c > '9') &&
1092 		    (c < 'A' || c > 'Z') &&
1093 		    (c < 'a' || c > 'z')) {
1094 			return 0;
1095 		}
1096 	}
1097 	return 1;
1098 }
1099 
zend_ast_var_needs_braces(char ch)1100 static ZEND_COLD bool zend_ast_var_needs_braces(char ch)
1101 {
1102 	return ch == '[' || zend_ast_valid_var_char(ch);
1103 }
1104 
zend_ast_export_var(smart_str * str,zend_ast * ast,int priority,int indent)1105 static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int priority, int indent)
1106 {
1107 	if (ast->kind == ZEND_AST_ZVAL) {
1108 		zval *zv = zend_ast_get_zval(ast);
1109 		if (Z_TYPE_P(zv) == IS_STRING &&
1110 		    zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) {
1111 			smart_str_append(str, Z_STR_P(zv));
1112 			return;
1113 		}
1114 	} else if (ast->kind == ZEND_AST_VAR) {
1115 		zend_ast_export_ex(str, ast, 0, indent);
1116 		return;
1117 	}
1118 	smart_str_appendc(str, '{');
1119 	zend_ast_export_name(str, ast, 0, indent);
1120 	smart_str_appendc(str, '}');
1121 }
1122 
zend_ast_export_list(smart_str * str,zend_ast_list * list,bool separator,int priority,int indent)1123 static ZEND_COLD void zend_ast_export_list(smart_str *str, zend_ast_list *list, bool separator, int priority, int indent)
1124 {
1125 	uint32_t i = 0;
1126 
1127 	while (i < list->children) {
1128 		if (i != 0 && separator) {
1129 			smart_str_appends(str, ", ");
1130 		}
1131 		zend_ast_export_ex(str, list->child[i], priority, indent);
1132 		i++;
1133 	}
1134 }
1135 
zend_ast_export_encaps_list(smart_str * str,char quote,zend_ast_list * list,int indent)1136 static ZEND_COLD void zend_ast_export_encaps_list(smart_str *str, char quote, zend_ast_list *list, int indent)
1137 {
1138 	uint32_t i = 0;
1139 	zend_ast *ast;
1140 
1141 	while (i < list->children) {
1142 		ast = list->child[i];
1143 		if (ast->kind == ZEND_AST_ZVAL) {
1144 			zval *zv = zend_ast_get_zval(ast);
1145 
1146 			ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
1147 			zend_ast_export_qstr(str, quote, Z_STR_P(zv));
1148 		} else if (ast->kind == ZEND_AST_VAR &&
1149 		           ast->child[0]->kind == ZEND_AST_ZVAL &&
1150 		           (i + 1 == list->children ||
1151 		            list->child[i + 1]->kind != ZEND_AST_ZVAL ||
1152 		            !zend_ast_var_needs_braces(
1153 		                *Z_STRVAL_P(
1154 		                    zend_ast_get_zval(list->child[i + 1]))))) {
1155 			zend_ast_export_ex(str, ast, 0, indent);
1156 		} else {
1157 			smart_str_appendc(str, '{');
1158 			zend_ast_export_ex(str, ast, 0, indent);
1159 			smart_str_appendc(str, '}');
1160 		}
1161 		i++;
1162 	}
1163 }
1164 
zend_ast_export_name_list_ex(smart_str * str,zend_ast_list * list,int indent,const char * separator)1165 static ZEND_COLD void zend_ast_export_name_list_ex(smart_str *str, zend_ast_list *list, int indent, const char *separator)
1166 {
1167 	uint32_t i = 0;
1168 
1169 	while (i < list->children) {
1170 		if (i != 0) {
1171 			smart_str_appends(str, separator);
1172 		}
1173 		zend_ast_export_name(str, list->child[i], 0, indent);
1174 		i++;
1175 	}
1176 }
1177 
1178 #define zend_ast_export_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, ", ")
1179 #define zend_ast_export_catch_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, "|")
1180 
zend_ast_export_var_list(smart_str * str,zend_ast_list * list,int indent)1181 static ZEND_COLD void zend_ast_export_var_list(smart_str *str, zend_ast_list *list, int indent)
1182 {
1183 	uint32_t i = 0;
1184 
1185 	while (i < list->children) {
1186 		if (i != 0) {
1187 			smart_str_appends(str, ", ");
1188 		}
1189 		if (list->child[i]->attr & ZEND_BIND_REF) {
1190 			smart_str_appendc(str, '&');
1191 		}
1192 		smart_str_appendc(str, '$');
1193 		zend_ast_export_name(str, list->child[i], 20, indent);
1194 		i++;
1195 	}
1196 }
1197 
zend_ast_export_stmt(smart_str * str,zend_ast * ast,int indent)1198 static ZEND_COLD void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int indent)
1199 {
1200 	if (!ast) {
1201 		return;
1202 	}
1203 
1204 	if (ast->kind == ZEND_AST_STMT_LIST ||
1205 	    ast->kind == ZEND_AST_TRAIT_ADAPTATIONS) {
1206 		zend_ast_list *list = (zend_ast_list*)ast;
1207 		uint32_t i = 0;
1208 
1209 		while (i < list->children) {
1210 			ast = list->child[i];
1211 			zend_ast_export_stmt(str, ast, indent);
1212 			i++;
1213 		}
1214 	} else {
1215 		zend_ast_export_indent(str, indent);
1216 		zend_ast_export_ex(str, ast, 0, indent);
1217 		switch (ast->kind) {
1218 			case ZEND_AST_LABEL:
1219 			case ZEND_AST_IF:
1220 			case ZEND_AST_SWITCH:
1221 			case ZEND_AST_WHILE:
1222 			case ZEND_AST_TRY:
1223 			case ZEND_AST_FOR:
1224 			case ZEND_AST_FOREACH:
1225 			case ZEND_AST_FUNC_DECL:
1226 			case ZEND_AST_METHOD:
1227 			case ZEND_AST_CLASS:
1228 			case ZEND_AST_USE_TRAIT:
1229 			case ZEND_AST_NAMESPACE:
1230 			case ZEND_AST_DECLARE:
1231 				break;
1232 			default:
1233 				smart_str_appendc(str, ';');
1234 				break;
1235 		}
1236 		smart_str_appendc(str, '\n');
1237 	}
1238 }
1239 
zend_ast_export_if_stmt(smart_str * str,zend_ast_list * list,int indent)1240 static ZEND_COLD void zend_ast_export_if_stmt(smart_str *str, zend_ast_list *list, int indent)
1241 {
1242 	uint32_t i;
1243 	zend_ast *ast;
1244 
1245 tail_call:
1246 	i = 0;
1247 	while (i < list->children) {
1248 		ast = list->child[i];
1249 		ZEND_ASSERT(ast->kind == ZEND_AST_IF_ELEM);
1250 		if (ast->child[0]) {
1251 			if (i == 0) {
1252 				smart_str_appends(str, "if (");
1253 			} else {
1254 				zend_ast_export_indent(str, indent);
1255 				smart_str_appends(str, "} elseif (");
1256 			}
1257 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1258 			smart_str_appends(str, ") {\n");
1259 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1260 		} else {
1261 			zend_ast_export_indent(str, indent);
1262 			smart_str_appends(str, "} else ");
1263 			if (ast->child[1] && ast->child[1]->kind == ZEND_AST_IF) {
1264 				list = (zend_ast_list*)ast->child[1];
1265 				goto tail_call;
1266 			} else {
1267 				smart_str_appends(str, "{\n");
1268 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1269 			}
1270 		}
1271 		i++;
1272 	}
1273 	zend_ast_export_indent(str, indent);
1274 	smart_str_appendc(str, '}');
1275 }
1276 
zend_ast_export_zval(smart_str * str,zval * zv,int priority,int indent)1277 static ZEND_COLD void zend_ast_export_zval(smart_str *str, zval *zv, int priority, int indent)
1278 {
1279 	zend_long idx;
1280 	zend_string *key;
1281 	zval *val;
1282 	int first;
1283 
1284 	ZVAL_DEREF(zv);
1285 	switch (Z_TYPE_P(zv)) {
1286 		case IS_NULL:
1287 			smart_str_appends(str, "null");
1288 			break;
1289 		case IS_FALSE:
1290 			smart_str_appends(str, "false");
1291 			break;
1292 		case IS_TRUE:
1293 			smart_str_appends(str, "true");
1294 			break;
1295 		case IS_LONG:
1296 			smart_str_append_long(str, Z_LVAL_P(zv));
1297 			break;
1298 		case IS_DOUBLE:
1299 			key = zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(zv));
1300 			smart_str_appendl(str, ZSTR_VAL(key), ZSTR_LEN(key));
1301 			zend_string_release_ex(key, 0);
1302 			break;
1303 		case IS_STRING:
1304 			smart_str_appendc(str, '\'');
1305 			zend_ast_export_str(str, Z_STR_P(zv));
1306 			smart_str_appendc(str, '\'');
1307 			break;
1308 		case IS_ARRAY:
1309 			smart_str_appendc(str, '[');
1310 			first = 1;
1311 			ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zv), idx, key, val) {
1312 				if (first) {
1313 					first = 0;
1314 				} else {
1315 					smart_str_appends(str, ", ");
1316 				}
1317 				if (key) {
1318 					smart_str_appendc(str, '\'');
1319 					zend_ast_export_str(str, key);
1320 					smart_str_appends(str, "' => ");
1321 				} else {
1322 					smart_str_append_long(str, idx);
1323 					smart_str_appends(str, " => ");
1324 				}
1325 				zend_ast_export_zval(str, val, 0, indent);
1326 			} ZEND_HASH_FOREACH_END();
1327 			smart_str_appendc(str, ']');
1328 			break;
1329 		case IS_CONSTANT_AST:
1330 			zend_ast_export_ex(str, Z_ASTVAL_P(zv), priority, indent);
1331 			break;
1332 		EMPTY_SWITCH_DEFAULT_CASE();
1333 	}
1334 }
1335 
zend_ast_export_class_no_header(smart_str * str,zend_ast_decl * decl,int indent)1336 static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_decl *decl, int indent) {
1337 	if (decl->child[0]) {
1338 		smart_str_appends(str, " extends ");
1339 		zend_ast_export_ns_name(str, decl->child[0], 0, indent);
1340 	}
1341 	if (decl->child[1]) {
1342 		smart_str_appends(str, " implements ");
1343 		zend_ast_export_ex(str, decl->child[1], 0, indent);
1344 	}
1345 	smart_str_appends(str, " {\n");
1346 	zend_ast_export_stmt(str, decl->child[2], indent + 1);
1347 	zend_ast_export_indent(str, indent);
1348 	smart_str_appends(str, "}");
1349 }
1350 
zend_ast_export_attribute_group(smart_str * str,zend_ast * ast,int indent)1351 static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) {
1352 	zend_ast_list *list = zend_ast_get_list(ast);
1353 	uint32_t i, j;
1354 
1355 	for (i = 0; i < list->children; i++) {
1356 		zend_ast *attr = list->child[i];
1357 
1358 		if (i) {
1359 			smart_str_appends(str, ", ");
1360 		}
1361 		zend_ast_export_ns_name(str, attr->child[0], 0, indent);
1362 
1363 		if (attr->child[1]) {
1364 			zend_ast_list *args = zend_ast_get_list(attr->child[1]);
1365 
1366 			smart_str_appendc(str, '(');
1367 			for (j = 0; j < args->children; j++) {
1368 				if (j) {
1369 					smart_str_appends(str, ", ");
1370 				}
1371 				zend_ast_export_ex(str, args->child[j], 0, indent);
1372 			}
1373 			smart_str_appendc(str, ')');
1374 		}
1375 	}
1376 }
1377 
zend_ast_export_attributes(smart_str * str,zend_ast * ast,int indent,zend_bool newlines)1378 static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
1379 	zend_ast_list *list = zend_ast_get_list(ast);
1380 	uint32_t i;
1381 
1382 	for (i = 0; i < list->children; i++) {
1383 		smart_str_appends(str, "#[");
1384 		zend_ast_export_attribute_group(str, list->child[i], indent);
1385 		smart_str_appends(str, "]");
1386 
1387 		if (newlines) {
1388 			smart_str_appendc(str, '\n');
1389 			zend_ast_export_indent(str, indent);
1390 		} else {
1391 			smart_str_appendc(str, ' ');
1392 		}
1393 	}
1394 }
1395 
zend_ast_export_visibility(smart_str * str,uint32_t flags)1396 static ZEND_COLD void zend_ast_export_visibility(smart_str *str, uint32_t flags) {
1397 	if (flags & ZEND_ACC_PUBLIC) {
1398 		smart_str_appends(str, "public ");
1399 	} else if (flags & ZEND_ACC_PROTECTED) {
1400 		smart_str_appends(str, "protected ");
1401 	} else if (flags & ZEND_ACC_PRIVATE) {
1402 		smart_str_appends(str, "private ");
1403 	}
1404 }
1405 
zend_ast_export_type(smart_str * str,zend_ast * ast,int indent)1406 static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int indent) {
1407 	if (ast->kind == ZEND_AST_TYPE_UNION) {
1408 		zend_ast_list *list = zend_ast_get_list(ast);
1409 		for (uint32_t i = 0; i < list->children; i++) {
1410 			if (i != 0) {
1411 				smart_str_appendc(str, '|');
1412 			}
1413 			zend_ast_export_type(str, list->child[i], indent);
1414 		}
1415 		return;
1416 	}
1417 	if (ast->attr & ZEND_TYPE_NULLABLE) {
1418 		smart_str_appendc(str, '?');
1419 	}
1420 	zend_ast_export_ns_name(str, ast, 0, indent);
1421 }
1422 
1423 #define BINARY_OP(_op, _p, _pl, _pr) do { \
1424 		op = _op; \
1425 		p = _p; \
1426 		pl = _pl; \
1427 		pr = _pr; \
1428 		goto binary_op; \
1429 	} while (0)
1430 
1431 #define PREFIX_OP(_op, _p, _pl) do { \
1432 		op = _op; \
1433 		p = _p; \
1434 		pl = _pl; \
1435 		goto prefix_op; \
1436 	} while (0)
1437 
1438 #define FUNC_OP(_op) do { \
1439 		op = _op; \
1440 		goto func_op; \
1441 	} while (0)
1442 
1443 #define POSTFIX_OP(_op, _p, _pl) do { \
1444 		op = _op; \
1445 		p = _p; \
1446 		pl = _pl; \
1447 		goto postfix_op; \
1448 	} while (0)
1449 
1450 #define APPEND_NODE_1(_op) do { \
1451 		op = _op; \
1452 		goto append_node_1; \
1453 	} while (0)
1454 
1455 #define APPEND_STR(_op) do { \
1456 		op = _op; \
1457 		goto append_str; \
1458 	} while (0)
1459 
1460 #define APPEND_DEFAULT_VALUE(n) do { \
1461 		p = n; \
1462 		goto append_default_value; \
1463 	} while (0)
1464 
zend_ast_export_ex(smart_str * str,zend_ast * ast,int priority,int indent)1465 static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent)
1466 {
1467 	zend_ast_decl *decl;
1468 	int p, pl, pr;
1469 	const char *op;
1470 
1471 tail_call:
1472 	if (!ast) {
1473 		return;
1474 	}
1475 	switch (ast->kind) {
1476 		/* special nodes */
1477 		case ZEND_AST_ZVAL:
1478 			zend_ast_export_zval(str, zend_ast_get_zval(ast), priority, indent);
1479 			break;
1480 		case ZEND_AST_CONSTANT: {
1481 			zend_string *name = zend_ast_get_constant_name(ast);
1482 			smart_str_appendl(str, ZSTR_VAL(name), ZSTR_LEN(name));
1483 			break;
1484 		}
1485 		case ZEND_AST_CONSTANT_CLASS:
1486 			smart_str_appendl(str, "__CLASS__", sizeof("__CLASS__")-1);
1487 			break;
1488 		case ZEND_AST_ZNODE:
1489 			/* This AST kind is only used for temporary nodes during compilation */
1490 			ZEND_UNREACHABLE();
1491 			break;
1492 
1493 		/* declaration nodes */
1494 		case ZEND_AST_FUNC_DECL:
1495 		case ZEND_AST_CLOSURE:
1496 		case ZEND_AST_ARROW_FUNC:
1497 		case ZEND_AST_METHOD:
1498 			decl = (zend_ast_decl *) ast;
1499 			if (decl->child[4]) {
1500 				zend_bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC);
1501 				zend_ast_export_attributes(str, decl->child[4], indent, newlines);
1502 			}
1503 
1504 			zend_ast_export_visibility(str, decl->flags);
1505 
1506 			if (decl->flags & ZEND_ACC_STATIC) {
1507 				smart_str_appends(str, "static ");
1508 			}
1509 			if (decl->flags & ZEND_ACC_ABSTRACT) {
1510 				smart_str_appends(str, "abstract ");
1511 			}
1512 			if (decl->flags & ZEND_ACC_FINAL) {
1513 				smart_str_appends(str, "final ");
1514 			}
1515 			if (decl->kind == ZEND_AST_ARROW_FUNC) {
1516 				smart_str_appends(str, "fn");
1517 			} else {
1518 				smart_str_appends(str, "function ");
1519 			}
1520 			if (decl->flags & ZEND_ACC_RETURN_REFERENCE) {
1521 				smart_str_appendc(str, '&');
1522 			}
1523 			if (ast->kind != ZEND_AST_CLOSURE && ast->kind != ZEND_AST_ARROW_FUNC) {
1524 				smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
1525 			}
1526 			smart_str_appendc(str, '(');
1527 			zend_ast_export_ex(str, decl->child[0], 0, indent);
1528 			smart_str_appendc(str, ')');
1529 			zend_ast_export_ex(str, decl->child[1], 0, indent);
1530 			if (decl->child[3]) {
1531 				smart_str_appends(str, ": ");
1532 				zend_ast_export_type(str, decl->child[3], indent);
1533 			}
1534 			if (decl->child[2]) {
1535 				if (decl->kind == ZEND_AST_ARROW_FUNC) {
1536 					ZEND_ASSERT(decl->child[2]->kind == ZEND_AST_RETURN);
1537 					smart_str_appends(str, " => ");
1538 					zend_ast_export_ex(str, decl->child[2]->child[0], 0, indent);
1539 					break;
1540 				}
1541 
1542 				smart_str_appends(str, " {\n");
1543 				zend_ast_export_stmt(str, decl->child[2], indent + 1);
1544 				zend_ast_export_indent(str, indent);
1545 				smart_str_appendc(str, '}');
1546 				if (ast->kind != ZEND_AST_CLOSURE) {
1547 					smart_str_appendc(str, '\n');
1548 				}
1549 			} else {
1550 				smart_str_appends(str, ";\n");
1551 			}
1552 			break;
1553 		case ZEND_AST_CLASS:
1554 			decl = (zend_ast_decl *) ast;
1555 			if (decl->child[3]) {
1556 				zend_ast_export_attributes(str, decl->child[3], indent, 1);
1557 			}
1558 			if (decl->flags & ZEND_ACC_INTERFACE) {
1559 				smart_str_appends(str, "interface ");
1560 			} else if (decl->flags & ZEND_ACC_TRAIT) {
1561 				smart_str_appends(str, "trait ");
1562 			} else {
1563 				if (decl->flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
1564 					smart_str_appends(str, "abstract ");
1565 				}
1566 				if (decl->flags & ZEND_ACC_FINAL) {
1567 					smart_str_appends(str, "final ");
1568 				}
1569 				smart_str_appends(str, "class ");
1570 			}
1571 			smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
1572 			zend_ast_export_class_no_header(str, decl, indent);
1573 			smart_str_appendc(str, '\n');
1574 			break;
1575 
1576 		/* list nodes */
1577 		case ZEND_AST_ARG_LIST:
1578 		case ZEND_AST_EXPR_LIST:
1579 		case ZEND_AST_PARAM_LIST:
1580 simple_list:
1581 			zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1582 			break;
1583 		case ZEND_AST_ARRAY:
1584 			smart_str_appendc(str, '[');
1585 			zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1586 			smart_str_appendc(str, ']');
1587 			break;
1588 		case ZEND_AST_ENCAPS_LIST:
1589 			smart_str_appendc(str, '"');
1590 			zend_ast_export_encaps_list(str, '"', (zend_ast_list*)ast, indent);
1591 			smart_str_appendc(str, '"');
1592 			break;
1593 		case ZEND_AST_STMT_LIST:
1594 		case ZEND_AST_TRAIT_ADAPTATIONS:
1595 			zend_ast_export_stmt(str, ast, indent);
1596 			break;
1597 		case ZEND_AST_IF:
1598 			zend_ast_export_if_stmt(str, (zend_ast_list*)ast, indent);
1599 			break;
1600 		case ZEND_AST_SWITCH_LIST:
1601 		case ZEND_AST_CATCH_LIST:
1602 		case ZEND_AST_MATCH_ARM_LIST:
1603 			zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
1604 			break;
1605 		case ZEND_AST_CLOSURE_USES:
1606 			smart_str_appends(str, " use(");
1607 			zend_ast_export_var_list(str, (zend_ast_list*)ast, indent);
1608 			smart_str_appendc(str, ')');
1609 			break;
1610 		case ZEND_AST_PROP_GROUP: {
1611 			zend_ast *type_ast = ast->child[0];
1612 			zend_ast *prop_ast = ast->child[1];
1613 
1614 			if (ast->child[2]) {
1615 				zend_ast_export_attributes(str, ast->child[2], indent, 1);
1616 			}
1617 
1618 			zend_ast_export_visibility(str, ast->attr);
1619 
1620 			if (ast->attr & ZEND_ACC_STATIC) {
1621 				smart_str_appends(str, "static ");
1622 			}
1623 
1624 			if (type_ast) {
1625 				zend_ast_export_type(str, type_ast, indent);
1626 				smart_str_appendc(str, ' ');
1627 			}
1628 
1629 			ast = prop_ast;
1630 			goto simple_list;
1631 		}
1632 
1633 		case ZEND_AST_CONST_DECL:
1634 			smart_str_appends(str, "const ");
1635 			goto simple_list;
1636 		case ZEND_AST_CLASS_CONST_GROUP:
1637 			if (ast->child[1]) {
1638 				zend_ast_export_attributes(str, ast->child[1], indent, 1);
1639 			}
1640 
1641 			zend_ast_export_visibility(str, ast->attr);
1642 			smart_str_appends(str, "const ");
1643 
1644 			ast = ast->child[0];
1645 
1646 			goto simple_list;
1647 		case ZEND_AST_NAME_LIST:
1648 			zend_ast_export_name_list(str, (zend_ast_list*)ast, indent);
1649 			break;
1650 		case ZEND_AST_USE:
1651 			smart_str_appends(str, "use ");
1652 			if (ast->attr == T_FUNCTION) {
1653 				smart_str_appends(str, "function ");
1654 			} else if (ast->attr == T_CONST) {
1655 				smart_str_appends(str, "const ");
1656 			}
1657 			goto simple_list;
1658 
1659 		/* 0 child nodes */
1660 		case ZEND_AST_MAGIC_CONST:
1661 			switch (ast->attr) {
1662 				case T_LINE:     APPEND_STR("__LINE__");
1663 				case T_FILE:     APPEND_STR("__FILE__");
1664 				case T_DIR:      APPEND_STR("__DIR__");
1665 				case T_TRAIT_C:  APPEND_STR("__TRAIT__");
1666 				case T_METHOD_C: APPEND_STR("__METHOD__");
1667 				case T_FUNC_C:   APPEND_STR("__FUNCTION__");
1668 				case T_NS_C:     APPEND_STR("__NAMESPACE__");
1669 				case T_CLASS_C:  APPEND_STR("__CLASS__");
1670 				EMPTY_SWITCH_DEFAULT_CASE();
1671 			}
1672 			break;
1673 		case ZEND_AST_TYPE:
1674 			switch (ast->attr & ~ZEND_TYPE_NULLABLE) {
1675 				case IS_ARRAY:    APPEND_STR("array");
1676 				case IS_CALLABLE: APPEND_STR("callable");
1677 				case IS_STATIC:   APPEND_STR("static");
1678 				case IS_MIXED:    APPEND_STR("mixed");
1679 				EMPTY_SWITCH_DEFAULT_CASE();
1680 			}
1681 			break;
1682 
1683 		/* 1 child node */
1684 		case ZEND_AST_VAR:
1685 			smart_str_appendc(str, '$');
1686 			zend_ast_export_var(str, ast->child[0], 0, indent);
1687 			break;
1688 		case ZEND_AST_CONST:
1689 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1690 			break;
1691 		case ZEND_AST_UNPACK:
1692 			smart_str_appends(str, "...");
1693 			ast = ast->child[0];
1694 			goto tail_call;
1695 		case ZEND_AST_UNARY_PLUS:  PREFIX_OP("+", 240, 241);
1696 		case ZEND_AST_UNARY_MINUS: PREFIX_OP("-", 240, 241);
1697 		case ZEND_AST_CAST:
1698 			switch (ast->attr) {
1699 				case IS_NULL:      PREFIX_OP("(unset)",  240, 241);
1700 				case _IS_BOOL:     PREFIX_OP("(bool)",   240, 241);
1701 				case IS_LONG:      PREFIX_OP("(int)",    240, 241);
1702 				case IS_DOUBLE:    PREFIX_OP("(double)", 240, 241);
1703 				case IS_STRING:    PREFIX_OP("(string)", 240, 241);
1704 				case IS_ARRAY:     PREFIX_OP("(array)",  240, 241);
1705 				case IS_OBJECT:    PREFIX_OP("(object)", 240, 241);
1706 				EMPTY_SWITCH_DEFAULT_CASE();
1707 			}
1708 			break;
1709 		case ZEND_AST_EMPTY:
1710 			FUNC_OP("empty");
1711 		case ZEND_AST_ISSET:
1712 			FUNC_OP("isset");
1713 		case ZEND_AST_SILENCE:
1714 			PREFIX_OP("@", 240, 241);
1715 		case ZEND_AST_SHELL_EXEC:
1716 			smart_str_appendc(str, '`');
1717 			if (ast->child[0]->kind == ZEND_AST_ENCAPS_LIST) {
1718 				zend_ast_export_encaps_list(str, '`', (zend_ast_list*)ast->child[0], indent);
1719 			} else {
1720 				zval *zv;
1721 				ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_ZVAL);
1722 				zv = zend_ast_get_zval(ast->child[0]);
1723 				ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
1724 				zend_ast_export_qstr(str, '`', Z_STR_P(zv));
1725 			}
1726 			smart_str_appendc(str, '`');
1727 			break;
1728 		case ZEND_AST_CLONE:
1729 			PREFIX_OP("clone ", 270, 271);
1730 		case ZEND_AST_EXIT:
1731 			if (ast->child[0]) {
1732 				FUNC_OP("exit");
1733 			} else {
1734 				APPEND_STR("exit");
1735 			}
1736 			break;
1737 		case ZEND_AST_PRINT:
1738 			PREFIX_OP("print ", 60, 61);
1739 		case ZEND_AST_INCLUDE_OR_EVAL:
1740 			switch (ast->attr) {
1741 				case ZEND_INCLUDE_ONCE: FUNC_OP("include_once");
1742 				case ZEND_INCLUDE:      FUNC_OP("include");
1743 				case ZEND_REQUIRE_ONCE: FUNC_OP("require_once");
1744 				case ZEND_REQUIRE:      FUNC_OP("require");
1745 				case ZEND_EVAL:         FUNC_OP("eval");
1746 				EMPTY_SWITCH_DEFAULT_CASE();
1747 			}
1748 			break;
1749 		case ZEND_AST_UNARY_OP:
1750 			switch (ast->attr) {
1751 				case ZEND_BW_NOT:   PREFIX_OP("~", 240, 241);
1752 				case ZEND_BOOL_NOT: PREFIX_OP("!", 240, 241);
1753 				EMPTY_SWITCH_DEFAULT_CASE();
1754 			}
1755 			break;
1756 		case ZEND_AST_PRE_INC:
1757 			PREFIX_OP("++", 240, 241);
1758 		case ZEND_AST_PRE_DEC:
1759 			PREFIX_OP("--", 240, 241);
1760 		case ZEND_AST_POST_INC:
1761 			POSTFIX_OP("++", 240, 241);
1762 		case ZEND_AST_POST_DEC:
1763 			POSTFIX_OP("--", 240, 241);
1764 
1765 		case ZEND_AST_GLOBAL:
1766 			APPEND_NODE_1("global");
1767 		case ZEND_AST_UNSET:
1768 			FUNC_OP("unset");
1769 		case ZEND_AST_RETURN:
1770 			APPEND_NODE_1("return");
1771 		case ZEND_AST_LABEL:
1772 			zend_ast_export_name(str, ast->child[0], 0, indent);
1773 			smart_str_appendc(str, ':');
1774 			break;
1775 		case ZEND_AST_REF:
1776 			smart_str_appendc(str, '&');
1777 			ast = ast->child[0];
1778 			goto tail_call;
1779 		case ZEND_AST_HALT_COMPILER:
1780 			APPEND_STR("__HALT_COMPILER()");
1781 		case ZEND_AST_ECHO:
1782 			APPEND_NODE_1("echo");
1783 		case ZEND_AST_THROW:
1784 			APPEND_NODE_1("throw");
1785 		case ZEND_AST_GOTO:
1786 			smart_str_appends(str, "goto ");
1787 			zend_ast_export_name(str, ast->child[0], 0, indent);
1788 			break;
1789 		case ZEND_AST_BREAK:
1790 			APPEND_NODE_1("break");
1791 		case ZEND_AST_CONTINUE:
1792 			APPEND_NODE_1("continue");
1793 
1794 		/* 2 child nodes */
1795 		case ZEND_AST_DIM:
1796 			zend_ast_export_ex(str, ast->child[0], 260, indent);
1797 			smart_str_appendc(str, '[');
1798 			if (ast->child[1]) {
1799 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1800 			}
1801 			smart_str_appendc(str, ']');
1802 			break;
1803 		case ZEND_AST_PROP:
1804 		case ZEND_AST_NULLSAFE_PROP:
1805 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1806 			smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_PROP ? "?->" : "->");
1807 			zend_ast_export_var(str, ast->child[1], 0, indent);
1808 			break;
1809 		case ZEND_AST_STATIC_PROP:
1810 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1811 			smart_str_appends(str, "::$");
1812 			zend_ast_export_var(str, ast->child[1], 0, indent);
1813 			break;
1814 		case ZEND_AST_CALL:
1815 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1816 			smart_str_appendc(str, '(');
1817 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1818 			smart_str_appendc(str, ')');
1819 			break;
1820 		case ZEND_AST_CLASS_CONST:
1821 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1822 			smart_str_appends(str, "::");
1823 			zend_ast_export_name(str, ast->child[1], 0, indent);
1824 			break;
1825 		case ZEND_AST_CLASS_NAME:
1826 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1827 			smart_str_appends(str, "::class");
1828 			break;
1829 		case ZEND_AST_ASSIGN:            BINARY_OP(" = ",   90, 91, 90);
1830 		case ZEND_AST_ASSIGN_REF:        BINARY_OP(" =& ",  90, 91, 90);
1831 		case ZEND_AST_ASSIGN_OP:
1832 			switch (ast->attr) {
1833 				case ZEND_ADD:    BINARY_OP(" += ",  90, 91, 90);
1834 				case ZEND_SUB:    BINARY_OP(" -= ",  90, 91, 90);
1835 				case ZEND_MUL:    BINARY_OP(" *= ",  90, 91, 90);
1836 				case ZEND_DIV:    BINARY_OP(" /= ",  90, 91, 90);
1837 				case ZEND_MOD:    BINARY_OP(" %= ",  90, 91, 90);
1838 				case ZEND_SL:     BINARY_OP(" <<= ", 90, 91, 90);
1839 				case ZEND_SR:     BINARY_OP(" >>= ", 90, 91, 90);
1840 				case ZEND_CONCAT: BINARY_OP(" .= ",  90, 91, 90);
1841 				case ZEND_BW_OR:  BINARY_OP(" |= ",  90, 91, 90);
1842 				case ZEND_BW_AND: BINARY_OP(" &= ",  90, 91, 90);
1843 				case ZEND_BW_XOR: BINARY_OP(" ^= ",  90, 91, 90);
1844 				case ZEND_POW:    BINARY_OP(" **= ", 90, 91, 90);
1845 				EMPTY_SWITCH_DEFAULT_CASE();
1846 			}
1847 			break;
1848 		case ZEND_AST_ASSIGN_COALESCE: BINARY_OP(" \?\?= ", 90, 91, 90);
1849 		case ZEND_AST_BINARY_OP:
1850 			switch (ast->attr) {
1851 				case ZEND_ADD:                 BINARY_OP(" + ",   200, 200, 201);
1852 				case ZEND_SUB:                 BINARY_OP(" - ",   200, 200, 201);
1853 				case ZEND_MUL:                 BINARY_OP(" * ",   210, 210, 211);
1854 				case ZEND_DIV:                 BINARY_OP(" / ",   210, 210, 211);
1855 				case ZEND_MOD:                 BINARY_OP(" % ",   210, 210, 211);
1856 				case ZEND_SL:                  BINARY_OP(" << ",  190, 190, 191);
1857 				case ZEND_SR:                  BINARY_OP(" >> ",  190, 190, 191);
1858 				case ZEND_CONCAT:              BINARY_OP(" . ",   185, 185, 186);
1859 				case ZEND_BW_OR:               BINARY_OP(" | ",   140, 140, 141);
1860 				case ZEND_BW_AND:              BINARY_OP(" & ",   160, 160, 161);
1861 				case ZEND_BW_XOR:              BINARY_OP(" ^ ",   150, 150, 151);
1862 				case ZEND_IS_IDENTICAL:        BINARY_OP(" === ", 170, 171, 171);
1863 				case ZEND_IS_NOT_IDENTICAL:    BINARY_OP(" !== ", 170, 171, 171);
1864 				case ZEND_IS_EQUAL:            BINARY_OP(" == ",  170, 171, 171);
1865 				case ZEND_IS_NOT_EQUAL:        BINARY_OP(" != ",  170, 171, 171);
1866 				case ZEND_IS_SMALLER:          BINARY_OP(" < ",   180, 181, 181);
1867 				case ZEND_IS_SMALLER_OR_EQUAL: BINARY_OP(" <= ",  180, 181, 181);
1868 				case ZEND_POW:                 BINARY_OP(" ** ",  250, 251, 250);
1869 				case ZEND_BOOL_XOR:            BINARY_OP(" xor ",  40,  40,  41);
1870 				case ZEND_SPACESHIP:           BINARY_OP(" <=> ", 180, 181, 181);
1871 				EMPTY_SWITCH_DEFAULT_CASE();
1872 			}
1873 			break;
1874 		case ZEND_AST_GREATER:                 BINARY_OP(" > ",   180, 181, 181);
1875 		case ZEND_AST_GREATER_EQUAL:           BINARY_OP(" >= ",  180, 181, 181);
1876 		case ZEND_AST_AND:                     BINARY_OP(" && ",  130, 130, 131);
1877 		case ZEND_AST_OR:                      BINARY_OP(" || ",  120, 120, 121);
1878 		case ZEND_AST_ARRAY_ELEM:
1879 			if (ast->child[1]) {
1880 				zend_ast_export_ex(str, ast->child[1], 80, indent);
1881 				smart_str_appends(str, " => ");
1882 			}
1883 			if (ast->attr)
1884 				smart_str_appendc(str, '&');
1885 			zend_ast_export_ex(str, ast->child[0], 80, indent);
1886 			break;
1887 		case ZEND_AST_NEW:
1888 			smart_str_appends(str, "new ");
1889 			if (ast->child[0]->kind == ZEND_AST_CLASS) {
1890 				zend_ast_decl *decl = (zend_ast_decl *) ast->child[0];
1891 				if (decl->child[3]) {
1892 					zend_ast_export_attributes(str, decl->child[3], indent, 0);
1893 				}
1894 				smart_str_appends(str, "class");
1895 				if (zend_ast_get_list(ast->child[1])->children) {
1896 					smart_str_appendc(str, '(');
1897 					zend_ast_export_ex(str, ast->child[1], 0, indent);
1898 					smart_str_appendc(str, ')');
1899 				}
1900 				zend_ast_export_class_no_header(str, decl, indent);
1901 			} else {
1902 				zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1903 				smart_str_appendc(str, '(');
1904 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1905 				smart_str_appendc(str, ')');
1906 			}
1907 			break;
1908 		case ZEND_AST_INSTANCEOF:
1909 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1910 			smart_str_appends(str, " instanceof ");
1911 			zend_ast_export_ns_name(str, ast->child[1], 0, indent);
1912 			break;
1913 		case ZEND_AST_YIELD:
1914 			if (priority > 70) smart_str_appendc(str, '(');
1915 			smart_str_appends(str, "yield ");
1916 			if (ast->child[0]) {
1917 				if (ast->child[1]) {
1918 					zend_ast_export_ex(str, ast->child[1], 70, indent);
1919 					smart_str_appends(str, " => ");
1920 				}
1921 				zend_ast_export_ex(str, ast->child[0], 70, indent);
1922 			}
1923 			if (priority > 70) smart_str_appendc(str, ')');
1924 			break;
1925 		case ZEND_AST_YIELD_FROM:
1926 			PREFIX_OP("yield from ", 85, 86);
1927 		case ZEND_AST_COALESCE: BINARY_OP(" ?? ", 110, 111, 110);
1928 		case ZEND_AST_STATIC:
1929 			smart_str_appends(str, "static $");
1930 			zend_ast_export_name(str, ast->child[0], 0, indent);
1931 			APPEND_DEFAULT_VALUE(1);
1932 		case ZEND_AST_WHILE:
1933 			smart_str_appends(str, "while (");
1934 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1935 			smart_str_appends(str, ") {\n");
1936 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1937 			zend_ast_export_indent(str, indent);
1938 			smart_str_appendc(str, '}');
1939 			break;
1940 		case ZEND_AST_DO_WHILE:
1941 			smart_str_appends(str, "do {\n");
1942 			zend_ast_export_stmt(str, ast->child[0], indent + 1);
1943 			zend_ast_export_indent(str, indent);
1944 			smart_str_appends(str, "} while (");
1945 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1946 			smart_str_appendc(str, ')');
1947 			break;
1948 
1949 		case ZEND_AST_IF_ELEM:
1950 			if (ast->child[0]) {
1951 				smart_str_appends(str, "if (");
1952 				zend_ast_export_ex(str, ast->child[0], 0, indent);
1953 				smart_str_appends(str, ") {\n");
1954 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1955 			} else {
1956 				smart_str_appends(str, "else {\n");
1957 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1958 			}
1959 			zend_ast_export_indent(str, indent);
1960 			smart_str_appendc(str, '}');
1961 			break;
1962 		case ZEND_AST_SWITCH:
1963 			smart_str_appends(str, "switch (");
1964 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1965 			smart_str_appends(str, ") {\n");
1966 			zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
1967 			zend_ast_export_indent(str, indent);
1968 			smart_str_appendc(str, '}');
1969 			break;
1970 		case ZEND_AST_SWITCH_CASE:
1971 			zend_ast_export_indent(str, indent);
1972 			if (ast->child[0]) {
1973 				smart_str_appends(str, "case ");
1974 				zend_ast_export_ex(str, ast->child[0], 0, indent);
1975 				smart_str_appends(str, ":\n");
1976 			} else {
1977 				smart_str_appends(str, "default:\n");
1978 			}
1979 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1980 			break;
1981 		case ZEND_AST_MATCH:
1982 			smart_str_appends(str, "match (");
1983 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1984 			smart_str_appends(str, ") {\n");
1985 			zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
1986 			zend_ast_export_indent(str, indent);
1987 			smart_str_appendc(str, '}');
1988 			break;
1989 		case ZEND_AST_MATCH_ARM:
1990 			zend_ast_export_indent(str, indent);
1991 			if (ast->child[0]) {
1992 				zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
1993 				smart_str_appends(str, " => ");
1994 			} else {
1995 				smart_str_appends(str, "default => ");
1996 			}
1997 			zend_ast_export_ex(str, ast->child[1], 0, 0);
1998 			smart_str_appends(str, ",\n");
1999 			break;
2000 		case ZEND_AST_DECLARE:
2001 			smart_str_appends(str, "declare(");
2002 			ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_CONST_DECL);
2003 			zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
2004 			smart_str_appendc(str, ')');
2005 			if (ast->child[1]) {
2006 				smart_str_appends(str, " {\n");
2007 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
2008 				zend_ast_export_indent(str, indent);
2009 				smart_str_appendc(str, '}');
2010 			} else {
2011 				smart_str_appendc(str, ';');
2012 			}
2013 			break;
2014 		case ZEND_AST_PROP_ELEM:
2015 			smart_str_appendc(str, '$');
2016 			/* break missing intentionally */
2017 		case ZEND_AST_CONST_ELEM:
2018 			zend_ast_export_name(str, ast->child[0], 0, indent);
2019 			APPEND_DEFAULT_VALUE(1);
2020 		case ZEND_AST_USE_TRAIT:
2021 			smart_str_appends(str, "use ");
2022 			zend_ast_export_ex(str, ast->child[0], 0, indent);
2023 			if (ast->child[1]) {
2024 				smart_str_appends(str, " {\n");
2025 				zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
2026 				zend_ast_export_indent(str, indent);
2027 				smart_str_appends(str, "}");
2028 			} else {
2029 				smart_str_appends(str, ";");
2030 			}
2031 			break;
2032 		case ZEND_AST_TRAIT_PRECEDENCE:
2033 			zend_ast_export_ex(str, ast->child[0], 0, indent);
2034 			smart_str_appends(str, " insteadof ");
2035 			zend_ast_export_ex(str, ast->child[1], 0, indent);
2036 			break;
2037 		case ZEND_AST_METHOD_REFERENCE:
2038 			if (ast->child[0]) {
2039 				zend_ast_export_name(str, ast->child[0], 0, indent);
2040 				smart_str_appends(str, "::");
2041 			}
2042 			zend_ast_export_name(str, ast->child[1], 0, indent);
2043 			break;
2044 		case ZEND_AST_NAMESPACE:
2045 			smart_str_appends(str, "namespace");
2046 			if (ast->child[0]) {
2047 				smart_str_appendc(str, ' ');
2048 				zend_ast_export_name(str, ast->child[0], 0, indent);
2049 			}
2050 			if (ast->child[1]) {
2051 				smart_str_appends(str, " {\n");
2052 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
2053 				zend_ast_export_indent(str, indent);
2054 				smart_str_appends(str, "}\n");
2055 			} else {
2056 				smart_str_appendc(str, ';');
2057 			}
2058 			break;
2059 		case ZEND_AST_USE_ELEM:
2060 		case ZEND_AST_TRAIT_ALIAS:
2061 			zend_ast_export_name(str, ast->child[0], 0, indent);
2062 			if (ast->attr & ZEND_ACC_PUBLIC) {
2063 				smart_str_appends(str, " as public");
2064 			} else if (ast->attr & ZEND_ACC_PROTECTED) {
2065 				smart_str_appends(str, " as protected");
2066 			} else if (ast->attr & ZEND_ACC_PRIVATE) {
2067 				smart_str_appends(str, " as private");
2068 			} else if (ast->child[1]) {
2069 				smart_str_appends(str, " as");
2070 			}
2071 			if (ast->child[1]) {
2072 				smart_str_appendc(str, ' ');
2073 				zend_ast_export_name(str, ast->child[1], 0, indent);
2074 			}
2075 			break;
2076 		case ZEND_AST_NAMED_ARG:
2077 			smart_str_append(str, zend_ast_get_str(ast->child[0]));
2078 			smart_str_appends(str, ": ");
2079 			ast = ast->child[1];
2080 			goto tail_call;
2081 
2082 		/* 3 child nodes */
2083 		case ZEND_AST_METHOD_CALL:
2084 		case ZEND_AST_NULLSAFE_METHOD_CALL:
2085 			zend_ast_export_ex(str, ast->child[0], 0, indent);
2086 			smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL ? "?->" : "->");
2087 			zend_ast_export_var(str, ast->child[1], 0, indent);
2088 			smart_str_appendc(str, '(');
2089 			zend_ast_export_ex(str, ast->child[2], 0, indent);
2090 			smart_str_appendc(str, ')');
2091 			break;
2092 		case ZEND_AST_STATIC_CALL:
2093 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2094 			smart_str_appends(str, "::");
2095 			zend_ast_export_var(str, ast->child[1], 0, indent);
2096 			smart_str_appendc(str, '(');
2097 			zend_ast_export_ex(str, ast->child[2], 0, indent);
2098 			smart_str_appendc(str, ')');
2099 			break;
2100 		case ZEND_AST_CONDITIONAL:
2101 			if (priority > 100) smart_str_appendc(str, '(');
2102 			zend_ast_export_ex(str, ast->child[0], 100, indent);
2103 			if (ast->child[1]) {
2104 				smart_str_appends(str, " ? ");
2105 				zend_ast_export_ex(str, ast->child[1], 101, indent);
2106 				smart_str_appends(str, " : ");
2107 			} else {
2108 				smart_str_appends(str, " ?: ");
2109 			}
2110 			zend_ast_export_ex(str, ast->child[2], 101, indent);
2111 			if (priority > 100) smart_str_appendc(str, ')');
2112 			break;
2113 
2114 		case ZEND_AST_TRY:
2115 			smart_str_appends(str, "try {\n");
2116 			zend_ast_export_stmt(str, ast->child[0], indent + 1);
2117 			zend_ast_export_indent(str, indent);
2118 			zend_ast_export_ex(str, ast->child[1], 0, indent);
2119 			if (ast->child[2]) {
2120 				smart_str_appends(str, "} finally {\n");
2121 				zend_ast_export_stmt(str, ast->child[2], indent + 1);
2122 				zend_ast_export_indent(str, indent);
2123 			}
2124 			smart_str_appendc(str, '}');
2125 			break;
2126 		case ZEND_AST_CATCH:
2127 			smart_str_appends(str, "} catch (");
2128 			zend_ast_export_catch_name_list(str, zend_ast_get_list(ast->child[0]), indent);
2129 			if (ast->child[1]) {
2130 				smart_str_appends(str, " $");
2131 				zend_ast_export_var(str, ast->child[1], 0, indent);
2132 			}
2133 			smart_str_appends(str, ") {\n");
2134 			zend_ast_export_stmt(str, ast->child[2], indent + 1);
2135 			zend_ast_export_indent(str, indent);
2136 			break;
2137 		case ZEND_AST_PARAM:
2138 			if (ast->child[3]) {
2139 				zend_ast_export_attributes(str, ast->child[3], indent, 0);
2140 			}
2141 			if (ast->child[0]) {
2142 				zend_ast_export_type(str, ast->child[0], indent);
2143 				smart_str_appendc(str, ' ');
2144 			}
2145 			if (ast->attr & ZEND_PARAM_REF) {
2146 				smart_str_appendc(str, '&');
2147 			}
2148 			if (ast->attr & ZEND_PARAM_VARIADIC) {
2149 				smart_str_appends(str, "...");
2150 			}
2151 			smart_str_appendc(str, '$');
2152 			zend_ast_export_name(str, ast->child[1], 0, indent);
2153 			APPEND_DEFAULT_VALUE(2);
2154 
2155 		/* 4 child nodes */
2156 		case ZEND_AST_FOR:
2157 			smart_str_appends(str, "for (");
2158 			zend_ast_export_ex(str, ast->child[0], 0, indent);
2159 			smart_str_appendc(str, ';');
2160 			if (ast->child[1]) {
2161 				smart_str_appendc(str, ' ');
2162 				zend_ast_export_ex(str, ast->child[1], 0, indent);
2163 			}
2164 			smart_str_appendc(str, ';');
2165 			if (ast->child[2]) {
2166 				smart_str_appendc(str, ' ');
2167 				zend_ast_export_ex(str, ast->child[2], 0, indent);
2168 			}
2169 			smart_str_appends(str, ") {\n");
2170 			zend_ast_export_stmt(str, ast->child[3], indent + 1);
2171 			zend_ast_export_indent(str, indent);
2172 			smart_str_appendc(str, '}');
2173 			break;
2174 		case ZEND_AST_FOREACH:
2175 			smart_str_appends(str, "foreach (");
2176 			zend_ast_export_ex(str, ast->child[0], 0, indent);
2177 			smart_str_appends(str, " as ");
2178 			if (ast->child[2]) {
2179 				zend_ast_export_ex(str, ast->child[2], 0, indent);
2180 				smart_str_appends(str, " => ");
2181 			}
2182 			zend_ast_export_ex(str, ast->child[1], 0, indent);
2183 			smart_str_appends(str, ") {\n");
2184 			zend_ast_export_stmt(str, ast->child[3], indent + 1);
2185 			zend_ast_export_indent(str, indent);
2186 			smart_str_appendc(str, '}');
2187 			break;
2188 		EMPTY_SWITCH_DEFAULT_CASE();
2189 	}
2190 	return;
2191 
2192 binary_op:
2193 	if (priority > p) smart_str_appendc(str, '(');
2194 	zend_ast_export_ex(str, ast->child[0], pl, indent);
2195 	smart_str_appends(str, op);
2196 	zend_ast_export_ex(str, ast->child[1], pr, indent);
2197 	if (priority > p) smart_str_appendc(str, ')');
2198 	return;
2199 
2200 prefix_op:
2201 	if (priority > p) smart_str_appendc(str, '(');
2202 	smart_str_appends(str, op);
2203 	zend_ast_export_ex(str, ast->child[0], pl, indent);
2204 	if (priority > p) smart_str_appendc(str, ')');
2205 	return;
2206 
2207 postfix_op:
2208 	if (priority > p) smart_str_appendc(str, '(');
2209 	zend_ast_export_ex(str, ast->child[0], pl, indent);
2210 	smart_str_appends(str, op);
2211 	if (priority > p) smart_str_appendc(str, ')');
2212 	return;
2213 
2214 func_op:
2215 	smart_str_appends(str, op);
2216 	smart_str_appendc(str, '(');
2217 	zend_ast_export_ex(str, ast->child[0], 0, indent);
2218 	smart_str_appendc(str, ')');
2219 	return;
2220 
2221 append_node_1:
2222 	smart_str_appends(str, op);
2223 	if (ast->child[0]) {
2224 		smart_str_appendc(str, ' ');
2225 		ast = ast->child[0];
2226 		goto tail_call;
2227 	}
2228 	return;
2229 
2230 append_str:
2231 	smart_str_appends(str, op);
2232 	return;
2233 
2234 append_default_value:
2235 	if (ast->child[p]) {
2236 		smart_str_appends(str, " = ");
2237 		ast = ast->child[p];
2238 		goto tail_call;
2239 	}
2240 	return;
2241 }
2242 
zend_ast_export(const char * prefix,zend_ast * ast,const char * suffix)2243 ZEND_API ZEND_COLD zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix)
2244 {
2245 	smart_str str = {0};
2246 
2247 	smart_str_appends(&str, prefix);
2248 	zend_ast_export_ex(&str, ast, 0, 0);
2249 	smart_str_appends(&str, suffix);
2250 	smart_str_0(&str);
2251 	return str.s;
2252 }
2253 
zend_ast_with_attributes(zend_ast * ast,zend_ast * attr)2254 zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
2255 {
2256 	ZEND_ASSERT(attr->kind == ZEND_AST_ATTRIBUTE_LIST);
2257 
2258 	switch (ast->kind) {
2259 	case ZEND_AST_FUNC_DECL:
2260 	case ZEND_AST_CLOSURE:
2261 	case ZEND_AST_METHOD:
2262 	case ZEND_AST_ARROW_FUNC:
2263 		((zend_ast_decl *) ast)->child[4] = attr;
2264 		break;
2265 	case ZEND_AST_CLASS:
2266 		((zend_ast_decl *) ast)->child[3] = attr;
2267 		break;
2268 	case ZEND_AST_PROP_GROUP:
2269 		ast->child[2] = attr;
2270 		break;
2271 	case ZEND_AST_PARAM:
2272 		ast->child[3] = attr;
2273 		break;
2274 	case ZEND_AST_CLASS_CONST_GROUP:
2275 		ast->child[1] = attr;
2276 		break;
2277 	EMPTY_SWITCH_DEFAULT_CASE()
2278 	}
2279 
2280 	return ast;
2281 }
2282