xref: /PHP-7.2/Zend/zend_ast.c (revision 8a9df885)
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_REFCOUNTED) {
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 				zend_fetch_dimension_const(&tmp, &op1, &op2, (ast->attr == ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
436 
437 				if (UNEXPECTED(Z_ISREF(tmp))) {
438 					ZVAL_DUP(result, Z_REFVAL(tmp));
439 				} else {
440 					ZVAL_DUP(result, &tmp);
441 				}
442 				zval_ptr_dtor(&tmp);
443 				zval_dtor(&op1);
444 				zval_dtor(&op2);
445 			}
446 			break;
447 		default:
448 			zend_throw_error(NULL, "Unsupported constant expression");
449 			ret = FAILURE;
450 	}
451 	return ret;
452 }
453 
zend_ast_copy(zend_ast * ast)454 ZEND_API zend_ast *zend_ast_copy(zend_ast *ast)
455 {
456 	if (ast == NULL) {
457 		return NULL;
458 	} else if (ast->kind == ZEND_AST_ZVAL) {
459 		zend_ast_zval *new = emalloc(sizeof(zend_ast_zval));
460 		new->kind = ZEND_AST_ZVAL;
461 		new->attr = ast->attr;
462 		ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
463 		return (zend_ast *) new;
464 	} else if (zend_ast_is_list(ast)) {
465 		zend_ast_list *list = zend_ast_get_list(ast);
466 		zend_ast_list *new = emalloc(zend_ast_list_size(list->children));
467 		uint32_t i;
468 		new->kind = list->kind;
469 		new->attr = list->attr;
470 		new->children = list->children;
471 		for (i = 0; i < list->children; i++) {
472 			new->child[i] = zend_ast_copy(list->child[i]);
473 		}
474 		return (zend_ast *) new;
475 	} else {
476 		uint32_t i, children = zend_ast_get_num_children(ast);
477 		zend_ast *new = emalloc(zend_ast_size(children));
478 		new->kind = ast->kind;
479 		new->attr = ast->attr;
480 		for (i = 0; i < children; i++) {
481 			new->child[i] = zend_ast_copy(ast->child[i]);
482 		}
483 		return new;
484 	}
485 }
486 
zend_ast_destroy_ex(zend_ast * ast,zend_bool free)487 static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) {
488 	if (!ast) {
489 		return;
490 	}
491 
492 	switch (ast->kind) {
493 		case ZEND_AST_ZVAL:
494 			/* Destroy value without using GC: When opcache moves arrays into SHM it will
495 			 * free the zend_array structure, so references to it from outside the op array
496 			 * become invalid. GC would cause such a reference in the root buffer. */
497 			zval_ptr_dtor_nogc(zend_ast_get_zval(ast));
498 			break;
499 		case ZEND_AST_FUNC_DECL:
500 		case ZEND_AST_CLOSURE:
501 		case ZEND_AST_METHOD:
502 		case ZEND_AST_CLASS:
503 		{
504 			zend_ast_decl *decl = (zend_ast_decl *) ast;
505 			if (decl->name) {
506 			    zend_string_release(decl->name);
507 			}
508 			if (decl->doc_comment) {
509 				zend_string_release(decl->doc_comment);
510 			}
511 			zend_ast_destroy_ex(decl->child[0], free);
512 			zend_ast_destroy_ex(decl->child[1], free);
513 			zend_ast_destroy_ex(decl->child[2], free);
514 			zend_ast_destroy_ex(decl->child[3], free);
515 			break;
516 		}
517 		default:
518 			if (zend_ast_is_list(ast)) {
519 				zend_ast_list *list = zend_ast_get_list(ast);
520 				uint32_t i;
521 				for (i = 0; i < list->children; i++) {
522 					zend_ast_destroy_ex(list->child[i], free);
523 				}
524 			} else {
525 				uint32_t i, children = zend_ast_get_num_children(ast);
526 				for (i = 0; i < children; i++) {
527 					zend_ast_destroy_ex(ast->child[i], free);
528 				}
529 			}
530 	}
531 
532 	if (free) {
533 		efree(ast);
534 	}
535 }
536 
zend_ast_destroy(zend_ast * ast)537 ZEND_API void zend_ast_destroy(zend_ast *ast) {
538 	zend_ast_destroy_ex(ast, 0);
539 }
zend_ast_destroy_and_free(zend_ast * ast)540 ZEND_API void zend_ast_destroy_and_free(zend_ast *ast) {
541 	zend_ast_destroy_ex(ast, 1);
542 }
543 
zend_ast_apply(zend_ast * ast,zend_ast_apply_func fn)544 ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn) {
545 	if (zend_ast_is_list(ast)) {
546 		zend_ast_list *list = zend_ast_get_list(ast);
547 		uint32_t i;
548 		for (i = 0; i < list->children; ++i) {
549 			fn(&list->child[i]);
550 		}
551 	} else {
552 		uint32_t i, children = zend_ast_get_num_children(ast);
553 		for (i = 0; i < children; ++i) {
554 			fn(&ast->child[i]);
555 		}
556 	}
557 }
558 
559 /*
560  * Operator Precendence
561  * ====================
562  * priority  associativity  operators
563  * ----------------------------------
564  *   10     left            include, include_once, eval, require, require_once
565  *   20     left            ,
566  *   30     left            or
567  *   40     left            xor
568  *   50     left            and
569  *   60     right           print
570  *   70     right           yield
571  *   80     right           =>
572  *   85     right           yield from
573  *   90     right           = += -= *= /= .= %= &= |= ^= <<= >>= **=
574  *  100     left            ? :
575  *  110     right           ??
576  *  120     left            ||
577  *  130     left            &&
578  *  140     left            |
579  *  150     left            ^
580  *  160     left            &
581  *  170     non-associative == != === !==
582  *  180     non-associative < <= > >= <=>
583  *  190     left            << >>
584  *  200     left            + - .
585  *  210     left            * / %
586  *  220     right           !
587  *  230     non-associative instanceof
588  *  240     right           + - ++ -- ~ (type) @
589  *  250     right           **
590  *  260     left            [
591  *  270     non-associative clone new
592  */
593 
594 static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent);
595 
zend_ast_export_str(smart_str * str,zend_string * s)596 static void zend_ast_export_str(smart_str *str, zend_string *s)
597 {
598 	size_t i;
599 
600 	for (i = 0; i < ZSTR_LEN(s); i++) {
601 		unsigned char c = ZSTR_VAL(s)[i];
602 		if (c == '\'' || c == '\\') {
603 			smart_str_appendc(str, '\\');
604 			smart_str_appendc(str, c);
605 		} else {
606 			smart_str_appendc(str, c);
607 		}
608 	}
609 }
610 
zend_ast_export_qstr(smart_str * str,char quote,zend_string * s)611 static void zend_ast_export_qstr(smart_str *str, char quote, zend_string *s)
612 {
613 	size_t i;
614 
615 	for (i = 0; i < ZSTR_LEN(s); i++) {
616 		unsigned char c = ZSTR_VAL(s)[i];
617 		if (c < ' ') {
618 			switch (c) {
619 				case '\n':
620 					smart_str_appends(str, "\\n");
621 					break;
622 				case '\r':
623 					smart_str_appends(str, "\\r");
624 					break;
625 				case '\t':
626 					smart_str_appends(str, "\\t");
627 					break;
628 				case '\f':
629 					smart_str_appends(str, "\\f");
630 					break;
631 				case '\v':
632 					smart_str_appends(str, "\\v");
633 					break;
634 #ifdef ZEND_WIN32
635 				case VK_ESCAPE:
636 #else
637 				case '\e':
638 #endif
639 					smart_str_appends(str, "\\e");
640 					break;
641 				default:
642 					smart_str_appends(str, "\\0");
643 					smart_str_appendc(str, '0' + (c / 8));
644 					smart_str_appendc(str, '0' + (c % 8));
645 					break;
646 			}
647 		} else {
648 			if (c == quote || c == '$' || c == '\\') {
649 				smart_str_appendc(str, '\\');
650 			}
651 			smart_str_appendc(str, c);
652 		}
653 	}
654 }
655 
zend_ast_export_indent(smart_str * str,int indent)656 static void zend_ast_export_indent(smart_str *str, int indent)
657 {
658 	while (indent > 0) {
659 		smart_str_appends(str, "    ");
660 		indent--;
661 	}
662 }
663 
zend_ast_export_name(smart_str * str,zend_ast * ast,int priority,int indent)664 static void zend_ast_export_name(smart_str *str, zend_ast *ast, int priority, int indent)
665 {
666 	if (ast->kind == ZEND_AST_ZVAL) {
667 		zval *zv = zend_ast_get_zval(ast);
668 
669 		if (Z_TYPE_P(zv) == IS_STRING) {
670 			smart_str_append(str, Z_STR_P(zv));
671 			return;
672 		}
673 	}
674 	zend_ast_export_ex(str, ast, priority, indent);
675 }
676 
zend_ast_export_ns_name(smart_str * str,zend_ast * ast,int priority,int indent)677 static void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int priority, int indent)
678 {
679 	if (ast->kind == ZEND_AST_ZVAL) {
680 		zval *zv = zend_ast_get_zval(ast);
681 
682 		if (Z_TYPE_P(zv) == IS_STRING) {
683 		    if (ast->attr == ZEND_NAME_FQ) {
684 				smart_str_appendc(str, '\\');
685 		    } else if (ast->attr == ZEND_NAME_RELATIVE) {
686 				smart_str_appends(str, "namespace\\");
687 		    }
688 			smart_str_append(str, Z_STR_P(zv));
689 			return;
690 		}
691 	}
692 	zend_ast_export_ex(str, ast, priority, indent);
693 }
694 
zend_ast_valid_var_char(char ch)695 static int zend_ast_valid_var_char(char ch)
696 {
697 	unsigned char c = (unsigned char)ch;
698 
699 	if (c != '_' && c < 127 &&
700 	    (c < '0' || c > '9') &&
701 	    (c < 'A' || c > 'Z') &&
702 	    (c < 'a' || c > 'z')) {
703 		return 0;
704 	}
705 	return 1;
706 }
707 
zend_ast_valid_var_name(const char * s,size_t len)708 static int zend_ast_valid_var_name(const char *s, size_t len)
709 {
710 	unsigned char c;
711 	size_t i;
712 
713 	if (len == 0) {
714 		return 0;
715 	}
716 	c = (unsigned char)s[0];
717 	if (c != '_' && c < 127 &&
718 	    (c < 'A' || c > 'Z') &&
719 	    (c < 'a' || c > 'z')) {
720 		return 0;
721 	}
722 	for (i = 1; i < len; i++) {
723 		c = (unsigned char)s[i];
724 		if (c != '_' && c < 127 &&
725 		    (c < '0' || c > '9') &&
726 		    (c < 'A' || c > 'Z') &&
727 		    (c < 'a' || c > 'z')) {
728 			return 0;
729 		}
730 	}
731 	return 1;
732 }
733 
zend_ast_var_needs_braces(char ch)734 static ZEND_COLD int zend_ast_var_needs_braces(char ch)
735 {
736 	return ch == '[' || zend_ast_valid_var_char(ch);
737 }
738 
zend_ast_export_var(smart_str * str,zend_ast * ast,int priority,int indent)739 static void zend_ast_export_var(smart_str *str, zend_ast *ast, int priority, int indent)
740 {
741 	if (ast->kind == ZEND_AST_ZVAL) {
742 		zval *zv = zend_ast_get_zval(ast);
743 		if (Z_TYPE_P(zv) == IS_STRING &&
744 		    zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) {
745 			smart_str_append(str, Z_STR_P(zv));
746 			return;
747 		}
748 	} else if (ast->kind == ZEND_AST_VAR) {
749 		zend_ast_export_ex(str, ast, 0, indent);
750 		return;
751 	}
752 	smart_str_appendc(str, '{');
753 	zend_ast_export_name(str, ast, 0, indent);
754 	smart_str_appendc(str, '}');
755 }
756 
zend_ast_export_list(smart_str * str,zend_ast_list * list,int separator,int priority,int indent)757 static void zend_ast_export_list(smart_str *str, zend_ast_list *list, int separator, int priority, int indent)
758 {
759 	uint32_t i = 0;
760 
761 	while (i < list->children) {
762 		if (i != 0 && separator) {
763 			smart_str_appends(str, ", ");
764 		}
765 		zend_ast_export_ex(str, list->child[i], priority, indent);
766 		i++;
767 	}
768 }
769 
zend_ast_export_encaps_list(smart_str * str,char quote,zend_ast_list * list,int indent)770 static void zend_ast_export_encaps_list(smart_str *str, char quote, zend_ast_list *list, int indent)
771 {
772 	uint32_t i = 0;
773 	zend_ast *ast;
774 
775 	while (i < list->children) {
776 		ast = list->child[i];
777 		if (ast->kind == ZEND_AST_ZVAL) {
778 			zval *zv = zend_ast_get_zval(ast);
779 
780 			ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
781 			zend_ast_export_qstr(str, quote, Z_STR_P(zv));
782 		} else if (ast->kind == ZEND_AST_VAR &&
783 		           ast->child[0]->kind == ZEND_AST_ZVAL &&
784 		           (i + 1 == list->children ||
785 		            list->child[i + 1]->kind != ZEND_AST_ZVAL ||
786 		            !zend_ast_var_needs_braces(
787 		                *Z_STRVAL_P(
788 		                    zend_ast_get_zval(list->child[i + 1]))))) {
789 			zend_ast_export_ex(str, ast, 0, indent);
790 		} else {
791 			smart_str_appendc(str, '{');
792 			zend_ast_export_ex(str, ast, 0, indent);
793 			smart_str_appendc(str, '}');
794 		}
795 		i++;
796 	}
797 }
798 
zend_ast_export_name_list_ex(smart_str * str,zend_ast_list * list,int indent,const char * separator)799 static void zend_ast_export_name_list_ex(smart_str *str, zend_ast_list *list, int indent, const char *separator)
800 {
801 	uint32_t i = 0;
802 
803 	while (i < list->children) {
804 		if (i != 0) {
805 			smart_str_appends(str, separator);
806 		}
807 		zend_ast_export_name(str, list->child[i], 0, indent);
808 		i++;
809 	}
810 }
811 
812 #define zend_ast_export_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, ", ")
813 #define zend_ast_export_catch_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, "|")
814 
zend_ast_export_var_list(smart_str * str,zend_ast_list * list,int indent)815 static void zend_ast_export_var_list(smart_str *str, zend_ast_list *list, int indent)
816 {
817 	uint32_t i = 0;
818 
819 	while (i < list->children) {
820 		if (i != 0) {
821 			smart_str_appends(str, ", ");
822 		}
823 		if (list->child[i]->attr) {
824 			smart_str_appendc(str, '&');
825 		}
826 		smart_str_appendc(str, '$');
827 		zend_ast_export_name(str, list->child[i], 20, indent);
828 		i++;
829 	}
830 }
831 
zend_ast_export_stmt(smart_str * str,zend_ast * ast,int indent)832 static void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int indent)
833 {
834 	if (!ast) {
835 		return;
836 	}
837 
838 	if (ast->kind == ZEND_AST_STMT_LIST ||
839 	    ast->kind == ZEND_AST_TRAIT_ADAPTATIONS) {
840 		zend_ast_list *list = (zend_ast_list*)ast;
841 		uint32_t i = 0;
842 
843 		while (i < list->children) {
844 			ast = list->child[i];
845 			zend_ast_export_stmt(str, ast, indent);
846 			i++;
847 		}
848 	} else {
849 		zend_ast_export_indent(str, indent);
850 		zend_ast_export_ex(str, ast, 0, indent);
851 		switch (ast->kind) {
852 			case ZEND_AST_LABEL:
853 			case ZEND_AST_IF:
854 			case ZEND_AST_SWITCH:
855 			case ZEND_AST_WHILE:
856 			case ZEND_AST_TRY:
857 			case ZEND_AST_FOR:
858 			case ZEND_AST_FOREACH:
859 			case ZEND_AST_FUNC_DECL:
860 			case ZEND_AST_METHOD:
861 			case ZEND_AST_CLASS:
862 			case ZEND_AST_USE_TRAIT:
863 			case ZEND_AST_NAMESPACE:
864 			case ZEND_AST_DECLARE:
865 				break;
866 			default:
867 				smart_str_appendc(str, ';');
868 				break;
869 		}
870 		smart_str_appendc(str, '\n');
871 	}
872 }
873 
zend_ast_export_if_stmt(smart_str * str,zend_ast_list * list,int indent)874 static void zend_ast_export_if_stmt(smart_str *str, zend_ast_list *list, int indent)
875 {
876 	uint32_t i;
877 	zend_ast *ast;
878 
879 tail_call:
880 	i = 0;
881 	while (i < list->children) {
882 		ast = list->child[i];
883 		ZEND_ASSERT(ast->kind == ZEND_AST_IF_ELEM);
884 		if (ast->child[0]) {
885 			if (i == 0) {
886 				smart_str_appends(str, "if (");
887 			} else {
888 				zend_ast_export_indent(str, indent);
889 				smart_str_appends(str, "} elseif (");
890 			}
891 			zend_ast_export_ex(str, ast->child[0], 0, indent);
892 			smart_str_appends(str, ") {\n");
893 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
894 		} else {
895 			zend_ast_export_indent(str, indent);
896 			smart_str_appends(str, "} else ");
897 			if (ast->child[1] && ast->child[1]->kind == ZEND_AST_IF) {
898 				list = (zend_ast_list*)ast->child[1];
899 				goto tail_call;
900 			} else {
901 				smart_str_appends(str, "{\n");
902 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
903 			}
904 		}
905 		i++;
906 	}
907 	zend_ast_export_indent(str, indent);
908 	smart_str_appendc(str, '}');
909 }
910 
zend_ast_export_zval(smart_str * str,zval * zv,int priority,int indent)911 static void zend_ast_export_zval(smart_str *str, zval *zv, int priority, int indent)
912 {
913 	zend_long idx;
914 	zend_string *key;
915 	zval *val;
916 	int first;
917 
918 	ZVAL_DEREF(zv);
919 	switch (Z_TYPE_P(zv)) {
920 		case IS_NULL:
921 			smart_str_appends(str, "null");
922 			break;
923 		case IS_FALSE:
924 			smart_str_appends(str, "false");
925 			break;
926 		case IS_TRUE:
927 			smart_str_appends(str, "true");
928 			break;
929 		case IS_LONG:
930 			smart_str_append_long(str, Z_LVAL_P(zv));
931 			break;
932 		case IS_DOUBLE:
933 			key = zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(zv));
934 			smart_str_appendl(str, ZSTR_VAL(key), ZSTR_LEN(key));
935 			zend_string_release(key);
936 			break;
937 		case IS_STRING:
938 			smart_str_appendc(str, '\'');
939 			zend_ast_export_str(str, Z_STR_P(zv));
940 			smart_str_appendc(str, '\'');
941 			break;
942 		case IS_ARRAY:
943 			smart_str_appendc(str, '[');
944 			first = 1;
945 			ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zv), idx, key, val) {
946 				if (first) {
947 					first = 0;
948 				} else {
949 					smart_str_appends(str, ", ");
950 				}
951 				if (key) {
952 					smart_str_appendc(str, '\'');
953 					zend_ast_export_str(str, key);
954 					smart_str_appends(str, "' => ");
955 				} else {
956 					smart_str_append_long(str, idx);
957 					smart_str_appends(str, " => ");
958 				}
959 				zend_ast_export_zval(str, val, 0, indent);
960 			} ZEND_HASH_FOREACH_END();
961 			smart_str_appendc(str, ']');
962 			break;
963 		case IS_CONSTANT:
964 			smart_str_appendl(str, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
965 			break;
966 		case IS_CONSTANT_AST:
967 			zend_ast_export_ex(str, Z_ASTVAL_P(zv), priority, indent);
968 			break;
969 		EMPTY_SWITCH_DEFAULT_CASE();
970 	}
971 }
972 
zend_ast_export_class_no_header(smart_str * str,zend_ast_decl * decl,int indent)973 static void zend_ast_export_class_no_header(smart_str *str, zend_ast_decl *decl, int indent) {
974 	if (decl->child[0]) {
975 		smart_str_appends(str, " extends ");
976 		zend_ast_export_ns_name(str, decl->child[0], 0, indent);
977 	}
978 	if (decl->child[1]) {
979 		smart_str_appends(str, " implements ");
980 		zend_ast_export_ex(str, decl->child[1], 0, indent);
981 	}
982 	smart_str_appends(str, " {\n");
983 	zend_ast_export_stmt(str, decl->child[2], indent + 1);
984 	zend_ast_export_indent(str, indent);
985 	smart_str_appends(str, "}");
986 }
987 
988 #define BINARY_OP(_op, _p, _pl, _pr) do { \
989 		op = _op; \
990 		p = _p; \
991 		pl = _pl; \
992 		pr = _pr; \
993 		goto binary_op; \
994 	} while (0)
995 
996 #define PREFIX_OP(_op, _p, _pl) do { \
997 		op = _op; \
998 		p = _p; \
999 		pl = _pl; \
1000 		goto prefix_op; \
1001 	} while (0)
1002 
1003 #define FUNC_OP(_op) do { \
1004 		op = _op; \
1005 		goto func_op; \
1006 	} while (0)
1007 
1008 #define POSTFIX_OP(_op, _p, _pl) do { \
1009 		op = _op; \
1010 		p = _p; \
1011 		pl = _pl; \
1012 		goto postfix_op; \
1013 	} while (0)
1014 
1015 #define APPEND_NODE_1(_op) do { \
1016 		op = _op; \
1017 		goto append_node_1; \
1018 	} while (0)
1019 
1020 #define APPEND_STR(_op) do { \
1021 		op = _op; \
1022 		goto append_str; \
1023 	} while (0)
1024 
1025 #define APPEND_DEFAULT_VALUE(n) do { \
1026 		p = n; \
1027 		goto append_default_value; \
1028 	} while (0)
1029 
zend_ast_export_ex(smart_str * str,zend_ast * ast,int priority,int indent)1030 static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent)
1031 {
1032 	zend_ast_decl *decl;
1033 	int p, pl, pr;
1034 	const char *op;
1035 
1036 tail_call:
1037 	if (!ast) {
1038 		return;
1039 	}
1040 	switch (ast->kind) {
1041 		/* special nodes */
1042 		case ZEND_AST_ZVAL:
1043 			zend_ast_export_zval(str, zend_ast_get_zval(ast), priority, indent);
1044 			break;
1045 		case ZEND_AST_ZNODE:
1046 			/* This AST kind is only used for temporary nodes during compilation */
1047 			ZEND_ASSERT(0);
1048 			break;
1049 
1050 		/* declaration nodes */
1051 		case ZEND_AST_FUNC_DECL:
1052 		case ZEND_AST_CLOSURE:
1053 		case ZEND_AST_METHOD:
1054 			decl = (zend_ast_decl *) ast;
1055 			if (decl->flags & ZEND_ACC_PUBLIC) {
1056 				smart_str_appends(str, "public ");
1057 			} else if (decl->flags & ZEND_ACC_PROTECTED) {
1058 				smart_str_appends(str, "protected ");
1059 			} else if (decl->flags & ZEND_ACC_PRIVATE) {
1060 				smart_str_appends(str, "private ");
1061 			}
1062 			if (decl->flags & ZEND_ACC_STATIC) {
1063 				smart_str_appends(str, "static ");
1064 			}
1065 			if (decl->flags & ZEND_ACC_ABSTRACT) {
1066 				smart_str_appends(str, "abstract ");
1067 			}
1068 			if (decl->flags & ZEND_ACC_FINAL) {
1069 				smart_str_appends(str, "final ");
1070 			}
1071 			smart_str_appends(str, "function ");
1072 			if (decl->flags & ZEND_ACC_RETURN_REFERENCE) {
1073 				smart_str_appendc(str, '&');
1074 			}
1075 			if (ast->kind != ZEND_AST_CLOSURE) {
1076 				smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
1077 			}
1078 			smart_str_appendc(str, '(');
1079 			zend_ast_export_ex(str, decl->child[0], 0, indent);
1080 			smart_str_appendc(str, ')');
1081 			zend_ast_export_ex(str, decl->child[1], 0, indent);
1082 			if (decl->child[3]) {
1083 				smart_str_appends(str, ": ");
1084 				if (decl->child[3]->attr & ZEND_TYPE_NULLABLE) {
1085 					smart_str_appendc(str, '?');
1086 				}
1087 				zend_ast_export_ns_name(str, decl->child[3], 0, indent);
1088 			}
1089 			if (decl->child[2]) {
1090 				smart_str_appends(str, " {\n");
1091 				zend_ast_export_stmt(str, decl->child[2], indent + 1);
1092 				zend_ast_export_indent(str, indent);
1093 				smart_str_appendc(str, '}');
1094 				if (ast->kind != ZEND_AST_CLOSURE) {
1095 					smart_str_appendc(str, '\n');
1096 				}
1097 			} else {
1098 				smart_str_appends(str, ";\n");
1099 			}
1100 			break;
1101 		case ZEND_AST_CLASS:
1102 			decl = (zend_ast_decl *) ast;
1103 			if (decl->flags & ZEND_ACC_INTERFACE) {
1104 				smart_str_appends(str, "interface ");
1105 			} else if (decl->flags & ZEND_ACC_TRAIT) {
1106 				smart_str_appends(str, "trait ");
1107 			} else {
1108 				if (decl->flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
1109 					smart_str_appends(str, "abstract ");
1110 				}
1111 				if (decl->flags & ZEND_ACC_FINAL) {
1112 					smart_str_appends(str, "final ");
1113 				}
1114 				smart_str_appends(str, "class ");
1115 			}
1116 			smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
1117 			zend_ast_export_class_no_header(str, decl, indent);
1118 			smart_str_appendc(str, '\n');
1119 			break;
1120 
1121 		/* list nodes */
1122 		case ZEND_AST_ARG_LIST:
1123 		case ZEND_AST_EXPR_LIST:
1124 		case ZEND_AST_PARAM_LIST:
1125 simple_list:
1126 			zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1127 			break;
1128 		case ZEND_AST_ARRAY:
1129 			smart_str_appendc(str, '[');
1130 			zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1131 			smart_str_appendc(str, ']');
1132 			break;
1133 		case ZEND_AST_ENCAPS_LIST:
1134 			smart_str_appendc(str, '"');
1135 			zend_ast_export_encaps_list(str, '"', (zend_ast_list*)ast, indent);
1136 			smart_str_appendc(str, '"');
1137 			break;
1138 		case ZEND_AST_STMT_LIST:
1139 		case ZEND_AST_TRAIT_ADAPTATIONS:
1140 			zend_ast_export_stmt(str, ast, indent);
1141 			break;
1142 		case ZEND_AST_IF:
1143 			zend_ast_export_if_stmt(str, (zend_ast_list*)ast, indent);
1144 			break;
1145 		case ZEND_AST_SWITCH_LIST:
1146 		case ZEND_AST_CATCH_LIST:
1147 			zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
1148 			break;
1149 		case ZEND_AST_CLOSURE_USES:
1150 			smart_str_appends(str, " use(");
1151 			zend_ast_export_var_list(str, (zend_ast_list*)ast, indent);
1152 			smart_str_appendc(str, ')');
1153 			break;
1154 		case ZEND_AST_PROP_DECL:
1155 			if (ast->attr & ZEND_ACC_PUBLIC) {
1156 				smart_str_appends(str, "public ");
1157 			} else if (ast->attr & ZEND_ACC_PROTECTED) {
1158 				smart_str_appends(str, "protected ");
1159 			} else if (ast->attr & ZEND_ACC_PRIVATE) {
1160 				smart_str_appends(str, "private ");
1161 			}
1162 			if (ast->attr & ZEND_ACC_STATIC) {
1163 				smart_str_appends(str, "static ");
1164 			}
1165 			goto simple_list;
1166 		case ZEND_AST_CONST_DECL:
1167 		case ZEND_AST_CLASS_CONST_DECL:
1168 			smart_str_appends(str, "const ");
1169 			goto simple_list;
1170 		case ZEND_AST_NAME_LIST:
1171 			zend_ast_export_name_list(str, (zend_ast_list*)ast, indent);
1172 			break;
1173 		case ZEND_AST_USE:
1174 			smart_str_appends(str, "use ");
1175 			if (ast->attr == T_FUNCTION) {
1176 				smart_str_appends(str, "function ");
1177 			} else if (ast->attr == T_CONST) {
1178 				smart_str_appends(str, "const ");
1179 			}
1180 			goto simple_list;
1181 
1182 		/* 0 child nodes */
1183 		case ZEND_AST_MAGIC_CONST:
1184 			switch (ast->attr) {
1185 				case T_LINE:     APPEND_STR("__LINE__");
1186 				case T_FILE:     APPEND_STR("__FILE__");
1187 				case T_DIR:      APPEND_STR("__DIR__");
1188 				case T_TRAIT_C:  APPEND_STR("__TRAIT__");
1189 				case T_METHOD_C: APPEND_STR("__METHOD__");
1190 				case T_FUNC_C:   APPEND_STR("__FUNCTION__");
1191 				case T_NS_C:     APPEND_STR("__NAMESPACE__");
1192 				case T_CLASS_C:  APPEND_STR("__CLASS__");
1193 				EMPTY_SWITCH_DEFAULT_CASE();
1194 			}
1195 			break;
1196 		case ZEND_AST_TYPE:
1197 			switch (ast->attr) {
1198 				case IS_ARRAY:    APPEND_STR("array");
1199 				case IS_CALLABLE: APPEND_STR("callable");
1200 				EMPTY_SWITCH_DEFAULT_CASE();
1201 			}
1202 			break;
1203 
1204 		/* 1 child node */
1205 		case ZEND_AST_VAR:
1206 			smart_str_appendc(str, '$');
1207 			zend_ast_export_var(str, ast->child[0], 0, indent);
1208 			break;
1209 		case ZEND_AST_CONST:
1210 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1211 			break;
1212 		case ZEND_AST_UNPACK:
1213 			smart_str_appends(str, "...");
1214 			ast = ast->child[0];
1215 			goto tail_call;
1216 		case ZEND_AST_UNARY_PLUS:  PREFIX_OP("+", 240, 241);
1217 		case ZEND_AST_UNARY_MINUS: PREFIX_OP("-", 240, 241);
1218 		case ZEND_AST_CAST:
1219 			switch (ast->attr) {
1220 				case IS_NULL:      PREFIX_OP("(unset)",  240, 241);
1221 				case _IS_BOOL:     PREFIX_OP("(bool)",   240, 241);
1222 				case IS_LONG:      PREFIX_OP("(int)",    240, 241);
1223 				case IS_DOUBLE:    PREFIX_OP("(double)", 240, 241);
1224 				case IS_STRING:    PREFIX_OP("(string)", 240, 241);
1225 				case IS_ARRAY:     PREFIX_OP("(array)",  240, 241);
1226 				case IS_OBJECT:    PREFIX_OP("(object)", 240, 241);
1227 				EMPTY_SWITCH_DEFAULT_CASE();
1228 			}
1229 			break;
1230 		case ZEND_AST_EMPTY:
1231 			FUNC_OP("empty");
1232 		case ZEND_AST_ISSET:
1233 			FUNC_OP("isset");
1234 		case ZEND_AST_SILENCE:
1235 			PREFIX_OP("@", 240, 241);
1236 		case ZEND_AST_SHELL_EXEC:
1237 			smart_str_appendc(str, '`');
1238 			if (ast->child[0]->kind == ZEND_AST_ENCAPS_LIST) {
1239 				zend_ast_export_encaps_list(str, '`', (zend_ast_list*)ast->child[0], indent);
1240 			} else {
1241 				zval *zv;
1242 				ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_ZVAL);
1243 				zv = zend_ast_get_zval(ast->child[0]);
1244 				ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
1245 				zend_ast_export_qstr(str, '`', Z_STR_P(zv));
1246 			}
1247 			smart_str_appendc(str, '`');
1248 			break;
1249 		case ZEND_AST_CLONE:
1250 			PREFIX_OP("clone ", 270, 271);
1251 		case ZEND_AST_EXIT:
1252 			if (ast->child[0]) {
1253 				FUNC_OP("exit");
1254 			} else {
1255 				APPEND_STR("exit");
1256 			}
1257 			break;
1258 		case ZEND_AST_PRINT:
1259 			PREFIX_OP("print ", 60, 61);
1260 		case ZEND_AST_INCLUDE_OR_EVAL:
1261 			switch (ast->attr) {
1262 				case ZEND_INCLUDE_ONCE: FUNC_OP("include_once");
1263 				case ZEND_INCLUDE:      FUNC_OP("include");
1264 				case ZEND_REQUIRE_ONCE: FUNC_OP("require_once");
1265 				case ZEND_REQUIRE:      FUNC_OP("require");
1266 				case ZEND_EVAL:         FUNC_OP("eval");
1267 				EMPTY_SWITCH_DEFAULT_CASE();
1268 			}
1269 			break;
1270 		case ZEND_AST_UNARY_OP:
1271 			switch (ast->attr) {
1272 				case ZEND_BW_NOT:   PREFIX_OP("~", 240, 241);
1273 				case ZEND_BOOL_NOT: PREFIX_OP("!", 240, 241);
1274 				EMPTY_SWITCH_DEFAULT_CASE();
1275 			}
1276 			break;
1277 		case ZEND_AST_PRE_INC:
1278 			PREFIX_OP("++", 240, 241);
1279 		case ZEND_AST_PRE_DEC:
1280 			PREFIX_OP("--", 240, 241);
1281 		case ZEND_AST_POST_INC:
1282 			POSTFIX_OP("++", 240, 241);
1283 		case ZEND_AST_POST_DEC:
1284 			POSTFIX_OP("--", 240, 241);
1285 
1286 		case ZEND_AST_GLOBAL:
1287 			APPEND_NODE_1("global");
1288 		case ZEND_AST_UNSET:
1289 			FUNC_OP("unset");
1290 		case ZEND_AST_RETURN:
1291 			APPEND_NODE_1("return");
1292 		case ZEND_AST_LABEL:
1293 			zend_ast_export_name(str, ast->child[0], 0, indent);
1294 			smart_str_appendc(str, ':');
1295 			break;
1296 		case ZEND_AST_REF:
1297 			smart_str_appendc(str, '&');
1298 			ast = ast->child[0];
1299 			goto tail_call;
1300 		case ZEND_AST_HALT_COMPILER:
1301 			APPEND_STR("__HALT_COMPILER()");
1302 		case ZEND_AST_ECHO:
1303 			APPEND_NODE_1("echo");
1304 		case ZEND_AST_THROW:
1305 			APPEND_NODE_1("throw");
1306 		case ZEND_AST_GOTO:
1307 			smart_str_appends(str, "goto ");
1308 			zend_ast_export_name(str, ast->child[0], 0, indent);
1309 			break;
1310 		case ZEND_AST_BREAK:
1311 			APPEND_NODE_1("break");
1312 		case ZEND_AST_CONTINUE:
1313 			APPEND_NODE_1("continue");
1314 
1315 		/* 2 child nodes */
1316 		case ZEND_AST_DIM:
1317 			zend_ast_export_ex(str, ast->child[0], 260, indent);
1318 			smart_str_appendc(str, '[');
1319 			if (ast->child[1]) {
1320 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1321 			}
1322 			smart_str_appendc(str, ']');
1323 			break;
1324 		case ZEND_AST_PROP:
1325 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1326 			smart_str_appends(str, "->");
1327 			zend_ast_export_var(str, ast->child[1], 0, indent);
1328 			break;
1329 		case ZEND_AST_STATIC_PROP:
1330 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1331 			smart_str_appends(str, "::$");
1332 			zend_ast_export_var(str, ast->child[1], 0, indent);
1333 			break;
1334 		case ZEND_AST_CALL:
1335 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1336 			smart_str_appendc(str, '(');
1337 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1338 			smart_str_appendc(str, ')');
1339 			break;
1340 		case ZEND_AST_CLASS_CONST:
1341 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1342 			smart_str_appends(str, "::");
1343 			zend_ast_export_name(str, ast->child[1], 0, indent);
1344 			break;
1345 		case ZEND_AST_ASSIGN:            BINARY_OP(" = ",   90, 91, 90);
1346 		case ZEND_AST_ASSIGN_REF:        BINARY_OP(" =& ",  90, 91, 90);
1347 		case ZEND_AST_ASSIGN_OP:
1348 			switch (ast->attr) {
1349 				case ZEND_ASSIGN_ADD:    BINARY_OP(" += ",  90, 91, 90);
1350 				case ZEND_ASSIGN_SUB:    BINARY_OP(" -= ",  90, 91, 90);
1351 				case ZEND_ASSIGN_MUL:    BINARY_OP(" *= ",  90, 91, 90);
1352 				case ZEND_ASSIGN_DIV:    BINARY_OP(" /= ",  90, 91, 90);
1353 				case ZEND_ASSIGN_MOD:    BINARY_OP(" %= ",  90, 91, 90);
1354 				case ZEND_ASSIGN_SL:     BINARY_OP(" <<= ", 90, 91, 90);
1355 				case ZEND_ASSIGN_SR:     BINARY_OP(" >>= ", 90, 91, 90);
1356 				case ZEND_ASSIGN_CONCAT: BINARY_OP(" .= ",  90, 91, 90);
1357 				case ZEND_ASSIGN_BW_OR:  BINARY_OP(" |= ",  90, 91, 90);
1358 				case ZEND_ASSIGN_BW_AND: BINARY_OP(" &= ",  90, 91, 90);
1359 				case ZEND_ASSIGN_BW_XOR: BINARY_OP(" ^= ",  90, 91, 90);
1360 				case ZEND_ASSIGN_POW:    BINARY_OP(" **= ", 90, 91, 90);
1361 				EMPTY_SWITCH_DEFAULT_CASE();
1362 			}
1363 			break;
1364 		case ZEND_AST_BINARY_OP:
1365 			switch (ast->attr) {
1366 				case ZEND_ADD:                 BINARY_OP(" + ",   200, 200, 201);
1367 				case ZEND_SUB:                 BINARY_OP(" - ",   200, 200, 201);
1368 				case ZEND_MUL:                 BINARY_OP(" * ",   210, 210, 211);
1369 				case ZEND_DIV:                 BINARY_OP(" / ",   210, 210, 211);
1370 				case ZEND_MOD:                 BINARY_OP(" % ",   210, 210, 211);
1371 				case ZEND_SL:                  BINARY_OP(" << ",  190, 190, 191);
1372 				case ZEND_SR:                  BINARY_OP(" >> ",  190, 190, 191);
1373 				case ZEND_CONCAT:              BINARY_OP(" . ",   200, 200, 201);
1374 				case ZEND_BW_OR:               BINARY_OP(" | ",   140, 140, 141);
1375 				case ZEND_BW_AND:              BINARY_OP(" & ",   160, 160, 161);
1376 				case ZEND_BW_XOR:              BINARY_OP(" ^ ",   150, 150, 151);
1377 				case ZEND_IS_IDENTICAL:        BINARY_OP(" === ", 170, 171, 171);
1378 				case ZEND_IS_NOT_IDENTICAL:    BINARY_OP(" !== ", 170, 171, 171);
1379 				case ZEND_IS_EQUAL:            BINARY_OP(" == ",  170, 171, 171);
1380 				case ZEND_IS_NOT_EQUAL:        BINARY_OP(" != ",  170, 171, 171);
1381 				case ZEND_IS_SMALLER:          BINARY_OP(" < ",   180, 181, 181);
1382 				case ZEND_IS_SMALLER_OR_EQUAL: BINARY_OP(" <= ",  180, 181, 181);
1383 				case ZEND_POW:                 BINARY_OP(" ** ",  250, 251, 250);
1384 				case ZEND_BOOL_XOR:            BINARY_OP(" xor ",  40,  40,  41);
1385 				case ZEND_SPACESHIP:           BINARY_OP(" <=> ", 180, 181, 181);
1386 				EMPTY_SWITCH_DEFAULT_CASE();
1387 			}
1388 			break;
1389 		case ZEND_AST_GREATER:                 BINARY_OP(" > ",   180, 181, 181);
1390 		case ZEND_AST_GREATER_EQUAL:           BINARY_OP(" >= ",  180, 181, 181);
1391 		case ZEND_AST_AND:                     BINARY_OP(" && ",  130, 130, 131);
1392 		case ZEND_AST_OR:                      BINARY_OP(" || ",  120, 120, 121);
1393 		case ZEND_AST_ARRAY_ELEM:
1394 			if (ast->child[1]) {
1395 				zend_ast_export_ex(str, ast->child[1], 80, indent);
1396 				smart_str_appends(str, " => ");
1397 			}
1398 			if (ast->attr)
1399 				smart_str_appendc(str, '&');
1400 			zend_ast_export_ex(str, ast->child[0], 80, indent);
1401 			break;
1402 		case ZEND_AST_NEW:
1403 			smart_str_appends(str, "new ");
1404 			if (ast->child[0]->kind == ZEND_AST_CLASS) {
1405 				smart_str_appends(str, "class");
1406 				if (zend_ast_get_list(ast->child[1])->children) {
1407 					smart_str_appendc(str, '(');
1408 					zend_ast_export_ex(str, ast->child[1], 0, indent);
1409 					smart_str_appendc(str, ')');
1410 				}
1411 				zend_ast_export_class_no_header(str, (zend_ast_decl *) ast->child[0], indent);
1412 			} else {
1413 				zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1414 				smart_str_appendc(str, '(');
1415 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1416 				smart_str_appendc(str, ')');
1417 			}
1418 			break;
1419 		case ZEND_AST_INSTANCEOF:
1420 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1421 			smart_str_appends(str, " instanceof ");
1422 			zend_ast_export_ns_name(str, ast->child[1], 0, indent);
1423 			break;
1424 		case ZEND_AST_YIELD:
1425 			if (priority > 70) smart_str_appendc(str, '(');
1426 			smart_str_appends(str, "yield ");
1427 			if (ast->child[0]) {
1428 				if (ast->child[1]) {
1429 					zend_ast_export_ex(str, ast->child[1], 70, indent);
1430 					smart_str_appends(str, " => ");
1431 				}
1432 				zend_ast_export_ex(str, ast->child[0], 70, indent);
1433 			}
1434 			if (priority > 70) smart_str_appendc(str, ')');
1435 			break;
1436 		case ZEND_AST_YIELD_FROM:
1437 			PREFIX_OP("yield from ", 85, 86);
1438 		case ZEND_AST_COALESCE: BINARY_OP(" ?? ", 110, 111, 110);
1439 		case ZEND_AST_STATIC:
1440 			smart_str_appends(str, "static $");
1441 			zend_ast_export_name(str, ast->child[0], 0, indent);
1442 			APPEND_DEFAULT_VALUE(1);
1443 		case ZEND_AST_WHILE:
1444 			smart_str_appends(str, "while (");
1445 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1446 			smart_str_appends(str, ") {\n");
1447 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1448 			zend_ast_export_indent(str, indent);
1449 			smart_str_appendc(str, '}');
1450 			break;
1451 		case ZEND_AST_DO_WHILE:
1452 			smart_str_appends(str, "do {\n");
1453 			zend_ast_export_stmt(str, ast->child[0], indent + 1);
1454 			zend_ast_export_indent(str, indent);
1455 			smart_str_appends(str, "} while (");
1456 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1457 			smart_str_appendc(str, ')');
1458 			break;
1459 
1460 		case ZEND_AST_IF_ELEM:
1461 			if (ast->child[0]) {
1462 				smart_str_appends(str, "if (");
1463 				zend_ast_export_ex(str, ast->child[0], 0, indent);
1464 				smart_str_appends(str, ") {\n");
1465 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1466 			} else {
1467 				smart_str_appends(str, "else {\n");
1468 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1469 			}
1470 			zend_ast_export_indent(str, indent);
1471 			smart_str_appendc(str, '}');
1472 			break;
1473 		case ZEND_AST_SWITCH:
1474 			smart_str_appends(str, "switch (");
1475 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1476 			smart_str_appends(str, ") {\n");
1477 			zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
1478 			zend_ast_export_indent(str, indent);
1479 			smart_str_appendc(str, '}');
1480 			break;
1481 		case ZEND_AST_SWITCH_CASE:
1482 			zend_ast_export_indent(str, indent);
1483 			if (ast->child[0]) {
1484 				smart_str_appends(str, "case ");
1485 				zend_ast_export_ex(str, ast->child[0], 0, indent);
1486 				smart_str_appends(str, ":\n");
1487 			} else {
1488 				smart_str_appends(str, "default:\n");
1489 			}
1490 			zend_ast_export_stmt(str, ast->child[1], indent + 1);
1491 			break;
1492 		case ZEND_AST_DECLARE:
1493 			smart_str_appends(str, "declare(");
1494 			ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_CONST_DECL);
1495 			zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
1496 			smart_str_appendc(str, ')');
1497 			if (ast->child[1]) {
1498 				smart_str_appends(str, " {\n");
1499 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1500 				zend_ast_export_indent(str, indent);
1501 				smart_str_appendc(str, '}');
1502 			} else {
1503 				smart_str_appendc(str, ';');
1504 			}
1505 			break;
1506 		case ZEND_AST_PROP_ELEM:
1507 			smart_str_appendc(str, '$');
1508 			/* break missing intentionally */
1509 		case ZEND_AST_CONST_ELEM:
1510 			zend_ast_export_name(str, ast->child[0], 0, indent);
1511 			APPEND_DEFAULT_VALUE(1);
1512 		case ZEND_AST_USE_TRAIT:
1513 			smart_str_appends(str, "use ");
1514 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1515 			if (ast->child[1]) {
1516 				smart_str_appends(str, " {\n");
1517 				zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
1518 				zend_ast_export_indent(str, indent);
1519 				smart_str_appends(str, "}");
1520 			} else {
1521 				smart_str_appends(str, ";");
1522 			}
1523 			break;
1524 		case ZEND_AST_TRAIT_PRECEDENCE:
1525 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1526 			smart_str_appends(str, " insteadof ");
1527 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1528 			break;
1529 		case ZEND_AST_METHOD_REFERENCE:
1530 			if (ast->child[0]) {
1531 				zend_ast_export_name(str, ast->child[0], 0, indent);
1532 				smart_str_appends(str, "::");
1533 			}
1534 			zend_ast_export_name(str, ast->child[1], 0, indent);
1535 			break;
1536 		case ZEND_AST_NAMESPACE:
1537 			smart_str_appends(str, "namespace");
1538 			if (ast->child[0]) {
1539 				smart_str_appendc(str, ' ');
1540 				zend_ast_export_name(str, ast->child[0], 0, indent);
1541 			}
1542 			if (ast->child[1]) {
1543 				smart_str_appends(str, " {\n");
1544 				zend_ast_export_stmt(str, ast->child[1], indent + 1);
1545 				zend_ast_export_indent(str, indent);
1546 				smart_str_appends(str, "}\n");
1547 			} else {
1548 				smart_str_appendc(str, ';');
1549 			}
1550 			break;
1551 		case ZEND_AST_USE_ELEM:
1552 		case ZEND_AST_TRAIT_ALIAS:
1553 			zend_ast_export_name(str, ast->child[0], 0, indent);
1554 			if (ast->attr & ZEND_ACC_PUBLIC) {
1555 				smart_str_appends(str, " as public");
1556 			} else if (ast->attr & ZEND_ACC_PROTECTED) {
1557 				smart_str_appends(str, " as protected");
1558 			} else if (ast->attr & ZEND_ACC_PRIVATE) {
1559 				smart_str_appends(str, " as private");
1560 			} else if (ast->child[1]) {
1561 				smart_str_appends(str, " as");
1562 			}
1563 			if (ast->child[1]) {
1564 				smart_str_appendc(str, ' ');
1565 				zend_ast_export_name(str, ast->child[1], 0, indent);
1566 			}
1567 			break;
1568 
1569 		/* 3 child nodes */
1570 		case ZEND_AST_METHOD_CALL:
1571 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1572 			smart_str_appends(str, "->");
1573 			zend_ast_export_var(str, ast->child[1], 0, indent);
1574 			smart_str_appendc(str, '(');
1575 			zend_ast_export_ex(str, ast->child[2], 0, indent);
1576 			smart_str_appendc(str, ')');
1577 			break;
1578 		case ZEND_AST_STATIC_CALL:
1579 			zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1580 			smart_str_appends(str, "::");
1581 			zend_ast_export_var(str, ast->child[1], 0, indent);
1582 			smart_str_appendc(str, '(');
1583 			zend_ast_export_ex(str, ast->child[2], 0, indent);
1584 			smart_str_appendc(str, ')');
1585 			break;
1586 		case ZEND_AST_CONDITIONAL:
1587 			if (priority > 100) smart_str_appendc(str, '(');
1588 			zend_ast_export_ex(str, ast->child[0], 100, indent);
1589 			if (ast->child[1]) {
1590 				smart_str_appends(str, " ? ");
1591 				zend_ast_export_ex(str, ast->child[1], 101, indent);
1592 				smart_str_appends(str, " : ");
1593 			} else {
1594 				smart_str_appends(str, " ?: ");
1595 			}
1596 			zend_ast_export_ex(str, ast->child[2], 101, indent);
1597 			if (priority > 100) smart_str_appendc(str, ')');
1598 			break;
1599 
1600 		case ZEND_AST_TRY:
1601 			smart_str_appends(str, "try {\n");
1602 			zend_ast_export_stmt(str, ast->child[0], indent + 1);
1603 			zend_ast_export_indent(str, indent);
1604 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1605 			if (ast->child[2]) {
1606 				smart_str_appends(str, "} finally {\n");
1607 				zend_ast_export_stmt(str, ast->child[2], indent + 1);
1608 				zend_ast_export_indent(str, indent);
1609 			}
1610 			smart_str_appendc(str, '}');
1611 			break;
1612 		case ZEND_AST_CATCH:
1613 			smart_str_appends(str, "} catch (");
1614 			zend_ast_export_catch_name_list(str, zend_ast_get_list(ast->child[0]), indent);
1615 			smart_str_appends(str, " $");
1616 			zend_ast_export_var(str, ast->child[1], 0, indent);
1617 			smart_str_appends(str, ") {\n");
1618 			zend_ast_export_stmt(str, ast->child[2], indent + 1);
1619 			zend_ast_export_indent(str, indent);
1620 			break;
1621 		case ZEND_AST_PARAM:
1622 			if (ast->child[0]) {
1623 				if (ast->child[0]->attr & ZEND_TYPE_NULLABLE) {
1624 					smart_str_appendc(str, '?');
1625 				}
1626 				zend_ast_export_ns_name(str, ast->child[0], 0, indent);
1627 				smart_str_appendc(str, ' ');
1628 			}
1629 			if (ast->attr & ZEND_PARAM_REF) {
1630 				smart_str_appendc(str, '&');
1631 			}
1632 			if (ast->attr & ZEND_PARAM_VARIADIC) {
1633 				smart_str_appends(str, "...");
1634 			}
1635 			smart_str_appendc(str, '$');
1636 			zend_ast_export_name(str, ast->child[1], 0, indent);
1637 			APPEND_DEFAULT_VALUE(2);
1638 
1639 		/* 4 child nodes */
1640 		case ZEND_AST_FOR:
1641 			smart_str_appends(str, "for (");
1642 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1643 			smart_str_appendc(str, ';');
1644 			if (ast->child[1]) {
1645 				smart_str_appendc(str, ' ');
1646 				zend_ast_export_ex(str, ast->child[1], 0, indent);
1647 			}
1648 			smart_str_appendc(str, ';');
1649 			if (ast->child[2]) {
1650 				smart_str_appendc(str, ' ');
1651 				zend_ast_export_ex(str, ast->child[2], 0, indent);
1652 			}
1653 			smart_str_appends(str, ") {\n");
1654 			zend_ast_export_stmt(str, ast->child[3], indent + 1);
1655 			zend_ast_export_indent(str, indent);
1656 			smart_str_appendc(str, '}');
1657 			break;
1658 		case ZEND_AST_FOREACH:
1659 			smart_str_appends(str, "foreach (");
1660 			zend_ast_export_ex(str, ast->child[0], 0, indent);
1661 			smart_str_appends(str, " as ");
1662 			if (ast->child[2]) {
1663 				zend_ast_export_ex(str, ast->child[2], 0, indent);
1664 				smart_str_appends(str, " => ");
1665 			}
1666 			zend_ast_export_ex(str, ast->child[1], 0, indent);
1667 			smart_str_appends(str, ") {\n");
1668 			zend_ast_export_stmt(str, ast->child[3], indent + 1);
1669 			zend_ast_export_indent(str, indent);
1670 			smart_str_appendc(str, '}');
1671 			break;
1672 		EMPTY_SWITCH_DEFAULT_CASE();
1673 	}
1674 	return;
1675 
1676 binary_op:
1677 	if (priority > p) smart_str_appendc(str, '(');
1678 	zend_ast_export_ex(str, ast->child[0], pl, indent);
1679 	smart_str_appends(str, op);
1680 	zend_ast_export_ex(str, ast->child[1], pr, indent);
1681 	if (priority > p) smart_str_appendc(str, ')');
1682 	return;
1683 
1684 prefix_op:
1685 	if (priority > p) smart_str_appendc(str, '(');
1686 	smart_str_appends(str, op);
1687 	zend_ast_export_ex(str, ast->child[0], pl, indent);
1688 	if (priority > p) smart_str_appendc(str, ')');
1689 	return;
1690 
1691 postfix_op:
1692 	if (priority > p) smart_str_appendc(str, '(');
1693 	zend_ast_export_ex(str, ast->child[0], pl, indent);
1694 	smart_str_appends(str, op);
1695 	if (priority > p) smart_str_appendc(str, ')');
1696 	return;
1697 
1698 func_op:
1699 	smart_str_appends(str, op);
1700 	smart_str_appendc(str, '(');
1701 	zend_ast_export_ex(str, ast->child[0], 0, indent);
1702 	smart_str_appendc(str, ')');
1703 	return;
1704 
1705 append_node_1:
1706 	smart_str_appends(str, op);
1707 	if (ast->child[0]) {
1708 		smart_str_appendc(str, ' ');
1709 		ast = ast->child[0];
1710 		goto tail_call;
1711 	}
1712 	return;
1713 
1714 append_str:
1715 	smart_str_appends(str, op);
1716 	return;
1717 
1718 append_default_value:
1719 	if (ast->child[p]) {
1720 		smart_str_appends(str, " = ");
1721 		ast = ast->child[p];
1722 		goto tail_call;
1723 	}
1724 	return;
1725 }
1726 
zend_ast_export(const char * prefix,zend_ast * ast,const char * suffix)1727 ZEND_API zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix)
1728 {
1729 	smart_str str = {0};
1730 
1731 	smart_str_appends(&str, prefix);
1732 	zend_ast_export_ex(&str, ast, 0, 0);
1733 	smart_str_appends(&str, suffix);
1734 	smart_str_0(&str);
1735 	return str.s;
1736 }
1737 
1738 /*
1739  * Local variables:
1740  * tab-width: 4
1741  * c-basic-offset: 4
1742  * indent-tabs-mode: t
1743  * End:
1744  * vim600: sw=4 ts=4 fdm=marker
1745  * vim<600: sw=4 ts=4
1746  */
1747