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