root/Zend/zend_ast.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_ast_alloc
  2. zend_ast_realloc
  3. zend_ast_size
  4. zend_ast_list_size
  5. zend_ast_create_znode
  6. zend_ast_create_zval_ex
  7. zend_ast_create_decl
  8. zend_ast_create_from_va_list
  9. zend_ast_create_ex
  10. zend_ast_create
  11. zend_ast_create_list
  12. is_power_of_two
  13. zend_ast_list_add
  14. zend_ast_add_array_element
  15. zend_ast_evaluate
  16. zend_ast_copy
  17. zend_ast_destroy_ex
  18. zend_ast_destroy
  19. zend_ast_destroy_and_free
  20. zend_ast_apply
  21. zend_ast_export_str
  22. zend_ast_export_qstr
  23. zend_ast_export_indent
  24. zend_ast_export_name
  25. zend_ast_export_ns_name
  26. zend_ast_valid_var_char
  27. zend_ast_valid_var_name
  28. zend_ast_export_var
  29. zend_ast_export_list
  30. zend_ast_export_encaps_list
  31. zend_ast_export_name_list
  32. zend_ast_export_var_list
  33. zend_ast_export_stmt
  34. zend_ast_export_if_stmt
  35. zend_ast_export_zval
  36. zend_ast_export_ex
  37. zend_ast_export

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

/* [<][>][^][v][top][bottom][index][help] */