xref: /PHP-7.1/Zend/zend_ast.c (revision 962706d1)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 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@zend.com>                             |
17    +----------------------------------------------------------------------+
18 */
19 
20 /* $Id$ */
21 
22 #include "zend_ast.h"
23 #include "zend_API.h"
24 #include "zend_operators.h"
25 #include "zend_language_parser.h"
26 #include "zend_smart_str.h"
27 #include "zend_exceptions.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_size(uint32_t children)41 static inline size_t zend_ast_size(uint32_t children) {
42 	return sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children;
43 }
44 
zend_ast_list_size(uint32_t children)45 static inline size_t zend_ast_list_size(uint32_t children) {
46 	return sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * children;
47 }
48 
zend_ast_create_znode(znode * node)49 ZEND_API zend_ast *zend_ast_create_znode(znode *node) {
50 	zend_ast_znode *ast;
51 
52 	ast = zend_ast_alloc(sizeof(zend_ast_znode));
53 	ast->kind = ZEND_AST_ZNODE;
54 	ast->attr = 0;
55 	ast->lineno = CG(zend_lineno);
56 	ast->node = *node;
57 	return (zend_ast *) ast;
58 }
59 
zend_ast_create_zval_with_lineno(zval * zv,zend_ast_attr attr,uint32_t lineno)60 ZEND_API zend_ast *zend_ast_create_zval_with_lineno(zval *zv, zend_ast_attr attr, uint32_t lineno) {
61 	zend_ast_zval *ast;
62 
63 	ast = zend_ast_alloc(sizeof(zend_ast_zval));
64 	ast->kind = ZEND_AST_ZVAL;
65 	ast->attr = attr;
66 	ZVAL_COPY_VALUE(&ast->val, zv);
67 	ast->val.u2.lineno = lineno;
68 	return (zend_ast *) ast;
69 }
70 
zend_ast_create_zval_ex(zval * zv,zend_ast_attr attr)71 ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr) {
72 	return zend_ast_create_zval_with_lineno(zv, attr, CG(zend_lineno));
73 }
74 
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)75 ZEND_API zend_ast *zend_ast_create_decl(
76 	zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
77 	zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3
78 ) {
79 	zend_ast_decl *ast;
80 
81 	ast = zend_ast_alloc(sizeof(zend_ast_decl));
82 	ast->kind = kind;
83 	ast->attr = 0;
84 	ast->start_lineno = start_lineno;
85 	ast->end_lineno = CG(zend_lineno);
86 	ast->flags = flags;
87 	ast->lex_pos = LANG_SCNG(yy_text);
88 	ast->doc_comment = doc_comment;
89 	ast->name = name;
90 	ast->child[0] = child0;
91 	ast->child[1] = child1;
92 	ast->child[2] = child2;
93 	ast->child[3] = child3;
94 
95 	return (zend_ast *) ast;
96 }
97 
zend_ast_create_from_va_list(zend_ast_kind kind,zend_ast_attr attr,va_list va)98 static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) {
99 	uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT;
100 	zend_ast *ast;
101 
102 	ast = zend_ast_alloc(zend_ast_size(children));
103 	ast->kind = kind;
104 	ast->attr = attr;
105 	ast->lineno = (uint32_t) -1;
106 
107 	for (i = 0; i < children; ++i) {
108 		ast->child[i] = va_arg(va, zend_ast *);
109 		if (ast->child[i] != NULL) {
110 			uint32_t lineno = zend_ast_get_lineno(ast->child[i]);
111 			if (lineno < ast->lineno) {
112 				ast->lineno = lineno;
113 			}
114 		}
115 	}
116 
117 	if (ast->lineno == UINT_MAX) {
118 		ast->lineno = CG(zend_lineno);
119 	}
120 
121 	return ast;
122 }
123 
zend_ast_create_ex(zend_ast_kind kind,zend_ast_attr attr,...)124 ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, ...) {
125 	va_list va;
126 	zend_ast *ast;
127 
128 	va_start(va, attr);
129 	ast = zend_ast_create_from_va_list(kind, attr, va);
130 	va_end(va);
131 
132 	return ast;
133 }
134 
zend_ast_create(zend_ast_kind kind,...)135 ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...) {
136 	va_list va;
137 	zend_ast *ast;
138 
139 	va_start(va, kind);
140 	ast = zend_ast_create_from_va_list(kind, 0, va);
141 	va_end(va);
142 
143 	return ast;
144 }
145 
zend_ast_create_list(uint32_t init_children,zend_ast_kind kind,...)146 ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind kind, ...) {
147 	zend_ast *ast;
148 	zend_ast_list *list;
149 
150 	ast = zend_ast_alloc(zend_ast_list_size(4));
151 	list = (zend_ast_list *) ast;
152 	list->kind = kind;
153 	list->attr = 0;
154 	list->lineno = CG(zend_lineno);
155 	list->children = 0;
156 
157 	{
158 		va_list va;
159 		uint32_t i;
160 		va_start(va, kind);
161 		for (i = 0; i < init_children; ++i) {
162 			zend_ast *child = va_arg(va, zend_ast *);
163 			ast = zend_ast_list_add(ast, child);
164 			if (child != NULL) {
165 				uint32_t lineno = zend_ast_get_lineno(child);
166 				if (lineno < ast->lineno) {
167 					ast->lineno = lineno;
168 				}
169 			}
170 		}
171 		va_end(va);
172 	}
173 
174 	return ast;
175 }
176 
is_power_of_two(uint32_t n)177 static inline zend_bool is_power_of_two(uint32_t n) {
178 	return ((n != 0) && (n == (n & (~n + 1))));
179 }
180 
zend_ast_list_add(zend_ast * ast,zend_ast * op)181 ZEND_API zend_ast *zend_ast_list_add(zend_ast *ast, zend_ast *op) {
182 	zend_ast_list *list = zend_ast_get_list(ast);
183 	if (list->children >= 4 && is_power_of_two(list->children)) {
184 			list = zend_ast_realloc(list,
185 			zend_ast_list_size(list->children), zend_ast_list_size(list->children * 2));
186 	}
187 	list->child[list->children++] = op;
188 	return (zend_ast *) list;
189 }
190 
zend_ast_add_array_element(zval * result,zval * offset,zval * expr)191 static int zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
192 {
193 	switch (Z_TYPE_P(offset)) {
194 		case IS_UNDEF:
195 			if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), expr)) {
196 				zend_error(E_WARNING,
197 					"Cannot add element to the array as the next element is already occupied");
198 				zval_ptr_dtor(expr);
199 			}
200 			break;
201 		case IS_STRING:
202 			zend_symtable_update(Z_ARRVAL_P(result), Z_STR_P(offset), expr);
203 			zval_dtor(offset);
204 			break;
205 		case IS_NULL:
206 			zend_symtable_update(Z_ARRVAL_P(result), ZSTR_EMPTY_ALLOC(), expr);
207 			break;
208 		case IS_LONG:
209 			zend_hash_index_update(Z_ARRVAL_P(result), Z_LVAL_P(offset), expr);
210 			break;
211 		case IS_FALSE:
212 			zend_hash_index_update(Z_ARRVAL_P(result), 0, expr);
213 			break;
214 		case IS_TRUE:
215 			zend_hash_index_update(Z_ARRVAL_P(result), 1, expr);
216 			break;
217 		case IS_DOUBLE:
218 			zend_hash_index_update(Z_ARRVAL_P(result), zend_dval_to_lval(Z_DVAL_P(offset)), expr);
219 			break;
220 		case IS_RESOURCE:
221 			zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
222 			zend_hash_index_update(Z_ARRVAL_P(result), Z_RES_HANDLE_P(offset), expr);
223 			break;
224 		default:
225 			zend_throw_error(NULL, "Illegal offset type");
226 			return FAILURE;
227  	}
228 	return SUCCESS;
229 }
230 
zend_ast_evaluate(zval * result,zend_ast * ast,zend_class_entry * scope)231 ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
232 {
233 	zval op1, op2;
234 	int ret = SUCCESS;
235 
236 	switch (ast->kind) {
237 		case ZEND_AST_BINARY_OP:
238 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
239 				ret = FAILURE;
240 			} else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
241 				zval_dtor(&op1);
242 				ret = FAILURE;
243 			} else {
244 				binary_op_type op = get_binary_op(ast->attr);
245 				ret = op(result, &op1, &op2);
246 				zval_dtor(&op1);
247 				zval_dtor(&op2);
248 			}
249 			break;
250 		case ZEND_AST_GREATER:
251 		case ZEND_AST_GREATER_EQUAL:
252 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
253 				ret = FAILURE;
254 			} else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
255 				zval_dtor(&op1);
256 				ret = FAILURE;
257 			} else {
258 				/* op1 > op2 is the same as op2 < op1 */
259 				binary_op_type op = ast->kind == ZEND_AST_GREATER
260 					? is_smaller_function : is_smaller_or_equal_function;
261 				ret = op(result, &op2, &op1);
262 				zval_dtor(&op1);
263 				zval_dtor(&op2);
264 			}
265 			break;
266 		case ZEND_AST_UNARY_OP:
267 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
268 				ret = FAILURE;
269 			} else {
270 				unary_op_type op = get_unary_op(ast->attr);
271 				ret = op(result, &op1);
272 				zval_dtor(&op1);
273 			}
274 			break;
275 		case ZEND_AST_ZVAL:
276 		{
277 			zval *zv = zend_ast_get_zval(ast);
278 
279 			if (Z_OPT_CONSTANT_P(zv)) {
280 				if (!(Z_TYPE_FLAGS_P(zv) & IS_TYPE_IMMUTABLE)) {
281 					if (UNEXPECTED(zval_update_constant_ex(zv, scope) != SUCCESS)) {
282 						ret = FAILURE;
283 						break;
284 					}
285 					ZVAL_COPY(result, zv);
286 				} else {
287 					ZVAL_COPY_VALUE(result, zv);
288 					if (UNEXPECTED(zval_update_constant_ex(result, scope) != SUCCESS)) {
289 						ret = FAILURE;
290 						break;
291 					}
292 				}
293 			} else {
294 				ZVAL_COPY(result, zv);
295 			}
296 			break;
297 		}
298 		case ZEND_AST_AND:
299 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
300 				ret = FAILURE;
301 				break;
302 			}
303 			if (zend_is_true(&op1)) {
304 				if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
305 					zval_dtor(&op1);
306 					ret = FAILURE;
307 					break;
308 				}
309 				ZVAL_BOOL(result, zend_is_true(&op2));
310 				zval_dtor(&op2);
311 			} else {
312 				ZVAL_FALSE(result);
313 			}
314 			zval_dtor(&op1);
315 			break;
316 		case ZEND_AST_OR:
317 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
318 				ret = FAILURE;
319 				break;
320 			}
321 			if (zend_is_true(&op1)) {
322 				ZVAL_TRUE(result);
323 			} else {
324 				if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
325 					zval_dtor(&op1);
326 					ret = FAILURE;
327 					break;
328 				}
329 				ZVAL_BOOL(result, zend_is_true(&op2));
330 				zval_dtor(&op2);
331 			}
332 			zval_dtor(&op1);
333 			break;
334 		case ZEND_AST_CONDITIONAL:
335 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
336 				ret = FAILURE;
337 				break;
338 			}
339 			if (zend_is_true(&op1)) {
340 				if (!ast->child[1]) {
341 					*result = op1;
342 				} else {
343 					if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) {
344 						zval_dtor(&op1);
345 						ret = FAILURE;
346 						break;
347 					}
348 					zval_dtor(&op1);
349 				}
350 			} else {
351 				if (UNEXPECTED(zend_ast_evaluate(result, ast->child[2], scope) != SUCCESS)) {
352 					zval_dtor(&op1);
353 					ret = FAILURE;
354 					break;
355 				}
356 				zval_dtor(&op1);
357 			}
358 			break;
359 		case ZEND_AST_COALESCE:
360 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
361 				ret = FAILURE;
362 				break;
363 			}
364 			if (Z_TYPE(op1) > IS_NULL) {
365 				*result = op1;
366 			} else {
367 				if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) {
368 					zval_dtor(&op1);
369 					ret = FAILURE;
370 					break;
371 				}
372 				zval_dtor(&op1);
373 			}
374 			break;
375 		case ZEND_AST_UNARY_PLUS:
376 			if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) {
377 				ret = FAILURE;
378 			} else {
379 				ZVAL_LONG(&op1, 0);
380 				ret = add_function(result, &op1, &op2);
381 				zval_dtor(&op2);
382 			}
383 			break;
384 		case ZEND_AST_UNARY_MINUS:
385 			if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) {
386 				ret = FAILURE;
387 			} else {
388 				ZVAL_LONG(&op1, 0);
389 				ret = sub_function(result, &op1, &op2);
390 				zval_dtor(&op2);
391 			}
392 			break;
393 		case ZEND_AST_ARRAY:
394 			array_init(result);
395 			{
396 				uint32_t i;
397 				zend_ast_list *list = zend_ast_get_list(ast);
398 				for (i = 0; i < list->children; i++) {
399 					zend_ast *elem = list->child[i];
400 					if (elem->child[1]) {
401 						if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[1], scope) != SUCCESS)) {
402 							zval_dtor(result);
403 							return FAILURE;
404 						}
405 					} else {
406 						ZVAL_UNDEF(&op1);
407 					}
408 					if (UNEXPECTED(zend_ast_evaluate(&op2, elem->child[0], scope) != SUCCESS)) {
409 						zval_dtor(&op1);
410 						zval_dtor(result);
411 						return FAILURE;
412 					}
413 					if (UNEXPECTED(zend_ast_add_array_element(result, &op1, &op2) != SUCCESS)) {
414 						zval_dtor(&op1);
415 						zval_dtor(&op2);
416 						zval_dtor(result);
417 						return FAILURE;
418 					}
419 				}
420 			}
421 			break;
422 		case ZEND_AST_DIM:
423 			if (ast->child[1] == NULL) {
424 				zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
425 			}
426 
427 			if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
428 				ret = FAILURE;
429 			} else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
430 				zval_dtor(&op1);
431 				ret = FAILURE;
432 			} else {
433 				zval tmp;
434 
435 				if (ast->attr == ZEND_DIM_IS) {
436 					zend_fetch_dimension_by_zval_is(&tmp, &op1, &op2, IS_CONST);
437 				} else {
438 					zend_fetch_dimension_by_zval(&tmp, &op1, &op2);
439 				}
440 
441 				if (UNEXPECTED(Z_ISREF(tmp))) {
442 					ZVAL_DUP(result, Z_REFVAL(tmp));
443 				} else {
444 					ZVAL_DUP(result, &tmp);
445 				}
446 				zval_ptr_dtor(&tmp);
447 				zval_dtor(&op1);
448 				zval_dtor(&op2);
449 			}
450 			break;
451 		default:
452 			zend_throw_error(NULL, "Unsupported constant expression");
453 			ret = FAILURE;
454 	}
455 	return ret;
456 }
457 
zend_ast_copy(zend_ast * ast)458 ZEND_API zend_ast *zend_ast_copy(zend_ast *ast)
459 {
460 	if (ast == NULL) {
461 		return NULL;
462 	} else if (ast->kind == ZEND_AST_ZVAL) {
463 		zend_ast_zval *new = emalloc(sizeof(zend_ast_zval));
464 		new->kind = ZEND_AST_ZVAL;
465 		new->attr = ast->attr;
466 		ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
467 		return (zend_ast *) new;
468 	} else if (zend_ast_is_list(ast)) {
469 		zend_ast_list *list = zend_ast_get_list(ast);
470 		zend_ast_list *new = emalloc(zend_ast_list_size(list->children));
471 		uint32_t i;
472 		new->kind = list->kind;
473 		new->attr = list->attr;
474 		new->children = list->children;
475 		for (i = 0; i < list->children; i++) {
476 			new->child[i] = zend_ast_copy(list->child[i]);
477 		}
478 		return (zend_ast *) new;
479 	} else {
480 		uint32_t i, children = zend_ast_get_num_children(ast);
481 		zend_ast *new = emalloc(zend_ast_size(children));
482 		new->kind = ast->kind;
483 		new->attr = ast->attr;
484 		for (i = 0; i < children; i++) {
485 			new->child[i] = zend_ast_copy(ast->child[i]);
486 		}
487 		return new;
488 	}
489 }
490 
zend_ast_destroy_ex(zend_ast * ast,zend_bool free)491 static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) {
492 	if (!ast) {
493 		return;
494 	}
495 
496 	switch (ast->kind) {
497 		case ZEND_AST_ZVAL:
498 			/* Destroy value without using GC: When opcache moves arrays into SHM it will
499 			 * free the zend_array structure, so references to it from outside the op array
500 			 * become invalid. GC would cause such a reference in the root buffer. */
501 			zval_ptr_dtor_nogc(zend_ast_get_zval(ast));
502 			break;
503 		case ZEND_AST_FUNC_DECL:
504 		case ZEND_AST_CLOSURE:
505 		case ZEND_AST_METHOD:
506 		case ZEND_AST_CLASS:
507 		{
508 			zend_ast_decl *decl = (zend_ast_decl *) ast;
509 			if (decl->name) {
510 			    zend_string_release(decl->name);
511 			}
512 			if (decl->doc_comment) {
513 				zend_string_release(decl->doc_comment);
514 			}
515 			zend_ast_destroy_ex(decl->child[0], free);
516 			zend_ast_destroy_ex(decl->child[1], free);
517 			zend_ast_destroy_ex(decl->child[2], free);
518 			zend_ast_destroy_ex(decl->child[3], free);
519 			break;
520 		}
521 		default:
522 			if (zend_ast_is_list(ast)) {
523 				zend_ast_list *list = zend_ast_get_list(ast);
524 				uint32_t i;
525 				for (i = 0; i < list->children; i++) {
526 					zend_ast_destroy_ex(list->child[i], free);
527 				}
528 			} else {
529 				uint32_t i, children = zend_ast_get_num_children(ast);
530 				for (i = 0; i < children; i++) {
531 					zend_ast_destroy_ex(ast->child[i], free);
532 				}
533 			}
534 	}
535 
536 	if (free) {
537 		efree(ast);
538 	}
539 }
540 
zend_ast_destroy(zend_ast * ast)541 ZEND_API void zend_ast_destroy(zend_ast *ast) {
542 	zend_ast_destroy_ex(ast, 0);
543 }
zend_ast_destroy_and_free(zend_ast * ast)544 ZEND_API void zend_ast_destroy_and_free(zend_ast *ast) {
545 	zend_ast_destroy_ex(ast, 1);
546 }
547 
zend_ast_apply(zend_ast * ast,zend_ast_apply_func fn)548 ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn) {
549 	if (zend_ast_is_list(ast)) {
550 		zend_ast_list *list = zend_ast_get_list(ast);
551 		uint32_t i;
552 		for (i = 0; i < list->children; ++i) {
553 			fn(&list->child[i]);
554 		}
555 	} else {
556 		uint32_t i, children = zend_ast_get_num_children(ast);
557 		for (i = 0; i < children; ++i) {
558 			fn(&ast->child[i]);
559 		}
560 	}
561 }
562 
563 /*
564  * Operator Precendence
565  * ====================
566  * priority  associativity  operators
567  * ----------------------------------
568  *   10     left            include, include_once, eval, require, require_once
569  *   20     left            ,
570  *   30     left            or
571  *   40     left            xor
572  *   50     left            and
573  *   60     right           print
574  *   70     right           yield
575  *   80     right           =>
576  *   85     right           yield from
577  *   90     right           = += -= *= /= .= %= &= |= ^= <<= >>= **=
578  *  100     left            ? :
579  *  110     right           ??
580  *  120     left            ||
581  *  130     left            &&
582  *  140     left            |
583  *  150     left            ^
584  *  160     left            &
585  *  170     non-associative == != === !==
586  *  180     non-associative < <= > >= <=>
587  *  190     left            << >>
588  *  200     left            + - .
589  *  210     left            * / %
590  *  220     right           !
591  *  230     non-associative instanceof
592  *  240     right           + - ++ -- ~ (type) @
593  *  250     right           **
594  *  260     left            [
595  *  270     non-associative clone new
596  */
597 
598 static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent);
599 
zend_ast_export_str(smart_str * str,zend_string * s)600 static void zend_ast_export_str(smart_str *str, zend_string *s)
601 {
602 	size_t i;
603 
604 	for (i = 0; i < ZSTR_LEN(s); i++) {
605 		unsigned char c = ZSTR_VAL(s)[i];
606 		if (c == '\'' || c == '\\') {
607 			smart_str_appendc(str, '\\');
608 			smart_str_appendc(str, c);
609 		} else {
610 			smart_str_appendc(str, c);
611 		}
612 	}
613 }
614 
zend_ast_export_qstr(smart_str * str,char quote,zend_string * s)615 static void zend_ast_export_qstr(smart_str *str, char quote, zend_string *s)
616 {
617 	size_t i;
618 
619 	for (i = 0; i < ZSTR_LEN(s); i++) {
620 		unsigned char c = ZSTR_VAL(s)[i];
621 		if (c < ' ') {
622 			switch (c) {
623 				case '\n':
624 					smart_str_appends(str, "\\n");
625 					break;
626 				case '\r':
627 					smart_str_appends(str, "\\r");
628 					break;
629 				case '\t':
630 					smart_str_appends(str, "\\t");
631 					break;
632 				case '\f':
633 					smart_str_appends(str, "\\f");
634 					break;
635 				case '\v':
636 					smart_str_appends(str, "\\v");
637 					break;
638 #ifdef ZEND_WIN32
639 				case VK_ESCAPE:
640 #else
641 				case '\e':
642 #endif
643 					smart_str_appends(str, "\\e");
644 					break;
645 				default:
646 					smart_str_appends(str, "\\0");
647 					smart_str_appendc(str, '0' + (c / 8));
648 					smart_str_appendc(str, '0' + (c % 8));
649 					break;
650 			}
651 		} else {
652 			if (c == quote || c == '$' || c == '\\') {
653 				smart_str_appendc(str, '\\');
654 			}
655 			smart_str_appendc(str, c);
656 		}
657 	}
658 }
659 
zend_ast_export_indent(smart_str * str,int indent)660 static void zend_ast_export_indent(smart_str *str, int indent)
661 {
662 	while (indent > 0) {
663 		smart_str_appends(str, "    ");
664 		indent--;
665 	}
666 }
667 
zend_ast_export_name(smart_str * str,zend_ast * ast,int priority,int indent)668 static void zend_ast_export_name(smart_str *str, zend_ast *ast, int priority, int indent)
669 {
670 	if (ast->kind == ZEND_AST_ZVAL) {
671 		zval *zv = zend_ast_get_zval(ast);
672 
673 		if (Z_TYPE_P(zv) == IS_STRING) {
674 			smart_str_append(str, Z_STR_P(zv));
675 			return;
676 		}
677 	}
678 	zend_ast_export_ex(str, ast, priority, indent);
679 }
680 
zend_ast_export_ns_name(smart_str * str,zend_ast * ast,int priority,int indent)681 static void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int priority, int indent)
682 {
683 	if (ast->kind == ZEND_AST_ZVAL) {
684 		zval *zv = zend_ast_get_zval(ast);
685 
686 		if (Z_TYPE_P(zv) == IS_STRING) {
687 		    if (ast->attr == ZEND_NAME_FQ) {
688 				smart_str_appendc(str, '\\');
689 		    } else if (ast->attr == ZEND_NAME_RELATIVE) {
690 				smart_str_appends(str, "namespace\\");
691 		    }
692 			smart_str_append(str, Z_STR_P(zv));
693 			return;
694 		}
695 	}
696 	zend_ast_export_ex(str, ast, priority, indent);
697 }
698 
zend_ast_valid_var_char(char ch)699 static int zend_ast_valid_var_char(char ch)
700 {
701 	unsigned char c = (unsigned char)ch;
702 
703 	if (c != '_' && c < 127 &&
704 	    (c < '0' || c > '9') &&
705 	    (c < 'A' || c > 'Z') &&
706 	    (c < 'a' || c > 'z')) {
707 		return 0;
708 	}
709 	return 1;
710 }
711 
zend_ast_valid_var_name(const char * s,size_t len)712 static int zend_ast_valid_var_name(const char *s, size_t len)
713 {
714 	unsigned char c;
715 	size_t i;
716 
717 	if (len == 0) {
718 		return 0;
719 	}
720 	c = (unsigned char)s[0];
721 	if (c != '_' && c < 127 &&
722 	    (c < 'A' || c > 'Z') &&
723 	    (c < 'a' || c > 'z')) {
724 		return 0;
725 	}
726 	for (i = 1; i < len; i++) {
727 		c = (unsigned char)s[i];
728 		if (c != '_' && c < 127 &&
729 		    (c < '0' || c > '9') &&
730 		    (c < 'A' || c > 'Z') &&
731 		    (c < 'a' || c > 'z')) {
732 			return 0;
733 		}
734 	}
735 	return 1;
736 }
737 
zend_ast_export_var(smart_str * str,zend_ast * ast,int priority,int indent)738 static void zend_ast_export_var(smart_str *str, zend_ast *ast, int priority, int indent)
739 {
740 	if (ast->kind == ZEND_AST_ZVAL) {
741 		zval *zv = zend_ast_get_zval(ast);
742 		if (Z_TYPE_P(zv) == IS_STRING &&
743 		    zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) {
744 			smart_str_append(str, Z_STR_P(zv));
745 			return;
746 		}
747 	} else if (ast->kind == ZEND_AST_VAR) {
748 		zend_ast_export_ex(str, ast, 0, indent);
749 		return;
750 	}
751 	smart_str_appendc(str, '{');
752 	zend_ast_export_name(str, ast, 0, indent);
753 	smart_str_appendc(str, '}');
754 }
755 
zend_ast_export_list(smart_str * str,zend_ast_list * list,int separator,int priority,int indent)756 static void zend_ast_export_list(smart_str *str, zend_ast_list *list, int separator, int priority, int indent)
757 {
758 	uint32_t i = 0;
759 
760 	while (i < list->children) {
761 		if (i != 0 && separator) {
762 			smart_str_appends(str, ", ");
763 		}
764 		zend_ast_export_ex(str, list->child[i], priority, indent);
765 		i++;
766 	}
767 }
768 
zend_ast_export_encaps_list(smart_str * str,char quote,zend_ast_list * list,int indent)769 static void zend_ast_export_encaps_list(smart_str *str, char quote, zend_ast_list *list, int indent)
770 {
771 	uint32_t i = 0;
772 	zend_ast *ast;
773 
774 	while (i < list->children) {
775 		ast = list->child[i];
776 		if (ast->kind == ZEND_AST_ZVAL) {
777 			zval *zv = zend_ast_get_zval(ast);
778 
779 			ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
780 			zend_ast_export_qstr(str, quote, Z_STR_P(zv));
781 		} else if (ast->kind == ZEND_AST_VAR &&
782 		           ast->child[0]->kind == ZEND_AST_ZVAL &&
783 		           (i + 1 == list->children ||
784 		            list->child[i + 1]->kind != ZEND_AST_ZVAL ||
785 		            !zend_ast_valid_var_char(
786 		                *Z_STRVAL_P(
787 		                    zend_ast_get_zval(list->child[i + 1]))))) {
788 			zend_ast_export_ex(str, ast, 0, indent);
789 		} else {
790 			smart_str_appendc(str, '{');
791 			zend_ast_export_ex(str, ast, 0, indent);
792 			smart_str_appendc(str, '}');
793 		}
794 		i++;
795 	}
796 }
797 
zend_ast_export_name_list_ex(smart_str * str,zend_ast_list * list,int indent,const char * separator)798 static void zend_ast_export_name_list_ex(smart_str *str, zend_ast_list *list, int indent, const char *separator)
799 {
800 	uint32_t i = 0;
801 
802 	while (i < list->children) {
803 		if (i != 0) {
804 			smart_str_appends(str, separator);
805 		}
806 		zend_ast_export_name(str, list->child[i], 0, indent);
807 		i++;
808 	}
809 }
810 
811 #define zend_ast_export_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, ", ")
812 #define zend_ast_export_catch_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, "|")
813 
zend_ast_export_var_list(smart_str * str,zend_ast_list * list,int indent)814 static void zend_ast_export_var_list(smart_str *str, zend_ast_list *list, int indent)
815 {
816 	uint32_t i = 0;
817 
818 	while (i < list->children) {
819 		if (i != 0) {
820 			smart_str_appends(str, ", ");
821 		}
822 		if (list->child[i]->attr) {
823 			smart_str_appendc(str, '&');
824 		}
825 		smart_str_appendc(str, '$');
826 		zend_ast_export_name(str, list->child[i], 20, indent);
827 		i++;
828 	}
829 }
830 
zend_ast_export_stmt(smart_str * str,zend_ast * ast,int indent)831 static void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int indent)
832 {
833 	if (!ast) {
834 		return;
835 	}
836 
837 	if (ast->kind == ZEND_AST_STMT_LIST ||
838 	    ast->kind == ZEND_AST_TRAIT_ADAPTATIONS) {
839 		zend_ast_list *list = (zend_ast_list*)ast;
840 		uint32_t i = 0;
841 
842 		while (i < list->children) {
843 			ast = list->child[i];
844 			zend_ast_export_stmt(str, ast, indent);
845 			i++;
846 		}
847 	} else {
848 		zend_ast_export_indent(str, indent);
849 		zend_ast_export_ex(str, ast, 0, indent);
850 		switch (ast->kind) {
851 			case ZEND_AST_LABEL:
852 			case ZEND_AST_IF:
853 			case ZEND_AST_SWITCH:
854 			case ZEND_AST_WHILE:
855 			case ZEND_AST_TRY:
856 			case ZEND_AST_FOR:
857 			case ZEND_AST_FOREACH:
858 			case ZEND_AST_FUNC_DECL:
859 			case ZEND_AST_METHOD:
860 			case ZEND_AST_CLASS:
861 			case ZEND_AST_USE_TRAIT:
862 			case ZEND_AST_NAMESPACE:
863 			case ZEND_AST_DECLARE:
864 				break;
865 			default:
866 				smart_str_appendc(str, ';');
867 				break;
868 		}
869 		smart_str_appendc(str, '\n');
870 	}
871 }
872 
zend_ast_export_if_stmt(smart_str * str,zend_ast_list * list,int indent)873 static void zend_ast_export_if_stmt(smart_str *str, zend_ast_list *list, int indent)
874 {
875 	uint32_t i;
876 	zend_ast *ast;
877 
878 tail_call:
879 	i = 0;
880 	while (i < list->children) {
881 		ast = list->child[i];
882 		ZEND_ASSERT(ast->kind == ZEND_AST_IF_ELEM);
883 		if (ast->child[0]) {
884 			if (i == 0) {
885 				smart_str_appends(str, "if (");
886 			} else {
887 				zend_ast_export_indent(str, indent);
888 				smart_str_appends(str, "} elseif (");
889 			}
890 			zend_ast_export_ex(str, ast->child[0], 0, indent);
891 			smart_str_appends(str, ") {\n");
892 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
893 		} else {
894 			zend_ast_export_indent(str, indent);
895 			smart_str_appends(str, "} else ");
896 			if (ast->child[1]->kind == ZEND_AST_IF) {
897 				list = (zend_ast_list*)ast->child[1];
898 				goto tail_call;
899 			} else {
900 				smart_str_appends(str, "{\n");
901 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
902 			}
903 		}
904 		i++;
905 	}
906 	zend_ast_export_indent(str, indent);
907 	smart_str_appendc(str, '}');
908 }
909 
zend_ast_export_zval(smart_str * str,zval * zv,int priority,int indent)910 static void zend_ast_export_zval(smart_str *str, zval *zv, int priority, int indent)
911 {
912 	zend_long idx;
913 	zend_string *key;
914 	zval *val;
915 	int first;
916 
917 	ZVAL_DEREF(zv);
918 	switch (Z_TYPE_P(zv)) {
919 		case IS_NULL:
920 			smart_str_appends(str, "null");
921 			break;
922 		case IS_FALSE:
923 			smart_str_appends(str, "false");
924 			break;
925 		case IS_TRUE:
926 			smart_str_appends(str, "true");
927 			break;
928 		case IS_LONG:
929 			smart_str_append_long(str, Z_LVAL_P(zv));
930 			break;
931 		case IS_DOUBLE:
932 			key = zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(zv));
933 			smart_str_appendl(str, ZSTR_VAL(key), ZSTR_LEN(key));
934 			zend_string_release(key);
935 			break;
936 		case IS_STRING:
937 			smart_str_appendc(str, '\'');
938 			zend_ast_export_str(str, Z_STR_P(zv));
939 			smart_str_appendc(str, '\'');
940 			break;
941 		case IS_ARRAY:
942 			smart_str_appendc(str, '[');
943 			first = 1;
944 			ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zv), idx, key, val) {
945 				if (first) {
946 					first = 0;
947 				} else {
948 					smart_str_appends(str, ", ");
949 				}
950 				if (key) {
951 					smart_str_appendc(str, '\'');
952 					zend_ast_export_str(str, key);
953 					smart_str_appends(str, "' => ");
954 				} else {
955 					smart_str_append_long(str, idx);
956 					smart_str_appends(str, " => ");
957 				}
958 				zend_ast_export_zval(str, val, 0, indent);
959 			} ZEND_HASH_FOREACH_END();
960 			smart_str_appendc(str, ']');
961 			break;
962 		case IS_CONSTANT:
963 			smart_str_appendl(str, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
964 			break;
965 		case IS_CONSTANT_AST:
966 			zend_ast_export_ex(str, Z_ASTVAL_P(zv), priority, indent);
967 			break;
968 		EMPTY_SWITCH_DEFAULT_CASE();
969 	}
970 }
971 
zend_ast_export_class_no_header(smart_str * str,zend_ast_decl * decl,int indent)972 static void zend_ast_export_class_no_header(smart_str *str, zend_ast_decl *decl, int indent) {
973 	if (decl->child[0]) {
974 		smart_str_appends(str, " extends ");
975 		zend_ast_export_ns_name(str, decl->child[0], 0, indent);
976 	}
977 	if (decl->child[1]) {
978 		smart_str_appends(str, " implements ");
979 		zend_ast_export_ex(str, decl->child[1], 0, indent);
980 	}
981 	smart_str_appends(str, " {\n");
982 	zend_ast_export_stmt(str, decl->child[2], indent + 1);
983 	zend_ast_export_indent(str, indent);
984 	smart_str_appends(str, "}");
985 }
986 
987 #define BINARY_OP(_op, _p, _pl, _pr) do { \
988 		op = _op; \
989 		p = _p; \
990 		pl = _pl; \
991 		pr = _pr; \
992 		goto binary_op; \
993 	} while (0)
994 
995 #define PREFIX_OP(_op, _p, _pl) do { \
996 		op = _op; \
997 		p = _p; \
998 		pl = _pl; \
999 		goto prefix_op; \
1000 	} while (0)
1001 
1002 #define FUNC_OP(_op) do { \
1003 		op = _op; \
1004 		goto func_op; \
1005 	} while (0)
1006 
1007 #define POSTFIX_OP(_op, _p, _pl) do { \
1008 		op = _op; \
1009 		p = _p; \
1010 		pl = _pl; \
1011 		goto postfix_op; \
1012 	} while (0)
1013 
1014 #define APPEND_NODE_1(_op) do { \
1015 		op = _op; \
1016 		goto append_node_1; \
1017 	} while (0)
1018 
1019 #define APPEND_STR(_op) do { \
1020 		op = _op; \
1021 		goto append_str; \
1022 	} while (0)
1023 
1024 #define APPEND_DEFAULT_VALUE(n) do { \
1025 		p = n; \
1026 		goto append_default_value; \
1027 	} while (0)
1028 
zend_ast_export_ex(smart_str * str,zend_ast * ast,int priority,int indent)1029 static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent)
1030 {
1031 	zend_ast_decl *decl;
1032 	int p, pl, pr;
1033 	const char *op;
1034 
1035 tail_call:
1036 	if (!ast) {
1037 		return;
1038 	}
1039 	switch (ast->kind) {
1040 		/* special nodes */
1041 		case ZEND_AST_ZVAL:
1042 			zend_ast_export_zval(str, zend_ast_get_zval(ast), priority, indent);
1043 			break;
1044 		case ZEND_AST_ZNODE:
1045 			/* This AST kind is only used for temporary nodes during compilation */
1046 			ZEND_ASSERT(0);
1047 			break;
1048 
1049 		/* declaration nodes */
1050 		case ZEND_AST_FUNC_DECL:
1051 		case ZEND_AST_CLOSURE:
1052 		case ZEND_AST_METHOD:
1053 			decl = (zend_ast_decl *) ast;
1054 			if (decl->flags & ZEND_ACC_PUBLIC) {
1055 				smart_str_appends(str, "public ");
1056 			} else if (decl->flags & ZEND_ACC_PROTECTED) {
1057 				smart_str_appends(str, "protected ");
1058 			} else if (decl->flags & ZEND_ACC_PRIVATE) {
1059 				smart_str_appends(str, "private ");
1060 			}
1061 			if (decl->flags & ZEND_ACC_STATIC) {
1062 				smart_str_appends(str, "static ");
1063 			}
1064 			if (decl->flags & ZEND_ACC_ABSTRACT) {
1065 				smart_str_appends(str, "abstract ");
1066 			}
1067 			if (decl->flags & ZEND_ACC_FINAL) {
1068 				smart_str_appends(str, "final ");
1069 			}
1070 			smart_str_appends(str, "function ");
1071 			if (decl->flags & ZEND_ACC_RETURN_REFERENCE) {
1072 				smart_str_appendc(str, '&');
1073 			}
1074 			if (ast->kind != ZEND_AST_CLOSURE) {
1075 				smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
1076 			}
1077 			smart_str_appendc(str, '(');
1078 			zend_ast_export_ex(str, decl->child[0], 0, indent);
1079 			smart_str_appendc(str, ')');
1080 			zend_ast_export_ex(str, decl->child[1], 0, indent);
1081 			if (decl->child[3]) {
1082 				smart_str_appends(str, ": ");
1083 				if (decl->child[3]->attr & ZEND_TYPE_NULLABLE) {
1084 					smart_str_appendc(str, '?');
1085 				}
1086 				zend_ast_export_ns_name(str, decl->child[3], 0, indent);
1087 			}
1088 			if (decl->child[2]) {
1089 				smart_str_appends(str, " {\n");
1090 				zend_ast_export_stmt(str, decl->child[2], indent + 1);
1091 				zend_ast_export_indent(str, indent);
1092 				smart_str_appendc(str, '}');
1093 				if (ast->kind != ZEND_AST_CLOSURE) {
1094 					smart_str_appendc(str, '\n');
1095 				}
1096 			} else {
1097 				smart_str_appends(str, ";\n");
1098 			}
1099 			break;
1100 		case ZEND_AST_CLASS:
1101 			decl = (zend_ast_decl *) ast;
1102 			if (decl->flags & ZEND_ACC_INTERFACE) {
1103 				smart_str_appends(str, "interface ");
1104 			} else if (decl->flags & ZEND_ACC_TRAIT) {
1105 				smart_str_appends(str, "trait ");
1106 			} else {
1107 				if (decl->flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
1108 					smart_str_appends(str, "abstract ");
1109 				}
1110 				if (decl->flags & ZEND_ACC_FINAL) {
1111 					smart_str_appends(str, "final ");
1112 				}
1113 				smart_str_appends(str, "class ");
1114 			}
1115 			smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
1116 			zend_ast_export_class_no_header(str, decl, indent);
1117 			smart_str_appendc(str, '\n');
1118 			break;
1119 
1120 		/* list nodes */
1121 		case ZEND_AST_ARG_LIST:
1122 		case ZEND_AST_EXPR_LIST:
1123 		case ZEND_AST_PARAM_LIST:
1124 simple_list:
1125 			zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1126 			break;
1127 		case ZEND_AST_ARRAY:
1128 			smart_str_appendc(str, '[');
1129 			zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1130 			smart_str_appendc(str, ']');
1131 			break;
1132 		case ZEND_AST_ENCAPS_LIST:
1133 			smart_str_appendc(str, '"');
1134 			zend_ast_export_encaps_list(str, '"', (zend_ast_list*)ast, indent);
1135 			smart_str_appendc(str, '"');
1136 			break;
1137 		case ZEND_AST_STMT_LIST:
1138 		case ZEND_AST_TRAIT_ADAPTATIONS:
1139 			zend_ast_export_stmt(str, ast, indent);
1140 			break;
1141 		case ZEND_AST_IF:
1142 			zend_ast_export_if_stmt(str, (zend_ast_list*)ast, indent);
1143 			break;
1144 		case ZEND_AST_SWITCH_LIST:
1145 		case ZEND_AST_CATCH_LIST:
1146 			zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
1147 			break;
1148 		case ZEND_AST_CLOSURE_USES:
1149 			smart_str_appends(str, " use(");
1150 			zend_ast_export_var_list(str, (zend_ast_list*)ast, indent);
1151 			smart_str_appendc(str, ')');
1152 			break;
1153 		case ZEND_AST_PROP_DECL:
1154 			if (ast->attr & ZEND_ACC_PUBLIC) {
1155 				smart_str_appends(str, "public ");
1156 			} else if (ast->attr & ZEND_ACC_PROTECTED) {
1157 				smart_str_appends(str, "protected ");
1158 			} else if (ast->attr & ZEND_ACC_PRIVATE) {
1159 				smart_str_appends(str, "private ");
1160 			}
1161 			if (ast->attr & ZEND_ACC_STATIC) {
1162 				smart_str_appends(str, "static ");
1163 			}
1164 			goto simple_list;
1165 		case ZEND_AST_CONST_DECL:
1166 		case ZEND_AST_CLASS_CONST_DECL:
1167 			smart_str_appends(str, "const ");
1168 			goto simple_list;
1169 		case ZEND_AST_NAME_LIST:
1170 			zend_ast_export_name_list(str, (zend_ast_list*)ast, indent);
1171 			break;
1172 		case ZEND_AST_USE:
1173 			smart_str_appends(str, "use ");
1174 			if (ast->attr == T_FUNCTION) {
1175 				smart_str_appends(str, "function ");
1176 			} else if (ast->attr == T_CONST) {
1177 				smart_str_appends(str, "const ");
1178 			}
1179 			goto simple_list;
1180 
1181 		/* 0 child nodes */
1182 		case ZEND_AST_MAGIC_CONST:
1183 			switch (ast->attr) {
1184 				case T_LINE:     APPEND_STR("__LINE__");
1185 				case T_FILE:     APPEND_STR("__FILE__");
1186 				case T_DIR:      APPEND_STR("__DIR__");
1187 				case T_TRAIT_C:  APPEND_STR("__TRAIT__");
1188 				case T_METHOD_C: APPEND_STR("__METHOD__");
1189 				case T_FUNC_C:   APPEND_STR("__FUNCTION__");
1190 				case T_NS_C:     APPEND_STR("__NAMESPACE__");
1191 				case T_CLASS_C:  APPEND_STR("__CLASS__");
1192 				EMPTY_SWITCH_DEFAULT_CASE();
1193 			}
1194 			break;
1195 		case ZEND_AST_TYPE:
1196 			switch (ast->attr) {
1197 				case IS_ARRAY:    APPEND_STR("array");
1198 				case IS_CALLABLE: APPEND_STR("callable");
1199 				EMPTY_SWITCH_DEFAULT_CASE();
1200 			}
1201 			break;
1202 
1203 		/* 1 child node */
1204 		case ZEND_AST_VAR:
1205 			smart_str_appendc(str, '$');
1206 			zend_ast_export_var(str, ast->child[0], 0, indent);
1207 			break;
1208 		case ZEND_AST_CONST:
1209 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1210 			break;
1211 		case ZEND_AST_UNPACK:
1212 			smart_str_appends(str, "...");
1213 			ast = ast->child[0];
1214 			goto tail_call;
1215 		case ZEND_AST_UNARY_PLUS:  PREFIX_OP("+", 240, 241);
1216 		case ZEND_AST_UNARY_MINUS: PREFIX_OP("-", 240, 241);
1217 		case ZEND_AST_CAST:
1218 			switch (ast->attr) {
1219 				case IS_NULL:      PREFIX_OP("(unset)",  240, 241);
1220 				case _IS_BOOL:     PREFIX_OP("(bool)",   240, 241);
1221 				case IS_LONG:      PREFIX_OP("(int)",    240, 241);
1222 				case IS_DOUBLE:    PREFIX_OP("(double)", 240, 241);
1223 				case IS_STRING:    PREFIX_OP("(string)", 240, 241);
1224 				case IS_ARRAY:     PREFIX_OP("(array)",  240, 241);
1225 				case IS_OBJECT:    PREFIX_OP("(object)", 240, 241);
1226 				EMPTY_SWITCH_DEFAULT_CASE();
1227 			}
1228 			break;
1229 		case ZEND_AST_EMPTY:
1230 			FUNC_OP("empty");
1231 		case ZEND_AST_ISSET:
1232 			FUNC_OP("isset");
1233 		case ZEND_AST_SILENCE:
1234 			PREFIX_OP("@", 240, 241);
1235 		case ZEND_AST_SHELL_EXEC:
1236 			smart_str_appendc(str, '`');
1237 			if (ast->child[0]->kind == ZEND_AST_ENCAPS_LIST) {
1238 				zend_ast_export_encaps_list(str, '`', (zend_ast_list*)ast->child[0], indent);
1239 			} else {
1240 				zval *zv;
1241 				ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_ZVAL);
1242 				zv = zend_ast_get_zval(ast->child[0]);
1243 				ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
1244 				zend_ast_export_qstr(str, '`', Z_STR_P(zv));
1245 			}
1246 			smart_str_appendc(str, '`');
1247 			break;
1248 		case ZEND_AST_CLONE:
1249 			PREFIX_OP("clone ", 270, 271);
1250 		case ZEND_AST_EXIT:
1251 			if (ast->child[0]) {
1252 				FUNC_OP("exit");
1253 			} else {
1254 				APPEND_STR("exit");
1255 			}
1256 			break;
1257 		case ZEND_AST_PRINT:
1258 			PREFIX_OP("print ", 60, 61);
1259 		case ZEND_AST_INCLUDE_OR_EVAL:
1260 			switch (ast->attr) {
1261 				case ZEND_INCLUDE_ONCE: FUNC_OP("include_once");
1262 				case ZEND_INCLUDE:      FUNC_OP("include");
1263 				case ZEND_REQUIRE_ONCE: FUNC_OP("require_once");
1264 				case ZEND_REQUIRE:      FUNC_OP("require");
1265 				case ZEND_EVAL:         FUNC_OP("eval");
1266 				EMPTY_SWITCH_DEFAULT_CASE();
1267 			}
1268 			break;
1269 		case ZEND_AST_UNARY_OP:
1270 			switch (ast->attr) {
1271 				case ZEND_BW_NOT:   PREFIX_OP("~", 240, 241);
1272 				case ZEND_BOOL_NOT: PREFIX_OP("!", 240, 241);
1273 				EMPTY_SWITCH_DEFAULT_CASE();
1274 			}
1275 			break;
1276 		case ZEND_AST_PRE_INC:
1277 			PREFIX_OP("++", 240, 241);
1278 		case ZEND_AST_PRE_DEC:
1279 			PREFIX_OP("--", 240, 241);
1280 		case ZEND_AST_POST_INC:
1281 			POSTFIX_OP("++", 240, 241);
1282 		case ZEND_AST_POST_DEC:
1283 			POSTFIX_OP("--", 240, 241);
1284 
1285 		case ZEND_AST_GLOBAL:
1286 			APPEND_NODE_1("global");
1287 		case ZEND_AST_UNSET:
1288 			FUNC_OP("unset");
1289 		case ZEND_AST_RETURN:
1290 			APPEND_NODE_1("return");
1291 		case ZEND_AST_LABEL:
1292 			zend_ast_export_name(str, ast->child[0], 0, indent);
1293 			smart_str_appendc(str, ':');
1294 			break;
1295 		case ZEND_AST_REF:
1296 			smart_str_appendc(str, '&');
1297 			ast = ast->child[0];
1298 			goto tail_call;
1299 		case ZEND_AST_HALT_COMPILER:
1300 			APPEND_STR("__HALT_COMPILER()");
1301 		case ZEND_AST_ECHO:
1302 			APPEND_NODE_1("echo");
1303 		case ZEND_AST_THROW:
1304 			APPEND_NODE_1("throw");
1305 		case ZEND_AST_GOTO:
1306 			smart_str_appends(str, "goto ");
1307 			zend_ast_export_name(str, ast->child[0], 0, indent);
1308 			break;
1309 		case ZEND_AST_BREAK:
1310 			APPEND_NODE_1("break");
1311 		case ZEND_AST_CONTINUE:
1312 			APPEND_NODE_1("continue");
1313 
1314 		/* 2 child nodes */
1315 		case ZEND_AST_DIM:
1316 			zend_ast_export_ex(str, ast->child[0], 260, indent);
1317 			smart_str_appendc(str, '[');
1318 			if (ast->child[1]) {
1319 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1320 			}
1321 			smart_str_appendc(str, ']');
1322 			break;
1323 		case ZEND_AST_PROP:
1324 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1325 			smart_str_appends(str, "->");
1326 			zend_ast_export_var(str, ast->child[1], 0, indent);
1327 			break;
1328 		case ZEND_AST_STATIC_PROP:
1329 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1330 			smart_str_appends(str, "::$");
1331 			zend_ast_export_var(str, ast->child[1], 0, indent);
1332 			break;
1333 		case ZEND_AST_CALL:
1334 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1335 			smart_str_appendc(str, '(');
1336 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1337 			smart_str_appendc(str, ')');
1338 			break;
1339 		case ZEND_AST_CLASS_CONST:
1340 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1341 			smart_str_appends(str, "::");
1342 			zend_ast_export_name(str, ast->child[1], 0, indent);
1343 			break;
1344 		case ZEND_AST_ASSIGN:            BINARY_OP(" = ",   90, 91, 90);
1345 		case ZEND_AST_ASSIGN_REF:        BINARY_OP(" =& ",  90, 91, 90);
1346 		case ZEND_AST_ASSIGN_OP:
1347 			switch (ast->attr) {
1348 				case ZEND_ASSIGN_ADD:    BINARY_OP(" += ",  90, 91, 90);
1349 				case ZEND_ASSIGN_SUB:    BINARY_OP(" -= ",  90, 91, 90);
1350 				case ZEND_ASSIGN_MUL:    BINARY_OP(" *= ",  90, 91, 90);
1351 				case ZEND_ASSIGN_DIV:    BINARY_OP(" /= ",  90, 91, 90);
1352 				case ZEND_ASSIGN_MOD:    BINARY_OP(" %= ",  90, 91, 90);
1353 				case ZEND_ASSIGN_SL:     BINARY_OP(" <<= ", 90, 91, 90);
1354 				case ZEND_ASSIGN_SR:     BINARY_OP(" >>= ", 90, 91, 90);
1355 				case ZEND_ASSIGN_CONCAT: BINARY_OP(" .= ",  90, 91, 90);
1356 				case ZEND_ASSIGN_BW_OR:  BINARY_OP(" |= ",  90, 91, 90);
1357 				case ZEND_ASSIGN_BW_AND: BINARY_OP(" &= ",  90, 91, 90);
1358 				case ZEND_ASSIGN_BW_XOR: BINARY_OP(" ^= ",  90, 91, 90);
1359 				case ZEND_ASSIGN_POW:    BINARY_OP(" **= ", 90, 91, 90);
1360 				EMPTY_SWITCH_DEFAULT_CASE();
1361 			}
1362 			break;
1363 		case ZEND_AST_BINARY_OP:
1364 			switch (ast->attr) {
1365 				case ZEND_ADD:                 BINARY_OP(" + ",   200, 200, 201);
1366 				case ZEND_SUB:                 BINARY_OP(" - ",   200, 200, 201);
1367 				case ZEND_MUL:                 BINARY_OP(" * ",   210, 210, 211);
1368 				case ZEND_DIV:                 BINARY_OP(" / ",   210, 210, 211);
1369 				case ZEND_MOD:                 BINARY_OP(" % ",   210, 210, 211);
1370 				case ZEND_SL:                  BINARY_OP(" << ",  190, 190, 191);
1371 				case ZEND_SR:                  BINARY_OP(" >> ",  190, 190, 191);
1372 				case ZEND_CONCAT:              BINARY_OP(" . ",   200, 200, 201);
1373 				case ZEND_BW_OR:               BINARY_OP(" | ",   140, 140, 141);
1374 				case ZEND_BW_AND:              BINARY_OP(" & ",   160, 160, 161);
1375 				case ZEND_BW_XOR:              BINARY_OP(" ^ ",   150, 150, 151);
1376 				case ZEND_IS_IDENTICAL:        BINARY_OP(" === ", 170, 171, 171);
1377 				case ZEND_IS_NOT_IDENTICAL:    BINARY_OP(" !== ", 170, 171, 171);
1378 				case ZEND_IS_EQUAL:            BINARY_OP(" == ",  170, 171, 171);
1379 				case ZEND_IS_NOT_EQUAL:        BINARY_OP(" != ",  170, 171, 171);
1380 				case ZEND_IS_SMALLER:          BINARY_OP(" < ",   180, 181, 181);
1381 				case ZEND_IS_SMALLER_OR_EQUAL: BINARY_OP(" <= ",  180, 181, 181);
1382 				case ZEND_POW:                 BINARY_OP(" ** ",  250, 251, 250);
1383 				case ZEND_BOOL_XOR:            BINARY_OP(" xor ",  40,  40,  41);
1384 				case ZEND_SPACESHIP:           BINARY_OP(" <=> ", 180, 181, 181);
1385 				EMPTY_SWITCH_DEFAULT_CASE();
1386 			}
1387 			break;
1388 		case ZEND_AST_GREATER:                 BINARY_OP(" > ",   180, 181, 181);
1389 		case ZEND_AST_GREATER_EQUAL:           BINARY_OP(" >= ",  180, 181, 181);
1390 		case ZEND_AST_AND:                     BINARY_OP(" && ",  130, 130, 131);
1391 		case ZEND_AST_OR:                      BINARY_OP(" || ",  120, 120, 121);
1392 		case ZEND_AST_ARRAY_ELEM:
1393 			if (ast->child[1]) {
1394 				zend_ast_export_ex(str, ast->child[1], 80, indent);
1395 				smart_str_appends(str, " => ");
1396 			}
1397 			zend_ast_export_ex(str, ast->child[0], 80, indent);
1398 			break;
1399 		case ZEND_AST_NEW:
1400 			smart_str_appends(str, "new ");
1401 			if (ast->child[0]->kind == ZEND_AST_CLASS) {
1402 				smart_str_appends(str, "class");
1403 				if (zend_ast_get_list(ast->child[1])->children) {
1404 					smart_str_appendc(str, '(');
1405 					zend_ast_export_ex(str, ast->child[1], 0, indent);
1406 					smart_str_appendc(str, ')');
1407 				}
1408 				zend_ast_export_class_no_header(str, (zend_ast_decl *) ast->child[0], indent);
1409 			} else {
1410 				zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1411 				smart_str_appendc(str, '(');
1412 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1413 				smart_str_appendc(str, ')');
1414 			}
1415 			break;
1416 		case ZEND_AST_INSTANCEOF:
1417 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1418 			smart_str_appends(str, " instanceof ");
1419 			zend_ast_export_ns_name(str, ast->child[1], 0, indent);
1420 			break;
1421 		case ZEND_AST_YIELD:
1422 			if (priority > 70) smart_str_appendc(str, '(');
1423 			smart_str_appends(str, "yield ");
1424 			if (ast->child[0]) {
1425 				if (ast->child[1]) {
1426 					zend_ast_export_ex(str, ast->child[1], 70, indent);
1427 					smart_str_appends(str, " => ");
1428 				}
1429 				zend_ast_export_ex(str, ast->child[0], 70, indent);
1430 			}
1431 			if (priority > 70) smart_str_appendc(str, ')');
1432 			break;
1433 		case ZEND_AST_YIELD_FROM:
1434 			PREFIX_OP("yield from ", 85, 86);
1435 		case ZEND_AST_COALESCE: BINARY_OP(" ?? ", 110, 111, 110);
1436 		case ZEND_AST_STATIC:
1437 			smart_str_appends(str, "static $");
1438 			zend_ast_export_name(str, ast->child[0], 0, indent);
1439 			APPEND_DEFAULT_VALUE(1);
1440 		case ZEND_AST_WHILE:
1441 			smart_str_appends(str, "while (");
1442 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1443 			smart_str_appends(str, ") {\n");
1444 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1445 			zend_ast_export_indent(str, indent);
1446 			smart_str_appendc(str, '}');
1447 			break;
1448 		case ZEND_AST_DO_WHILE:
1449 			smart_str_appends(str, "do {\n");
1450 			zend_ast_export_stmt(str, ast->child[0], indent + 1);
1451 			zend_ast_export_indent(str, indent);
1452 			smart_str_appends(str, "} while (");
1453 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1454 			smart_str_appendc(str, ')');
1455 			break;
1456 
1457 		case ZEND_AST_IF_ELEM:
1458 			if (ast->child[0]) {
1459 				smart_str_appends(str, "if (");
1460 				zend_ast_export_ex(str, ast->child[0], 0, indent);
1461 				smart_str_appends(str, ") {\n");
1462 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1463 			} else {
1464 				smart_str_appends(str, "else {\n");
1465 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1466 			}
1467 			zend_ast_export_indent(str, indent);
1468 			smart_str_appendc(str, '}');
1469 			break;
1470 		case ZEND_AST_SWITCH:
1471 			smart_str_appends(str, "switch (");
1472 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1473 			smart_str_appends(str, ") {\n");
1474 			zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
1475 			zend_ast_export_indent(str, indent);
1476 			smart_str_appendc(str, '}');
1477 			break;
1478 		case ZEND_AST_SWITCH_CASE:
1479 			zend_ast_export_indent(str, indent);
1480 			if (ast->child[0]) {
1481 				smart_str_appends(str, "case ");
1482 				zend_ast_export_ex(str, ast->child[0], 0, indent);
1483 				smart_str_appends(str, ":\n");
1484 			} else {
1485 				smart_str_appends(str, "default:\n");
1486 			}
1487 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1488 			break;
1489 		case ZEND_AST_DECLARE:
1490 			smart_str_appends(str, "declare(");
1491 			ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_CONST_DECL);
1492 			zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
1493 			smart_str_appendc(str, ')');
1494 			if (ast->child[1]) {
1495 				smart_str_appends(str, " {\n");
1496 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1497 				zend_ast_export_indent(str, indent);
1498 				smart_str_appendc(str, '}');
1499 			} else {
1500 				smart_str_appendc(str, ';');
1501 			}
1502 			break;
1503 		case ZEND_AST_PROP_ELEM:
1504 			smart_str_appendc(str, '$');
1505 			/* break missing intentionally */
1506 		case ZEND_AST_CONST_ELEM:
1507 			zend_ast_export_name(str, ast->child[0], 0, indent);
1508 			APPEND_DEFAULT_VALUE(1);
1509 		case ZEND_AST_USE_TRAIT:
1510 			smart_str_appends(str, "use ");
1511 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1512 			if (ast->child[1]) {
1513 				smart_str_appends(str, " {\n");
1514 				zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
1515 				zend_ast_export_indent(str, indent);
1516 				smart_str_appends(str, "}");
1517 			} else {
1518 				smart_str_appends(str, ";");
1519 			}
1520 			break;
1521 		case ZEND_AST_TRAIT_PRECEDENCE:
1522 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1523 			smart_str_appends(str, " insteadof ");
1524 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1525 			break;
1526 		case ZEND_AST_METHOD_REFERENCE:
1527 			if (ast->child[0]) {
1528 				zend_ast_export_name(str, ast->child[0], 0, indent);
1529 				smart_str_appends(str, "::");
1530 			}
1531 			zend_ast_export_name(str, ast->child[1], 0, indent);
1532 			break;
1533 		case ZEND_AST_NAMESPACE:
1534 			smart_str_appends(str, "namespace");
1535 			if (ast->child[0]) {
1536 				smart_str_appendc(str, ' ');
1537 				zend_ast_export_name(str, ast->child[0], 0, indent);
1538 			}
1539 			if (ast->child[1]) {
1540 				smart_str_appends(str, " {\n");
1541 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1542 				zend_ast_export_indent(str, indent);
1543 				smart_str_appends(str, "}\n");
1544 			} else {
1545 				smart_str_appendc(str, ';');
1546 			}
1547 			break;
1548 		case ZEND_AST_USE_ELEM:
1549 		case ZEND_AST_TRAIT_ALIAS:
1550 			zend_ast_export_name(str, ast->child[0], 0, indent);
1551 			if (ast->attr & ZEND_ACC_PUBLIC) {
1552 				smart_str_appends(str, " as public");
1553 			} else if (ast->attr & ZEND_ACC_PROTECTED) {
1554 				smart_str_appends(str, " as protected");
1555 			} else if (ast->attr & ZEND_ACC_PRIVATE) {
1556 				smart_str_appends(str, " as private");
1557 			} else if (ast->child[1]) {
1558 				smart_str_appends(str, " as");
1559 			}
1560 			if (ast->child[1]) {
1561 				smart_str_appendc(str, ' ');
1562 				zend_ast_export_name(str, ast->child[1], 0, indent);
1563 			}
1564 			break;
1565 
1566 		/* 3 child nodes */
1567 		case ZEND_AST_METHOD_CALL:
1568 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1569 			smart_str_appends(str, "->");
1570 			zend_ast_export_var(str, ast->child[1], 0, indent);
1571 			smart_str_appendc(str, '(');
1572 			zend_ast_export_ex(str, ast->child[2], 0, indent);
1573 			smart_str_appendc(str, ')');
1574 			break;
1575 		case ZEND_AST_STATIC_CALL:
1576 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1577 			smart_str_appends(str, "::");
1578 			zend_ast_export_var(str, ast->child[1], 0, indent);
1579 			smart_str_appendc(str, '(');
1580 			zend_ast_export_ex(str, ast->child[2], 0, indent);
1581 			smart_str_appendc(str, ')');
1582 			break;
1583 		case ZEND_AST_CONDITIONAL:
1584 			if (priority > 100) smart_str_appendc(str, '(');
1585 			zend_ast_export_ex(str, ast->child[0], 100, indent);
1586 			if (ast->child[1]) {
1587 				smart_str_appends(str, " ? ");
1588 				zend_ast_export_ex(str, ast->child[1], 101, indent);
1589 				smart_str_appends(str, " : ");
1590 			} else {
1591 				smart_str_appends(str, " ?: ");
1592 			}
1593 			zend_ast_export_ex(str, ast->child[2], 101, indent);
1594 			if (priority > 100) smart_str_appendc(str, ')');
1595 			break;
1596 
1597 		case ZEND_AST_TRY:
1598 			smart_str_appends(str, "try {\n");
1599 			zend_ast_export_stmt(str, ast->child[0], indent + 1);
1600 			zend_ast_export_indent(str, indent);
1601 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1602 			if (ast->child[2]) {
1603 				smart_str_appends(str, "} finally {\n");
1604 				zend_ast_export_stmt(str, ast->child[2], indent + 1);
1605 				zend_ast_export_indent(str, indent);
1606 			}
1607 			smart_str_appendc(str, '}');
1608 			break;
1609 		case ZEND_AST_CATCH:
1610 			smart_str_appends(str, "} catch (");
1611 			zend_ast_export_catch_name_list(str, zend_ast_get_list(ast->child[0]), indent);
1612 			smart_str_appends(str, " $");
1613 			zend_ast_export_var(str, ast->child[1], 0, indent);
1614 			smart_str_appends(str, ") {\n");
1615 			zend_ast_export_stmt(str, ast->child[2], indent + 1);
1616 			zend_ast_export_indent(str, indent);
1617 			break;
1618 		case ZEND_AST_PARAM:
1619 			if (ast->child[0]) {
1620 				if (ast->child[0]->attr & ZEND_TYPE_NULLABLE) {
1621 					smart_str_appendc(str, '?');
1622 				}
1623 				zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1624 				smart_str_appendc(str, ' ');
1625 			}
1626 			if (ast->attr & ZEND_PARAM_REF) {
1627 				smart_str_appendc(str, '&');
1628 			}
1629 			if (ast->attr & ZEND_PARAM_VARIADIC) {
1630 				smart_str_appends(str, "...");
1631 			}
1632 			smart_str_appendc(str, '$');
1633 			zend_ast_export_name(str, ast->child[1], 0, indent);
1634 			APPEND_DEFAULT_VALUE(2);
1635 
1636 		/* 4 child nodes */
1637 		case ZEND_AST_FOR:
1638 			smart_str_appends(str, "for (");
1639 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1640 			smart_str_appendc(str, ';');
1641 			if (ast->child[1]) {
1642 				smart_str_appendc(str, ' ');
1643 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1644 			}
1645 			smart_str_appendc(str, ';');
1646 			if (ast->child[2]) {
1647 				smart_str_appendc(str, ' ');
1648 				zend_ast_export_ex(str, ast->child[2], 0, indent);
1649 			}
1650 			smart_str_appends(str, ") {\n");
1651 			zend_ast_export_stmt(str, ast->child[3], indent + 1);
1652 			zend_ast_export_indent(str, indent);
1653 			smart_str_appendc(str, '}');
1654 			break;
1655 		case ZEND_AST_FOREACH:
1656 			smart_str_appends(str, "foreach (");
1657 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1658 			smart_str_appends(str, " as ");
1659 			if (ast->child[2]) {
1660 				zend_ast_export_ex(str, ast->child[2], 0, indent);
1661 				smart_str_appends(str, " => ");
1662 			}
1663 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1664 			smart_str_appends(str, ") {\n");
1665 			zend_ast_export_stmt(str, ast->child[3], indent + 1);
1666 			zend_ast_export_indent(str, indent);
1667 			smart_str_appendc(str, '}');
1668 			break;
1669 		EMPTY_SWITCH_DEFAULT_CASE();
1670 	}
1671 	return;
1672 
1673 binary_op:
1674 	if (priority > p) smart_str_appendc(str, '(');
1675 	zend_ast_export_ex(str, ast->child[0], pl, indent);
1676 	smart_str_appends(str, op);
1677 	zend_ast_export_ex(str, ast->child[1], pr, indent);
1678 	if (priority > p) smart_str_appendc(str, ')');
1679 	return;
1680 
1681 prefix_op:
1682 	if (priority > p) smart_str_appendc(str, '(');
1683 	smart_str_appends(str, op);
1684 	zend_ast_export_ex(str, ast->child[0], pl, indent);
1685 	if (priority > p) smart_str_appendc(str, ')');
1686 	return;
1687 
1688 postfix_op:
1689 	if (priority > p) smart_str_appendc(str, '(');
1690 	zend_ast_export_ex(str, ast->child[0], pl, indent);
1691 	smart_str_appends(str, op);
1692 	if (priority > p) smart_str_appendc(str, ')');
1693 	return;
1694 
1695 func_op:
1696 	smart_str_appends(str, op);
1697 	smart_str_appendc(str, '(');
1698 	zend_ast_export_ex(str, ast->child[0], 0, indent);
1699 	smart_str_appendc(str, ')');
1700 	return;
1701 
1702 append_node_1:
1703 	smart_str_appends(str, op);
1704 	if (ast->child[0]) {
1705 		smart_str_appendc(str, ' ');
1706 		ast = ast->child[0];
1707 		goto tail_call;
1708 	}
1709 	return;
1710 
1711 append_str:
1712 	smart_str_appends(str, op);
1713 	return;
1714 
1715 append_default_value:
1716 	if (ast->child[p]) {
1717 		smart_str_appends(str, " = ");
1718 		ast = ast->child[p];
1719 		goto tail_call;
1720 	}
1721 	return;
1722 }
1723 
zend_ast_export(const char * prefix,zend_ast * ast,const char * suffix)1724 ZEND_API zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix)
1725 {
1726 	smart_str str = {0};
1727 
1728 	smart_str_appends(&str, prefix);
1729 	zend_ast_export_ex(&str, ast, 0, 0);
1730 	smart_str_appends(&str, suffix);
1731 	smart_str_0(&str);
1732 	return str.s;
1733 }
1734