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