Coverage Report

Created: 2026-06-02 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/Zend/zend_ast.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend Engine                                                          |
4
   +----------------------------------------------------------------------+
5
   | Copyright © Zend Technologies Ltd., a subsidiary company of          |
6
   |     Perforce Software, Inc., and Contributors.                       |
7
   +----------------------------------------------------------------------+
8
   | This source file is subject to the Modified BSD License that is      |
9
   | bundled with this package in the file LICENSE, and is available      |
10
   | through the World Wide Web at <https://www.php.net/license/>.        |
11
   |                                                                      |
12
   | SPDX-License-Identifier: BSD-3-Clause                                |
13
   +----------------------------------------------------------------------+
14
   | Authors: Bob Weinand <bwoebi@php.net>                                |
15
   |          Dmitry Stogov <dmitry@php.net>                              |
16
   +----------------------------------------------------------------------+
17
*/
18
19
#include "zend_ast.h"
20
#include "zend_API.h"
21
#include "zend_operators.h"
22
#include "zend_language_parser.h"
23
#include "zend_smart_str.h"
24
#include "zend_exceptions.h"
25
#include "zend_closures.h"
26
#include "zend_constants.h"
27
#include "zend_enum.h"
28
29
ZEND_API zend_ast_process_t zend_ast_process = NULL;
30
31
2.93M
static inline void *zend_ast_alloc(size_t size) {
32
2.93M
  return zend_arena_alloc(&CG(ast_arena), size);
33
2.93M
}
34
35
50.0k
static inline void *zend_ast_realloc(const void *old, size_t old_size, size_t new_size) {
36
50.0k
  void *new = zend_ast_alloc(new_size);
37
50.0k
  memcpy(new, old, old_size);
38
50.0k
  return new;
39
50.0k
}
40
41
533k
static inline size_t zend_ast_list_size(uint32_t children) {
42
533k
  return sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * children;
43
533k
}
44
45
2.82k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(const znode *node) {
46
2.82k
  zend_ast_znode *ast;
47
48
2.82k
  ast = zend_ast_alloc(sizeof(zend_ast_znode));
49
2.82k
  ast->kind = ZEND_AST_ZNODE;
50
2.82k
  ast->attr = 0;
51
2.82k
  ast->lineno = CG(zend_lineno);
52
2.82k
  ast->node = *node;
53
2.82k
  return (zend_ast *) ast;
54
2.82k
}
55
56
633
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(zend_ast *args) {
57
633
  zend_ast_fcc *ast;
58
59
633
  ast = zend_ast_alloc(sizeof(zend_ast_fcc));
60
633
  ast->kind = ZEND_AST_CALLABLE_CONVERT;
61
633
  ast->attr = 0;
62
633
  ast->lineno = CG(zend_lineno);
63
633
  ast->args = args;
64
633
  ZEND_MAP_PTR_INIT(ast->fptr, NULL);
65
66
633
  return (zend_ast *) ast;
67
633
}
68
69
1.17M
static zend_always_inline zend_ast * zend_ast_create_zval_int(const zval *zv, uint32_t attr, uint32_t lineno) {
70
1.17M
  zend_ast_zval *ast;
71
72
1.17M
  ast = zend_ast_alloc(sizeof(zend_ast_zval));
73
1.17M
  ast->kind = ZEND_AST_ZVAL;
74
1.17M
  ast->attr = attr;
75
1.17M
  ZVAL_COPY_VALUE(&ast->val, zv);
76
1.17M
  Z_LINENO(ast->val) = lineno;
77
1.17M
  return (zend_ast *) ast;
78
1.17M
}
79
80
1.11M
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_with_lineno(const zval *zv, uint32_t lineno) {
81
1.11M
  return zend_ast_create_zval_int(zv, 0, lineno);
82
1.11M
}
83
84
340
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_ex(const zval *zv, zend_ast_attr attr) {
85
340
  return zend_ast_create_zval_int(zv, attr, CG(zend_lineno));
86
340
}
87
88
28.5k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval(const zval *zv) {
89
28.5k
  return zend_ast_create_zval_int(zv, 0, CG(zend_lineno));
90
28.5k
}
91
92
2.12k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_from_str(zend_string *str) {
93
2.12k
  zval zv;
94
2.12k
  ZVAL_STR(&zv, str);
95
2.12k
  return zend_ast_create_zval_int(&zv, 0, CG(zend_lineno));
96
2.12k
}
97
98
21.9k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_from_long(zend_long lval) {
99
21.9k
  zval zv;
100
21.9k
  ZVAL_LONG(&zv, lval);
101
21.9k
  return zend_ast_create_zval_int(&zv, 0, CG(zend_lineno));
102
21.9k
}
103
104
988
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_constant(zend_string *name, zend_ast_attr attr) {
105
988
  zend_ast_zval *ast;
106
107
988
  ast = zend_ast_alloc(sizeof(zend_ast_zval));
108
988
  ast->kind = ZEND_AST_CONSTANT;
109
988
  ast->attr = attr;
110
988
  ZVAL_STR(&ast->val, name);
111
988
  Z_LINENO(ast->val) = CG(zend_lineno);
112
988
  return (zend_ast *) ast;
113
988
}
114
115
38
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_op_array(zend_op_array *op_array) {
116
38
  zend_ast_op_array *ast;
117
118
38
  ast = zend_ast_alloc(sizeof(zend_ast_op_array));
119
38
  ast->kind = ZEND_AST_OP_ARRAY;
120
38
  ast->attr = 0;
121
38
  ast->lineno = CG(zend_lineno);
122
38
  ast->op_array = op_array;
123
124
38
  return (zend_ast *) ast;
125
38
}
126
127
5.91k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast *class_name, zend_ast *name) {
128
5.91k
  zend_string *name_str = zend_ast_get_str(name);
129
5.91k
  if (zend_string_equals_ci(name_str, ZSTR_KNOWN(ZEND_STR_CLASS))) {
130
2.18k
    zend_string_release(name_str);
131
2.18k
    return zend_ast_create(ZEND_AST_CLASS_NAME, class_name);
132
3.73k
  } else {
133
3.73k
    return zend_ast_create(ZEND_AST_CLASS_CONST, class_name, name);
134
3.73k
  }
135
5.91k
}
136
137
ZEND_API zend_ast *zend_ast_create_decl(
138
  zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
139
  zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4
140
43.4k
) {
141
43.4k
  zend_ast_decl *ast;
142
143
43.4k
  ast = zend_ast_alloc(sizeof(zend_ast_decl));
144
43.4k
  ast->kind = kind;
145
43.4k
  ast->attr = 0;
146
43.4k
  ast->start_lineno = start_lineno;
147
43.4k
  ast->end_lineno = CG(zend_lineno);
148
43.4k
  ast->flags = flags;
149
43.4k
  ast->doc_comment = doc_comment;
150
43.4k
  ast->name = name;
151
43.4k
  ast->child[0] = child0;
152
43.4k
  ast->child[1] = child1;
153
43.4k
  ast->child[2] = child2;
154
43.4k
  ast->child[3] = child3;
155
43.4k
  ast->child[4] = child4;
156
157
43.4k
  return (zend_ast *) ast;
158
43.4k
}
159
160
112k
static bool zend_ast_is_placeholder_arg(zend_ast *arg) {
161
112k
  return arg->kind == ZEND_AST_PLACEHOLDER_ARG
162
111k
    || (arg->kind == ZEND_AST_NAMED_ARG
163
1.82k
        && arg->child[1]->kind == ZEND_AST_PLACEHOLDER_ARG);
164
112k
}
165
166
#if ZEND_AST_SPEC
167
7.07k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_0(zend_ast_kind kind) {
168
7.07k
  zend_ast *ast;
169
170
7.07k
  ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 0);
171
7.07k
  ast = zend_ast_alloc(zend_ast_size(0));
172
7.07k
  ast->kind = kind;
173
7.07k
  ast->attr = 0;
174
7.07k
  ast->lineno = CG(zend_lineno);
175
176
7.07k
  return ast;
177
7.07k
}
178
179
576k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_1(zend_ast_kind kind, zend_ast *child) {
180
576k
  zend_ast *ast;
181
576k
  uint32_t lineno;
182
183
576k
  ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 1);
184
576k
  ast = zend_ast_alloc(zend_ast_size(1));
185
576k
  ast->kind = kind;
186
576k
  ast->attr = 0;
187
576k
  ast->child[0] = child;
188
576k
  if (child) {
189
575k
    lineno = zend_ast_get_lineno(child);
190
575k
  } else {
191
708
    lineno = CG(zend_lineno);
192
708
  }
193
576k
  ast->lineno = lineno;
194
195
576k
  return ast;
196
576k
}
197
198
544k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2) {
199
544k
  zend_ast *ast;
200
544k
  uint32_t lineno;
201
202
544k
  ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 2);
203
544k
  ast = zend_ast_alloc(zend_ast_size(2));
204
544k
  ast->kind = kind;
205
544k
  ast->attr = 0;
206
544k
  ast->child[0] = child1;
207
544k
  ast->child[1] = child2;
208
544k
  if (child1) {
209
542k
    lineno = zend_ast_get_lineno(child1);
210
542k
  } else if (child2) {
211
1.27k
    lineno = zend_ast_get_lineno(child2);
212
1.27k
  } else {
213
439
    lineno = CG(zend_lineno);
214
439
  }
215
544k
  ast->lineno = lineno;
216
217
544k
  return ast;
218
544k
}
219
220
67.7k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_3(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3) {
221
67.7k
  zend_ast *ast;
222
67.7k
  uint32_t lineno;
223
224
67.7k
  ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 3);
225
67.7k
  ast = zend_ast_alloc(zend_ast_size(3));
226
67.7k
  ast->kind = kind;
227
67.7k
  ast->attr = 0;
228
67.7k
  ast->child[0] = child1;
229
67.7k
  ast->child[1] = child2;
230
67.7k
  ast->child[2] = child3;
231
67.7k
  if (child1) {
232
62.3k
    lineno = zend_ast_get_lineno(child1);
233
62.3k
  } else if (child2) {
234
5.32k
    lineno = zend_ast_get_lineno(child2);
235
5.32k
  } else if (child3) {
236
0
    lineno = zend_ast_get_lineno(child3);
237
0
  } else {
238
0
    lineno = CG(zend_lineno);
239
0
  }
240
67.7k
  ast->lineno = lineno;
241
242
67.7k
  return ast;
243
67.7k
}
244
245
20.7k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_4(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4) {
246
20.7k
  zend_ast *ast;
247
20.7k
  uint32_t lineno;
248
249
20.7k
  ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 4);
250
20.7k
  ast = zend_ast_alloc(zend_ast_size(4));
251
20.7k
  ast->kind = kind;
252
20.7k
  ast->attr = 0;
253
20.7k
  ast->child[0] = child1;
254
20.7k
  ast->child[1] = child2;
255
20.7k
  ast->child[2] = child3;
256
20.7k
  ast->child[3] = child4;
257
20.7k
  if (child1) {
258
20.0k
    lineno = zend_ast_get_lineno(child1);
259
20.0k
  } else if (child2) {
260
243
    lineno = zend_ast_get_lineno(child2);
261
519
  } else if (child3) {
262
4
    lineno = zend_ast_get_lineno(child3);
263
515
  } else if (child4) {
264
515
    lineno = zend_ast_get_lineno(child4);
265
515
  } else {
266
0
    lineno = CG(zend_lineno);
267
0
  }
268
20.7k
  ast->lineno = lineno;
269
270
20.7k
  return ast;
271
20.7k
}
272
273
0
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_5(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4, zend_ast *child5) {
274
0
  zend_ast *ast;
275
0
  uint32_t lineno;
276
277
0
  ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 5);
278
0
  ast = zend_ast_alloc(zend_ast_size(5));
279
0
  ast->kind = kind;
280
0
  ast->attr = 0;
281
0
  ast->child[0] = child1;
282
0
  ast->child[1] = child2;
283
0
  ast->child[2] = child3;
284
0
  ast->child[3] = child4;
285
0
  ast->child[4] = child5;
286
0
  if (child1) {
287
0
    lineno = zend_ast_get_lineno(child1);
288
0
  } else if (child2) {
289
0
    lineno = zend_ast_get_lineno(child2);
290
0
  } else if (child3) {
291
0
    lineno = zend_ast_get_lineno(child3);
292
0
  } else if (child4) {
293
0
    lineno = zend_ast_get_lineno(child4);
294
0
  } else if (child5) {
295
0
    lineno = zend_ast_get_lineno(child5);
296
0
  } else {
297
0
    lineno = CG(zend_lineno);
298
0
  }
299
0
  ast->lineno = lineno;
300
301
0
  return ast;
302
0
}
303
304
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_va(
305
16.6k
    zend_ast_kind kind, zend_ast_attr attr, va_list *va) {
306
16.6k
  uint32_t lineno = (uint32_t)-1;
307
16.6k
  uint32_t children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT;
308
16.6k
  zend_ast *ast = zend_ast_alloc(zend_ast_size(children));
309
16.6k
  ast->kind = kind;
310
16.6k
  ast->attr = attr;
311
116k
  for (uint32_t i = 0; i < children; i++) {
312
99.8k
    ast->child[i] = va_arg(*va, zend_ast *);
313
99.8k
    if (lineno == (uint32_t)-1 && ast->child[i]) {
314
16.6k
      lineno = zend_ast_get_lineno(ast->child[i]);
315
16.6k
    }
316
99.8k
  }
317
16.6k
  if (lineno == (uint32_t)-1) {
318
0
    lineno = CG(zend_lineno);
319
0
  }
320
16.6k
  ast->lineno = lineno;
321
16.6k
  return ast;
322
16.6k
}
323
324
497
ZEND_API zend_ast * zend_ast_create_n(unsigned kind, ...) {
325
497
  va_list va;
326
497
  va_start(va, kind);
327
497
  zend_ast *ast = zend_ast_create_va(kind, 0, &va);
328
497
  va_end(va);
329
497
  return ast;
330
497
}
331
332
ZEND_API zend_ast * zend_ast_create_ex_n(
333
16.1k
    zend_ast_kind kind, unsigned attr, ...) {
334
16.1k
  va_list va;
335
16.1k
  va_start(va, attr);
336
16.1k
  zend_ast *ast = zend_ast_create_va(kind, attr, &va);
337
16.1k
  va_end(va);
338
16.1k
  return ast;
339
16.1k
}
340
341
198k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_0(zend_ast_kind kind) {
342
198k
  zend_ast *ast;
343
198k
  zend_ast_list *list;
344
345
198k
  ast = zend_ast_alloc(zend_ast_list_size(4));
346
198k
  list = (zend_ast_list *) ast;
347
198k
  list->kind = kind;
348
198k
  list->attr = 0;
349
198k
  list->lineno = CG(zend_lineno);
350
198k
  list->children = 0;
351
352
198k
  return ast;
353
198k
}
354
355
216k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_1(zend_ast_kind kind, zend_ast *child) {
356
216k
  zend_ast *ast;
357
216k
  zend_ast_list *list;
358
216k
  uint32_t lineno;
359
360
216k
  ast = zend_ast_alloc(zend_ast_list_size(4));
361
216k
  list = (zend_ast_list *) ast;
362
216k
  list->kind = kind;
363
216k
  list->attr = 0;
364
216k
  list->children = 1;
365
216k
  list->child[0] = child;
366
216k
  if (child) {
367
212k
    lineno = zend_ast_get_lineno(child);
368
212k
    if (lineno > CG(zend_lineno)) {
369
64
      lineno = CG(zend_lineno);
370
64
    }
371
212k
  } else {
372
4.37k
    lineno = CG(zend_lineno);
373
4.37k
  }
374
216k
  list->lineno = lineno;
375
376
216k
  return ast;
377
216k
}
378
379
16.9k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2) {
380
16.9k
  zend_ast *ast;
381
16.9k
  zend_ast_list *list;
382
16.9k
  uint32_t lineno;
383
384
16.9k
  ast = zend_ast_alloc(zend_ast_list_size(4));
385
16.9k
  list = (zend_ast_list *) ast;
386
16.9k
  list->kind = kind;
387
16.9k
  list->attr = 0;
388
16.9k
  list->children = 2;
389
16.9k
  list->child[0] = child1;
390
16.9k
  list->child[1] = child2;
391
16.9k
  if (child1) {
392
16.9k
    lineno = zend_ast_get_lineno(child1);
393
16.9k
    if (lineno > CG(zend_lineno)) {
394
0
      lineno = CG(zend_lineno);
395
0
    }
396
16.9k
  } else if (child2) {
397
0
    lineno = zend_ast_get_lineno(child2);
398
0
    if (lineno > CG(zend_lineno)) {
399
0
      lineno = CG(zend_lineno);
400
0
    }
401
0
  } else {
402
0
    list->children = 0;
403
0
    lineno = CG(zend_lineno);
404
0
  }
405
16.9k
  list->lineno = lineno;
406
407
16.9k
  return ast;
408
16.9k
}
409
410
28.9k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_0(zend_ast_kind kind) {
411
28.9k
  return zend_ast_create_list(0, kind);
412
28.9k
}
413
414
81.6k
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_1(zend_ast_kind kind, zend_ast *arg) {
415
81.6k
  zend_ast *list = zend_ast_create_list(1, kind, arg);
416
417
81.6k
  if (zend_ast_is_placeholder_arg(arg)) {
418
624
    return zend_ast_create_fcc(list);
419
624
  }
420
421
81.0k
  return list;
422
81.6k
}
423
424
93
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_2(zend_ast_kind kind, zend_ast *arg1, zend_ast *arg2) {
425
93
  zend_ast *list = zend_ast_create_list(2, kind, arg1, arg2);
426
427
93
  if (zend_ast_is_placeholder_arg(arg1) || zend_ast_is_placeholder_arg(arg2)) {
428
0
    return zend_ast_create_fcc(list);
429
0
  }
430
431
93
  return list;
432
93
}
433
#else
434
static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) {
435
  uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT;
436
  zend_ast *ast;
437
438
  ast = zend_ast_alloc(zend_ast_size(children));
439
  ast->kind = kind;
440
  ast->attr = attr;
441
  ast->lineno = (uint32_t) -1;
442
443
  for (i = 0; i < children; ++i) {
444
    ast->child[i] = va_arg(va, zend_ast *);
445
    if (ast->child[i] != NULL) {
446
      uint32_t lineno = zend_ast_get_lineno(ast->child[i]);
447
      if (lineno < ast->lineno) {
448
        ast->lineno = lineno;
449
      }
450
    }
451
  }
452
453
  if (ast->lineno == UINT_MAX) {
454
    ast->lineno = CG(zend_lineno);
455
  }
456
457
  return ast;
458
}
459
460
ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, ...) {
461
  va_list va;
462
  zend_ast *ast;
463
464
  va_start(va, attr);
465
  ast = zend_ast_create_from_va_list(kind, attr, va);
466
  va_end(va);
467
468
  return ast;
469
}
470
471
ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...) {
472
  va_list va;
473
  zend_ast *ast;
474
475
  va_start(va, kind);
476
  ast = zend_ast_create_from_va_list(kind, 0, va);
477
  va_end(va);
478
479
  return ast;
480
}
481
482
ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind kind, ...) {
483
  zend_ast *ast;
484
  zend_ast_list *list;
485
486
  ast = zend_ast_alloc(zend_ast_list_size(4));
487
  list = (zend_ast_list *) ast;
488
  list->kind = kind;
489
  list->attr = 0;
490
  list->lineno = CG(zend_lineno);
491
  list->children = 0;
492
493
  {
494
    va_list va;
495
    uint32_t i;
496
    va_start(va, kind);
497
    for (i = 0; i < init_children; ++i) {
498
      zend_ast *child = va_arg(va, zend_ast *);
499
      ast = zend_ast_list_add(ast, child);
500
      if (child != NULL) {
501
        uint32_t lineno = zend_ast_get_lineno(child);
502
        if (lineno < ast->lineno) {
503
          ast->lineno = lineno;
504
        }
505
      }
506
    }
507
    va_end(va);
508
  }
509
510
  return ast;
511
}
512
513
ZEND_API zend_ast *zend_ast_create_arg_list(uint32_t init_children, zend_ast_kind kind, ...) {
514
  zend_ast *ast;
515
  zend_ast_list *list;
516
  bool has_placeholders = false;
517
518
  ast = zend_ast_alloc(zend_ast_list_size(4));
519
  list = (zend_ast_list *) ast;
520
  list->kind = kind;
521
  list->attr = 0;
522
  list->lineno = CG(zend_lineno);
523
  list->children = 0;
524
525
  {
526
    va_list va;
527
    uint32_t i;
528
    va_start(va, kind);
529
    for (i = 0; i < init_children; ++i) {
530
      zend_ast *child = va_arg(va, zend_ast *);
531
      ast = zend_ast_list_add(ast, child);
532
      uint32_t lineno = zend_ast_get_lineno(child);
533
      if (lineno < ast->lineno) {
534
        ast->lineno = lineno;
535
      }
536
      has_placeholders = has_placeholders || zend_ast_is_placeholder_arg(child);
537
    }
538
    va_end(va);
539
  }
540
541
  if (has_placeholders) {
542
    return zend_ast_create_fcc(list);
543
  }
544
545
  return ast;
546
}
547
#endif
548
549
33.5k
zend_ast *zend_ast_create_concat_op(zend_ast *op0, zend_ast *op1) {
550
33.5k
  if (op0->kind == ZEND_AST_ZVAL && op1->kind == ZEND_AST_ZVAL) {
551
7.35k
    zval *zv0 = zend_ast_get_zval(op0);
552
7.35k
    zval *zv1 = zend_ast_get_zval(op1);
553
7.35k
    if (!zend_binary_op_produces_error(ZEND_CONCAT, zv0, zv1) &&
554
7.35k
        concat_function(zv0, zv0, zv1) == SUCCESS) {
555
7.35k
      zval_ptr_dtor_nogc(zv1);
556
7.35k
      return zend_ast_create_zval(zv0);
557
7.35k
    }
558
7.35k
  }
559
26.2k
  return zend_ast_create_binary_op(ZEND_CONCAT, op0, op1);
560
33.5k
}
561
562
345k
static inline bool is_power_of_two(uint32_t n) {
563
345k
  return ((n != 0) && (n == (n & (~n + 1))));
564
345k
}
565
566
677k
ZEND_ATTRIBUTE_NODISCARD ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *ast, zend_ast *op) {
567
677k
  zend_ast_list *list = zend_ast_get_list(ast);
568
677k
  if (list->children >= 4 && is_power_of_two(list->children)) {
569
50.0k
      list = zend_ast_realloc(list,
570
50.0k
      zend_ast_list_size(list->children), zend_ast_list_size(list->children * 2));
571
50.0k
  }
572
677k
  list->child[list->children++] = op;
573
677k
  return (zend_ast *) list;
574
677k
}
575
576
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_arg_list_add(zend_ast *list, zend_ast *arg)
577
30.6k
{
578
30.6k
  if (list->kind == ZEND_AST_CALLABLE_CONVERT) {
579
3
    zend_ast_fcc *fcc_ast = (zend_ast_fcc*)list;
580
3
    fcc_ast->args = zend_ast_list_add(fcc_ast->args, arg);
581
3
    return (zend_ast*)fcc_ast;
582
3
  }
583
584
30.6k
  ZEND_ASSERT(list->kind == ZEND_AST_ARG_LIST);
585
586
30.6k
  if (zend_ast_is_placeholder_arg(arg)) {
587
9
    return zend_ast_create_fcc(zend_ast_list_add(list, arg));
588
9
  }
589
590
30.6k
  return zend_ast_list_add(list, arg);
591
30.6k
}
592
593
static zend_result zend_ast_add_array_element(const zval *result, zval *offset, zval *expr)
594
252
{
595
252
  if (Z_TYPE_P(offset) == IS_UNDEF) {
596
66
    if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), expr)) {
597
3
      zend_throw_error(NULL,
598
3
        "Cannot add element to the array as the next element is already occupied");
599
3
      return FAILURE;
600
3
    }
601
63
    return SUCCESS;
602
66
  }
603
604
186
  if (array_set_zval_key(Z_ARRVAL_P(result), offset, expr) == FAILURE) {
605
6
    return FAILURE;
606
6
  }
607
608
180
  zval_ptr_dtor_nogc(offset);
609
180
  zval_ptr_dtor_nogc(expr);
610
180
  return SUCCESS;
611
186
}
612
613
15
static zend_result zend_ast_add_unpacked_element(const zval *result, const zval *expr) {
614
15
  if (EXPECTED(Z_TYPE_P(expr) == IS_ARRAY)) {
615
12
    const HashTable *ht = Z_ARRVAL_P(expr);
616
12
    zval *val;
617
12
    zend_string *key;
618
619
66
    ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
620
66
      if (key) {
621
0
        zend_hash_update(Z_ARRVAL_P(result), key, val);
622
27
      } else {
623
27
        if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), val)) {
624
6
          zend_throw_error(NULL,
625
6
            "Cannot add element to the array as the next element is already occupied");
626
6
          return FAILURE;
627
6
        }
628
27
      }
629
21
      Z_TRY_ADDREF_P(val);
630
21
    } ZEND_HASH_FOREACH_END();
631
6
    return SUCCESS;
632
12
  }
633
634
3
  zend_throw_error(NULL, "Only arrays can be unpacked in constant expression");
635
3
  return FAILURE;
636
15
}
637
638
static zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope)
639
234
{
640
234
  return zend_fetch_class_with_scope(zend_ast_get_str(ast), (ast->attr >> ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT) | ZEND_FETCH_CLASS_EXCEPTION, scope);
641
234
}
642
643
static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
644
  zval *result,
645
  zend_ast *ast,
646
  zend_class_entry *scope,
647
  bool *short_circuited_ptr,
648
  zend_ast_evaluate_ctx *ctx
649
);
650
651
ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex(
652
  zval *result,
653
  zend_ast *ast,
654
  zend_class_entry *scope,
655
  bool *short_circuited_ptr,
656
  zend_ast_evaluate_ctx *ctx
657
5.92k
) {
658
5.92k
  zend_string *previous_filename;
659
5.92k
  zend_long previous_lineno;
660
5.92k
  if (scope) {
661
4.20k
    previous_filename = EG(filename_override);
662
4.20k
    previous_lineno = EG(lineno_override);
663
4.20k
    EG(filename_override) = scope->info.user.filename;
664
4.20k
    EG(lineno_override) = zend_ast_get_lineno(ast);
665
4.20k
  }
666
5.92k
  zend_result r = zend_ast_evaluate_inner(result, ast, scope, short_circuited_ptr, ctx);
667
5.92k
  if (scope) {
668
4.19k
    EG(filename_override) = previous_filename;
669
4.19k
    EG(lineno_override) = previous_lineno;
670
4.19k
  }
671
5.92k
  return r;
672
5.92k
}
673
674
static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
675
  zval *result,
676
  zend_ast *ast,
677
  zend_class_entry *scope,
678
  bool *short_circuited_ptr,
679
  zend_ast_evaluate_ctx *ctx
680
5.92k
) {
681
5.92k
  zval op1, op2;
682
5.92k
  zend_result ret = SUCCESS;
683
5.92k
  bool short_circuited;
684
5.92k
  *short_circuited_ptr = false;
685
686
5.92k
  switch (ast->kind) {
687
288
    case ZEND_AST_BINARY_OP:
688
288
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
689
27
        ret = FAILURE;
690
261
      } else if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
691
6
        zval_ptr_dtor_nogc(&op1);
692
6
        ret = FAILURE;
693
255
      } else {
694
255
        binary_op_type op = get_binary_op(ast->attr);
695
255
        op(result, &op1, &op2);
696
255
        zval_ptr_dtor_nogc(&op1);
697
255
        zval_ptr_dtor_nogc(&op2);
698
255
        ret = EG(exception) ? FAILURE : SUCCESS;
699
255
      }
700
288
      break;
701
9
    case ZEND_AST_GREATER:
702
12
    case ZEND_AST_GREATER_EQUAL:
703
12
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
704
0
        ret = FAILURE;
705
12
      } else if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
706
3
        zval_ptr_dtor_nogc(&op1);
707
3
        ret = FAILURE;
708
9
      } else {
709
        /* op1 > op2 is the same as op2 < op1 */
710
9
        binary_op_type op = ast->kind == ZEND_AST_GREATER
711
9
          ? is_smaller_function : is_smaller_or_equal_function;
712
9
        op(result, &op2, &op1);
713
9
        zval_ptr_dtor_nogc(&op1);
714
9
        zval_ptr_dtor_nogc(&op2);
715
9
        ret = EG(exception) ? FAILURE : SUCCESS;
716
9
      }
717
12
      break;
718
6
    case ZEND_AST_UNARY_OP:
719
6
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
720
0
        ret = FAILURE;
721
6
      } else {
722
6
        unary_op_type op = get_unary_op(ast->attr);
723
6
        ret = op(result, &op1);
724
6
        zval_ptr_dtor_nogc(&op1);
725
6
      }
726
6
      break;
727
2.08k
    case ZEND_AST_ZVAL:
728
2.08k
    {
729
2.08k
      zval *zv = zend_ast_get_zval(ast);
730
731
2.08k
      ZVAL_COPY(result, zv);
732
2.08k
      break;
733
9
    }
734
498
    case ZEND_AST_CONSTANT:
735
498
    {
736
498
      zend_string *name = zend_ast_get_constant_name(ast);
737
498
      zval *zv = zend_get_constant_ex(name, scope, ast->attr);
738
739
498
      if (UNEXPECTED(zv == NULL)) {
740
93
        ZVAL_UNDEF(result);
741
93
        return FAILURE;
742
93
      }
743
405
      ZVAL_COPY_OR_DUP(result, zv);
744
405
      break;
745
498
    }
746
12
    case ZEND_AST_CONSTANT_CLASS:
747
12
      if (scope) {
748
12
        ZVAL_STR_COPY(result, scope->name);
749
12
      } else {
750
0
        ZVAL_EMPTY_STRING(result);
751
0
      }
752
12
      break;
753
42
    case ZEND_AST_CLASS_NAME:
754
42
      if (!scope) {
755
3
        zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active");
756
3
        return FAILURE;
757
3
      }
758
39
      if (ast->attr == ZEND_FETCH_CLASS_SELF) {
759
39
        ZVAL_STR_COPY(result, scope->name);
760
39
      } else if (ast->attr == ZEND_FETCH_CLASS_PARENT) {
761
0
        if (!scope->parent) {
762
0
          zend_throw_error(NULL,
763
0
            "Cannot use \"parent\" when current class scope has no parent");
764
0
          return FAILURE;
765
0
        }
766
0
        ZVAL_STR_COPY(result, scope->parent->name);
767
0
      } else {
768
0
        ZEND_ASSERT(0 && "Should have errored during compilation");
769
0
      }
770
39
      break;
771
39
    case ZEND_AST_AND:
772
12
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
773
0
        ret = FAILURE;
774
0
        break;
775
0
      }
776
12
      if (zend_is_true(&op1)) {
777
9
        if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
778
0
          zval_ptr_dtor_nogc(&op1);
779
0
          ret = FAILURE;
780
0
          break;
781
0
        }
782
9
        ZVAL_BOOL(result, zend_is_true(&op2));
783
9
        zval_ptr_dtor_nogc(&op2);
784
9
      } else {
785
3
        ZVAL_FALSE(result);
786
3
      }
787
12
      zval_ptr_dtor_nogc(&op1);
788
12
      break;
789
78
    case ZEND_AST_CAST:
790
78
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
791
3
        ret = FAILURE;
792
3
        break;
793
3
      }
794
75
      if (ast->attr == Z_TYPE(op1)) {
795
0
        ZVAL_COPY_VALUE(result, &op1);
796
75
      } else {
797
75
        switch (ast->attr) {
798
6
          case _IS_BOOL:
799
6
            ZVAL_BOOL(result, zend_is_true(&op1));
800
6
            break;
801
15
          case IS_LONG:
802
15
            ZVAL_LONG(result, zval_get_long_func(&op1, false));
803
15
            break;
804
3
          case IS_DOUBLE:
805
3
            ZVAL_DOUBLE(result, zval_get_double_func(&op1));
806
3
            break;
807
12
          case IS_STRING:
808
12
            ZVAL_STR(result, zval_get_string_func(&op1));
809
12
            break;
810
30
          case IS_ARRAY:
811
30
            zend_cast_zval_to_array(result, &op1, IS_VAR);
812
30
            break;
813
9
          case IS_OBJECT:
814
9
            zend_cast_zval_to_object(result, &op1, IS_VAR);
815
9
            break;
816
0
          default: ZEND_UNREACHABLE();
817
75
        }
818
75
        zval_ptr_dtor_nogc(&op1);
819
75
        if (UNEXPECTED(EG(exception))) {
820
0
          ret = FAILURE;
821
0
        }
822
75
      }
823
75
      break;
824
75
    case ZEND_AST_OR:
825
6
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
826
0
        ret = FAILURE;
827
0
        break;
828
0
      }
829
6
      if (zend_is_true(&op1)) {
830
3
        ZVAL_TRUE(result);
831
3
      } else {
832
3
        if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
833
0
          zval_ptr_dtor_nogc(&op1);
834
0
          ret = FAILURE;
835
0
          break;
836
0
        }
837
3
        ZVAL_BOOL(result, zend_is_true(&op2));
838
3
        zval_ptr_dtor_nogc(&op2);
839
3
      }
840
6
      zval_ptr_dtor_nogc(&op1);
841
6
      break;
842
30
    case ZEND_AST_CONDITIONAL:
843
30
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
844
0
        ret = FAILURE;
845
0
        break;
846
0
      }
847
30
      if (zend_is_true(&op1)) {
848
24
        if (!ast->child[1]) {
849
9
          *result = op1;
850
15
        } else {
851
15
          if (UNEXPECTED(zend_ast_evaluate_ex(result, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
852
3
            zval_ptr_dtor_nogc(&op1);
853
3
            ret = FAILURE;
854
3
            break;
855
3
          }
856
12
          zval_ptr_dtor_nogc(&op1);
857
12
        }
858
24
      } else {
859
6
        if (UNEXPECTED(zend_ast_evaluate_ex(result, ast->child[2], scope, &short_circuited, ctx) != SUCCESS)) {
860
0
          zval_ptr_dtor_nogc(&op1);
861
0
          ret = FAILURE;
862
0
          break;
863
0
        }
864
6
        zval_ptr_dtor_nogc(&op1);
865
6
      }
866
27
      break;
867
48
    case ZEND_AST_COALESCE:
868
48
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
869
0
        ret = FAILURE;
870
0
        break;
871
0
      }
872
48
      if (Z_TYPE(op1) > IS_NULL) {
873
0
        *result = op1;
874
48
      } else {
875
48
        if (UNEXPECTED(zend_ast_evaluate_ex(result, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
876
0
          zval_ptr_dtor_nogc(&op1);
877
0
          ret = FAILURE;
878
0
          break;
879
0
        }
880
48
        zval_ptr_dtor_nogc(&op1);
881
48
      }
882
48
      break;
883
48
    case ZEND_AST_UNARY_PLUS:
884
9
      if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
885
0
        ret = FAILURE;
886
9
      } else {
887
9
        ZVAL_LONG(&op1, 0);
888
9
        ret = add_function(result, &op1, &op2);
889
9
        zval_ptr_dtor_nogc(&op2);
890
9
      }
891
9
      break;
892
9
    case ZEND_AST_UNARY_MINUS:
893
9
      if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
894
3
        ret = FAILURE;
895
6
      } else {
896
6
        ZVAL_LONG(&op1, -1);
897
6
        ret = mul_function(result, &op1, &op2);
898
6
        zval_ptr_dtor_nogc(&op2);
899
6
      }
900
9
      break;
901
279
    case ZEND_AST_ARRAY:
902
279
      {
903
279
        uint32_t i;
904
279
        zend_ast_list *list = zend_ast_get_list(ast);
905
906
279
        if (!list->children) {
907
0
          ZVAL_EMPTY_ARRAY(result);
908
0
          break;
909
0
        }
910
279
        array_init(result);
911
528
        for (i = 0; i < list->children; i++) {
912
348
          zend_ast *elem = list->child[i];
913
348
          if (elem->kind == ZEND_AST_UNPACK) {
914
27
            if (UNEXPECTED(zend_ast_evaluate_ex(&op1, elem->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
915
12
              zval_ptr_dtor_nogc(result);
916
12
              return FAILURE;
917
12
            }
918
15
            if (UNEXPECTED(zend_ast_add_unpacked_element(result, &op1) != SUCCESS)) {
919
9
              zval_ptr_dtor_nogc(&op1);
920
9
              zval_ptr_dtor_nogc(result);
921
9
              return FAILURE;
922
9
            }
923
6
            zval_ptr_dtor_nogc(&op1);
924
6
            continue;
925
15
          }
926
321
          if (elem->child[1]) {
927
231
            if (UNEXPECTED(zend_ast_evaluate_ex(&op1, elem->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
928
24
              zval_ptr_dtor_nogc(result);
929
24
              return FAILURE;
930
24
            }
931
231
          } else {
932
90
            ZVAL_UNDEF(&op1);
933
90
          }
934
297
          if (UNEXPECTED(zend_ast_evaluate_ex(&op2, elem->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
935
45
            zval_ptr_dtor_nogc(&op1);
936
45
            zval_ptr_dtor_nogc(result);
937
45
            return FAILURE;
938
45
          }
939
252
          if (UNEXPECTED(zend_ast_add_array_element(result, &op1, &op2) != SUCCESS)) {
940
9
            zval_ptr_dtor_nogc(&op1);
941
9
            zval_ptr_dtor_nogc(&op2);
942
9
            zval_ptr_dtor_nogc(result);
943
9
            return FAILURE;
944
9
          }
945
252
        }
946
279
      }
947
180
      break;
948
180
    case ZEND_AST_DIM:
949
180
      if (ast->child[1] == NULL) {
950
0
        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
951
0
      }
952
953
180
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
954
0
        ret = FAILURE;
955
0
        break;
956
0
      }
957
180
      if (short_circuited) {
958
3
        *short_circuited_ptr = true;
959
3
        ZVAL_NULL(result);
960
3
        return SUCCESS;
961
3
      }
962
963
      // DIM on objects is disallowed because it allows executing arbitrary expressions
964
177
      if (Z_TYPE(op1) == IS_OBJECT) {
965
3
        zval_ptr_dtor_nogc(&op1);
966
3
        zend_throw_error(NULL, "Cannot use [] on objects in constant expression");
967
3
        ret = FAILURE;
968
3
        break;
969
3
      }
970
971
174
      if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
972
0
        zval_ptr_dtor_nogc(&op1);
973
0
        ret = FAILURE;
974
0
        break;
975
0
      }
976
977
174
      zend_fetch_dimension_const(result, &op1, &op2, (ast->attr & ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
978
979
174
      zval_ptr_dtor_nogc(&op1);
980
174
      zval_ptr_dtor_nogc(&op2);
981
174
      if (UNEXPECTED(EG(exception))) {
982
3
        return FAILURE;
983
3
      }
984
985
171
      break;
986
957
    case ZEND_AST_CONST_ENUM_INIT:
987
957
    {
988
      // Preloading will attempt to resolve constants but objects can't be stored in shm
989
      // Aborting here to store the const AST instead
990
957
      if (CG(in_compilation)) {
991
0
        return FAILURE;
992
0
      }
993
994
957
      zend_ast *class_name_ast = ast->child[0];
995
957
      zend_string *class_name = zend_ast_get_str(class_name_ast);
996
997
957
      zend_ast *case_id_ast = ast->child[1];
998
957
      int case_id = (int)Z_LVAL_P(zend_ast_get_zval(case_id_ast));
999
1000
957
      zend_ast *case_name_ast = ast->child[2];
1001
957
      zend_string *case_name = zend_ast_get_str(case_name_ast);
1002
1003
957
      zend_ast *case_value_ast = ast->child[3];
1004
1005
957
      zval case_value_zv;
1006
957
      ZVAL_UNDEF(&case_value_zv);
1007
957
      if (case_value_ast != NULL) {
1008
435
        if (UNEXPECTED(zend_ast_evaluate_ex(&case_value_zv, case_value_ast, scope, &short_circuited, ctx) != SUCCESS)) {
1009
6
          return FAILURE;
1010
6
        }
1011
435
      }
1012
1013
951
      zend_class_entry *ce = zend_lookup_class(class_name);
1014
951
      zend_enum_new(result, ce, case_id, case_name, case_value_ast != NULL ? &case_value_zv : NULL);
1015
951
      zval_ptr_dtor_nogc(&case_value_zv);
1016
951
      break;
1017
957
    }
1018
861
    case ZEND_AST_CLASS_CONST:
1019
861
    {
1020
861
      zend_string *class_name = zend_ast_get_str(ast->child[0]);
1021
861
      if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
1022
3
        return FAILURE;
1023
3
      }
1024
858
      if (UNEXPECTED(Z_TYPE(op2) != IS_STRING)) {
1025
3
        zend_invalid_class_constant_type_error(Z_TYPE(op2));
1026
3
        zval_ptr_dtor_nogc(&op2);
1027
3
        return FAILURE;
1028
3
      }
1029
855
      zend_string *const_name = Z_STR(op2);
1030
1031
855
      zend_string *previous_filename;
1032
855
      zend_long previous_lineno;
1033
855
      if (scope) {
1034
762
        previous_filename = EG(filename_override);
1035
762
        previous_lineno = EG(lineno_override);
1036
762
        EG(filename_override) = scope->info.user.filename;
1037
762
        EG(lineno_override) = zend_ast_get_lineno(ast);
1038
762
      }
1039
855
      zval *zv = zend_get_class_constant_ex(class_name, const_name, scope, ast->attr);
1040
855
      if (scope) {
1041
753
        EG(filename_override) = previous_filename;
1042
753
        EG(lineno_override) = previous_lineno;
1043
753
      }
1044
1045
855
      if (UNEXPECTED(zv == NULL)) {
1046
108
        ZVAL_UNDEF(result);
1047
108
        zval_ptr_dtor_nogc(&op2);
1048
108
        return FAILURE;
1049
108
      }
1050
747
      ZVAL_COPY_OR_DUP(result, zv);
1051
747
      zval_ptr_dtor_nogc(&op2);
1052
747
      break;
1053
855
    }
1054
186
    case ZEND_AST_NEW:
1055
186
    {
1056
186
      zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
1057
186
      if (!ce) {
1058
12
        return FAILURE;
1059
12
      }
1060
1061
174
      if (object_init_ex(result, ce) != SUCCESS) {
1062
0
        return FAILURE;
1063
0
      }
1064
1065
      /* Even if there is no constructor, the object can have cause side-effects in various ways (__toString(), __get(), __isset(), etc). */
1066
174
      ctx->had_side_effects = true;
1067
1068
174
      zend_ast_list *args_ast = zend_ast_get_list(ast->child[1]);
1069
174
      if (args_ast->attr) {
1070
        /* Has named arguments. */
1071
9
        HashTable *args = zend_new_array(args_ast->children);
1072
15
        for (uint32_t i = 0; i < args_ast->children; i++) {
1073
9
          zend_ast *arg_ast = args_ast->child[i];
1074
9
          zend_string *name = NULL;
1075
9
          zval arg;
1076
9
          if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
1077
9
            name = zend_ast_get_str(arg_ast->child[0]);
1078
9
            arg_ast = arg_ast->child[1];
1079
9
          }
1080
9
          if (zend_ast_evaluate_ex(&arg, arg_ast, scope, &short_circuited, ctx) == FAILURE) {
1081
3
            zend_array_destroy(args);
1082
3
            zval_ptr_dtor(result);
1083
3
            return FAILURE;
1084
3
          }
1085
6
          if (name) {
1086
6
            if (!zend_hash_add(args, name, &arg)) {
1087
0
              zend_throw_error(NULL,
1088
0
                "Named parameter $%s overwrites previous argument",
1089
0
                ZSTR_VAL(name));
1090
0
              zend_array_destroy(args);
1091
0
              zval_ptr_dtor(result);
1092
0
              return FAILURE;
1093
0
            }
1094
6
          } else {
1095
0
            zend_hash_next_index_insert(args, &arg);
1096
0
          }
1097
6
        }
1098
1099
6
        zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
1100
6
        if (ctor) {
1101
3
          zend_call_known_function(
1102
3
            ctor, Z_OBJ_P(result), Z_OBJCE_P(result), NULL, 0, NULL, args);
1103
3
        }
1104
1105
6
        zend_array_destroy(args);
1106
165
      } else {
1107
165
        ALLOCA_FLAG(use_heap)
1108
165
        zval *args = do_alloca(sizeof(zval) * args_ast->children, use_heap);
1109
201
        for (uint32_t i = 0; i < args_ast->children; i++) {
1110
45
          if (zend_ast_evaluate_ex(&args[i], args_ast->child[i], scope, &short_circuited, ctx) == FAILURE) {
1111
9
            for (uint32_t j = 0; j < i; j++) {
1112
0
              zval_ptr_dtor(&args[j]);
1113
0
            }
1114
9
            free_alloca(args, use_heap);
1115
9
            zval_ptr_dtor(result);
1116
9
            return FAILURE;
1117
9
          }
1118
45
        }
1119
1120
156
        zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
1121
156
        if (ctor) {
1122
57
          zend_call_known_instance_method(
1123
57
            ctor, Z_OBJ_P(result), NULL, args_ast->children, args);
1124
57
        }
1125
1126
192
        for (uint32_t i = 0; i < args_ast->children; i++) {
1127
36
          zval_ptr_dtor(&args[i]);
1128
36
        }
1129
156
        free_alloca(args, use_heap);
1130
156
      }
1131
1132
162
      if (EG(exception)) {
1133
3
        zend_object_store_ctor_failed(Z_OBJ_P(result));
1134
3
        zval_ptr_dtor(result);
1135
3
        return FAILURE;
1136
3
      }
1137
159
      return SUCCESS;
1138
162
    }
1139
72
    case ZEND_AST_CALL:
1140
120
    case ZEND_AST_STATIC_CALL:
1141
120
    {
1142
120
      zend_function *fptr;
1143
120
      zend_class_entry *called_scope = NULL;
1144
1145
120
      zend_ast *args_ast = zend_ast_call_get_args(ast);
1146
120
      ZEND_ASSERT(args_ast->kind == ZEND_AST_CALLABLE_CONVERT);
1147
1148
120
      zend_ast_fcc *fcc_ast = (zend_ast_fcc*)args_ast;
1149
1150
120
      zend_ast_list *args = zend_ast_get_list(fcc_ast->args);
1151
120
      ZEND_ASSERT(args->children > 0);
1152
120
      if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) {
1153
        /* TODO: PFAs */
1154
0
        zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations");
1155
0
      }
1156
1157
120
      switch (ast->kind) {
1158
72
        case ZEND_AST_CALL: {
1159
72
          fptr = ZEND_MAP_PTR_GET(fcc_ast->fptr);
1160
1161
72
          if (!fptr) {
1162
69
            zend_string *function_name = zend_ast_get_str(ast->child[0]);
1163
69
            zend_string *function_name_lc = zend_string_tolower(function_name);
1164
69
            fptr = zend_fetch_function(function_name_lc);
1165
69
            if (!fptr && ast->child[0]->attr != ZEND_NAME_FQ) {
1166
15
              const char *backslash = zend_memrchr(ZSTR_VAL(function_name_lc), '\\', ZSTR_LEN(function_name_lc));
1167
15
              if (backslash) {
1168
12
                fptr = zend_fetch_function_str(backslash + 1, ZSTR_LEN(function_name_lc) - (backslash - ZSTR_VAL(function_name_lc) + 1));
1169
12
              }
1170
15
            }
1171
69
            zend_string_release(function_name_lc);
1172
69
            if (!fptr) {
1173
9
              zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function_name));
1174
9
              return FAILURE;
1175
9
            }
1176
1177
60
            ZEND_MAP_PTR_SET(fcc_ast->fptr, fptr);
1178
60
          }
1179
1180
63
          break;
1181
72
        }
1182
63
        case ZEND_AST_STATIC_CALL: {
1183
48
          zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
1184
48
          if (!ce) {
1185
3
            return FAILURE;
1186
3
          }
1187
45
          called_scope = ce;
1188
1189
45
          fptr = ZEND_MAP_PTR_GET(fcc_ast->fptr);
1190
1191
45
          if (!fptr) {
1192
45
            zend_string *method_name = zend_ast_get_str(ast->child[1]);
1193
45
            if (ce->get_static_method) {
1194
0
              fptr = ce->get_static_method(ce, method_name);
1195
45
            } else {
1196
45
              fptr = zend_hash_find_ptr_lc(&ce->function_table, method_name);
1197
45
              if (fptr) {
1198
39
                if (!zend_check_method_accessible(fptr, scope)) {
1199
6
                  if (ce->__callstatic) {
1200
0
                    zend_throw_error(NULL, "Creating a callable for the magic __callStatic() method is not supported in constant expressions");
1201
6
                  } else {
1202
6
                    zend_bad_method_call(fptr, method_name, scope);
1203
6
                  }
1204
1205
6
                  return FAILURE;
1206
6
                }
1207
39
              } else {
1208
6
                if (ce->__callstatic) {
1209
3
                  zend_throw_error(NULL, "Creating a callable for the magic __callStatic() method is not supported in constant expressions");
1210
3
                } else {
1211
3
                  zend_undefined_method(ce, method_name);
1212
3
                }
1213
1214
6
                return FAILURE;
1215
6
              }
1216
45
            }
1217
1218
33
            if (!(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
1219
3
              zend_non_static_method_call(fptr);
1220
1221
3
              return FAILURE;
1222
3
            }
1223
30
            if ((fptr->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1224
3
              zend_abstract_method_call(fptr);
1225
1226
3
              return FAILURE;
1227
27
            } else if (fptr->common.scope->ce_flags & ZEND_ACC_TRAIT) {
1228
3
              zend_error(E_DEPRECATED,
1229
3
                "Calling static trait method %s::%s is deprecated, "
1230
3
                "it should only be called on a class using the trait",
1231
3
                ZSTR_VAL(fptr->common.scope->name), ZSTR_VAL(fptr->common.function_name));
1232
3
              if (EG(exception)) {
1233
0
                return FAILURE;
1234
0
              }
1235
3
            }
1236
1237
27
            ZEND_MAP_PTR_SET(fcc_ast->fptr, fptr);
1238
27
          }
1239
1240
27
          break;
1241
45
        }
1242
27
        default: ZEND_UNREACHABLE();
1243
120
      }
1244
1245
90
      zend_create_fake_closure(result, fptr, fptr->common.scope, called_scope, NULL);
1246
1247
90
      return SUCCESS;
1248
120
    }
1249
42
    case ZEND_AST_OP_ARRAY:
1250
42
    {
1251
      // Preloading will attempt to resolve constants but objects can't be stored in shm
1252
      // Aborting here to store the const AST instead
1253
42
      if (CG(in_compilation)) {
1254
0
        return FAILURE;
1255
0
      }
1256
1257
42
      zend_function *func = (zend_function *)zend_ast_get_op_array(ast)->op_array;
1258
1259
42
      zend_create_closure(result, func, scope, scope, NULL);
1260
42
      return SUCCESS;
1261
42
    }
1262
90
    case ZEND_AST_PROP:
1263
168
    case ZEND_AST_NULLSAFE_PROP:
1264
168
    {
1265
168
      if (UNEXPECTED(zend_ast_evaluate_ex(&op1, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) {
1266
3
        return FAILURE;
1267
3
      }
1268
165
      if (short_circuited) {
1269
3
        *short_circuited_ptr = true;
1270
3
        ZVAL_NULL(result);
1271
3
        return SUCCESS;
1272
3
      }
1273
162
      if (ast->kind == ZEND_AST_NULLSAFE_PROP && Z_TYPE(op1) == IS_NULL) {
1274
24
        *short_circuited_ptr = true;
1275
24
        ZVAL_NULL(result);
1276
24
        return SUCCESS;
1277
24
      }
1278
1279
138
      if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) {
1280
3
        zval_ptr_dtor_nogc(&op1);
1281
3
        return FAILURE;
1282
3
      }
1283
1284
135
      if (!try_convert_to_string(&op2)) {
1285
3
        zval_ptr_dtor_nogc(&op1);
1286
3
        zval_ptr_dtor_nogc(&op2);
1287
3
        return FAILURE;
1288
3
      }
1289
1290
132
      if (Z_TYPE(op1) != IS_OBJECT) {
1291
18
        zend_wrong_property_read(&op1, &op2);
1292
1293
18
        zval_ptr_dtor_nogc(&op1);
1294
18
        zval_ptr_dtor_nogc(&op2);
1295
1296
18
        ZVAL_NULL(result);
1297
18
        return SUCCESS;
1298
18
      }
1299
1300
114
      zend_object *zobj = Z_OBJ(op1);
1301
114
      if (!(zobj->ce->ce_flags & ZEND_ACC_ENUM)) {
1302
15
        zend_throw_error(NULL, "Fetching properties on non-enums in constant expressions is not allowed");
1303
15
        zval_ptr_dtor_nogc(&op1);
1304
15
        zval_ptr_dtor_nogc(&op2);
1305
15
        return FAILURE;
1306
15
      }
1307
1308
99
      zend_string *name = Z_STR(op2);
1309
99
      zval *property_result = zend_read_property_ex(scope, zobj, name, 0, result);
1310
99
      if (EG(exception)) {
1311
0
        zval_ptr_dtor_nogc(&op1);
1312
0
        zval_ptr_dtor_nogc(&op2);
1313
0
        return FAILURE;
1314
0
      }
1315
1316
99
      if (result != property_result) {
1317
99
        ZVAL_COPY(result, property_result);
1318
99
      }
1319
99
      zval_ptr_dtor_nogc(&op1);
1320
99
      zval_ptr_dtor_nogc(&op2);
1321
99
      return SUCCESS;
1322
99
    }
1323
0
    default:
1324
0
      zend_throw_error(NULL, "Unsupported constant expression");
1325
0
      ret = FAILURE;
1326
5.92k
  }
1327
5.08k
  return ret;
1328
5.92k
}
1329
1330
ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
1331
0
{
1332
0
  zend_ast_evaluate_ctx ctx = {0};
1333
0
  bool short_circuited;
1334
0
  return zend_ast_evaluate_ex(result, ast, scope, &short_circuited, &ctx);
1335
0
}
1336
1337
static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
1338
10.6k
{
1339
10.6k
  size_t size;
1340
1341
10.6k
  if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
1342
6.55k
    size = sizeof(zend_ast_zval);
1343
6.55k
  } else if (ast->kind == ZEND_AST_OP_ARRAY) {
1344
38
    size = sizeof(zend_ast_op_array);
1345
4.10k
  } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
1346
119
    zend_ast *args_ast = ((zend_ast_fcc*)ast)->args;
1347
119
    size = sizeof(zend_ast_fcc) + zend_ast_tree_size(args_ast);
1348
3.98k
  } else if (zend_ast_is_list(ast)) {
1349
653
    uint32_t i;
1350
653
    const zend_ast_list *list = zend_ast_get_list(ast);
1351
1352
653
    size = zend_ast_list_size(list->children);
1353
1.34k
    for (i = 0; i < list->children; i++) {
1354
691
      if (list->child[i]) {
1355
691
        size += zend_ast_tree_size(list->child[i]);
1356
691
      }
1357
691
    }
1358
3.32k
  } else if (zend_ast_is_decl(ast)) {
1359
    /* Not implemented. */
1360
0
    ZEND_UNREACHABLE();
1361
3.32k
  } else {
1362
3.32k
    uint32_t i, children = zend_ast_get_num_children(ast);
1363
1364
3.32k
    size = zend_ast_size(children);
1365
11.3k
    for (i = 0; i < children; i++) {
1366
8.02k
      if (ast->child[i]) {
1367
7.30k
        size += zend_ast_tree_size(ast->child[i]);
1368
7.30k
      }
1369
8.02k
    }
1370
3.32k
  }
1371
10.6k
  return size;
1372
10.6k
}
1373
1374
static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
1375
10.6k
{
1376
10.6k
  if (ast->kind == ZEND_AST_ZVAL) {
1377
5.57k
    zend_ast_zval *new = (zend_ast_zval*)buf;
1378
5.57k
    new->kind = ZEND_AST_ZVAL;
1379
5.57k
    new->attr = ast->attr;
1380
5.57k
    ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
1381
5.57k
    Z_LINENO(new->val) = zend_ast_get_lineno(ast);
1382
5.57k
    buf = (void*)((char*)buf + sizeof(zend_ast_zval));
1383
5.57k
  } else if (ast->kind == ZEND_AST_CONSTANT) {
1384
982
    zend_ast_zval *new = (zend_ast_zval*)buf;
1385
982
    new->kind = ZEND_AST_CONSTANT;
1386
982
    new->attr = ast->attr;
1387
982
    ZVAL_STR_COPY(&new->val, zend_ast_get_constant_name(ast));
1388
982
    Z_LINENO(new->val) = zend_ast_get_lineno(ast);
1389
982
    buf = (void*)((char*)buf + sizeof(zend_ast_zval));
1390
4.13k
  } else if (zend_ast_is_list(ast)) {
1391
653
    const zend_ast_list *list = zend_ast_get_list(ast);
1392
653
    zend_ast_list *new = (zend_ast_list*)buf;
1393
653
    uint32_t i;
1394
653
    new->kind = list->kind;
1395
653
    new->attr = list->attr;
1396
653
    new->children = list->children;
1397
653
    new->lineno = list->lineno;
1398
653
    buf = (void*)((char*)buf + zend_ast_list_size(list->children));
1399
1.34k
    for (i = 0; i < list->children; i++) {
1400
691
      if (list->child[i]) {
1401
691
        new->child[i] = (zend_ast*)buf;
1402
691
        buf = zend_ast_tree_copy(list->child[i], buf);
1403
691
      } else {
1404
0
        new->child[i] = NULL;
1405
0
      }
1406
691
    }
1407
3.48k
  } else if (ast->kind == ZEND_AST_OP_ARRAY) {
1408
38
    const zend_ast_op_array *old = zend_ast_get_op_array(ast);
1409
38
    zend_ast_op_array *new = (zend_ast_op_array*)buf;
1410
38
    new->kind = old->kind;
1411
38
    new->attr = old->attr;
1412
38
    new->lineno = old->lineno;
1413
38
    new->op_array = old->op_array;
1414
38
    function_add_ref((zend_function *)new->op_array);
1415
38
    buf = (void*)((char*)buf + sizeof(zend_ast_op_array));
1416
3.44k
  } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
1417
119
    const zend_ast_fcc *old = (zend_ast_fcc*)ast;
1418
119
    zend_ast_fcc *new = (zend_ast_fcc*)buf;
1419
119
    new->kind = old->kind;
1420
119
    new->attr = old->attr;
1421
119
    new->lineno = old->lineno;
1422
119
    ZEND_MAP_PTR_INIT(new->fptr, ZEND_MAP_PTR(old->fptr));
1423
119
    buf = (void*)((char*)buf + sizeof(zend_ast_fcc));
1424
119
    new->args = buf;
1425
119
    buf = zend_ast_tree_copy(old->args, buf);
1426
3.32k
  } else if (zend_ast_is_decl(ast)) {
1427
    /* Not implemented. */
1428
0
    ZEND_UNREACHABLE();
1429
3.32k
  } else {
1430
3.32k
    uint32_t i, children = zend_ast_get_num_children(ast);
1431
3.32k
    zend_ast *new = (zend_ast*)buf;
1432
3.32k
    new->kind = ast->kind;
1433
3.32k
    new->attr = ast->attr;
1434
3.32k
    new->lineno = ast->lineno;
1435
3.32k
    buf = (void*)((char*)buf + zend_ast_size(children));
1436
11.3k
    for (i = 0; i < children; i++) {
1437
8.02k
      if (ast->child[i]) {
1438
7.30k
        new->child[i] = (zend_ast*)buf;
1439
7.30k
        buf = zend_ast_tree_copy(ast->child[i], buf);
1440
7.30k
      } else {
1441
722
        new->child[i] = NULL;
1442
722
      }
1443
8.02k
    }
1444
3.32k
  }
1445
10.6k
  return buf;
1446
10.6k
}
1447
1448
ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast)
1449
2.58k
{
1450
2.58k
  size_t tree_size;
1451
2.58k
  zend_ast_ref *ref;
1452
1453
2.58k
  ZEND_ASSERT(ast != NULL);
1454
2.58k
  tree_size = zend_ast_tree_size(ast) + sizeof(zend_ast_ref);
1455
2.58k
  ref = emalloc(tree_size);
1456
2.58k
  zend_ast_tree_copy(ast, GC_AST(ref));
1457
2.58k
  GC_SET_REFCOUNT(ref, 1);
1458
2.58k
  GC_TYPE_INFO(ref) = GC_CONSTANT_AST;
1459
2.58k
  return ref;
1460
2.58k
}
1461
1462
ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
1463
1.58M
{
1464
3.12M
tail_call:
1465
3.12M
  if (!ast) {
1466
434k
    return;
1467
434k
  }
1468
1469
2.68M
  if (EXPECTED(ast->kind >= ZEND_AST_VAR)) {
1470
1.19M
    uint32_t i, children = zend_ast_get_num_children(ast);
1471
1472
1.98M
    for (i = 1; i < children; i++) {
1473
789k
      zend_ast_destroy(ast->child[i]);
1474
789k
    }
1475
1.19M
    ast = ast->child[0];
1476
1.19M
    goto tail_call;
1477
1.49M
  } else if (EXPECTED(ast->kind == ZEND_AST_ZVAL)) {
1478
1.06M
    zval_ptr_dtor_nogc(zend_ast_get_zval(ast));
1479
1.06M
  } else if (EXPECTED(zend_ast_is_list(ast))) {
1480
389k
    const zend_ast_list *list = zend_ast_get_list(ast);
1481
389k
    if (list->children) {
1482
311k
      uint32_t i;
1483
1484
866k
      for (i = 1; i < list->children; i++) {
1485
554k
        zend_ast_destroy(list->child[i]);
1486
554k
      }
1487
311k
      ast = list->child[0];
1488
311k
      goto tail_call;
1489
311k
    }
1490
389k
  } else if (EXPECTED(ast->kind == ZEND_AST_CONSTANT)) {
1491
1.01k
    zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
1492
45.2k
  } else if (EXPECTED(ast->kind == ZEND_AST_OP_ARRAY)) {
1493
38
    destroy_op_array(zend_ast_get_op_array(ast)->op_array);
1494
45.2k
  } else if (EXPECTED(zend_ast_is_decl(ast))) {
1495
38.2k
    const zend_ast_decl *decl = (const zend_ast_decl *) ast;
1496
1497
38.2k
    if (decl->name) {
1498
33.8k
        zend_string_release_ex(decl->name, 0);
1499
33.8k
    }
1500
38.2k
    if (decl->doc_comment) {
1501
57
      zend_string_release_ex(decl->doc_comment, 0);
1502
57
    }
1503
38.2k
    zend_ast_destroy(decl->child[0]);
1504
38.2k
    zend_ast_destroy(decl->child[1]);
1505
38.2k
    zend_ast_destroy(decl->child[2]);
1506
38.2k
    zend_ast_destroy(decl->child[3]);
1507
38.2k
    ast = decl->child[4];
1508
38.2k
    goto tail_call;
1509
38.2k
  } else if (EXPECTED(ast->kind == ZEND_AST_CALLABLE_CONVERT)) {
1510
576
    zend_ast_fcc *fcc_ast = (zend_ast_fcc*) ast;
1511
1512
576
    ast = fcc_ast->args;
1513
576
    goto tail_call;
1514
576
  }
1515
2.68M
}
1516
1517
ZEND_API void ZEND_FASTCALL zend_ast_ref_destroy(zend_ast_ref *ast)
1518
113
{
1519
113
  zend_ast_destroy(GC_AST(ast));
1520
113
  efree(ast);
1521
113
}
1522
1523
10.1k
ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn, void *context) {
1524
10.1k
  if (zend_ast_is_list(ast)) {
1525
2.24k
    zend_ast_list *list = zend_ast_get_list(ast);
1526
2.24k
    uint32_t i;
1527
4.85k
    for (i = 0; i < list->children; ++i) {
1528
2.61k
      fn(&list->child[i], context);
1529
2.61k
    }
1530
7.86k
  } else if (zend_ast_is_decl(ast)) {
1531
    /* Not implemented. */
1532
0
    ZEND_UNREACHABLE();
1533
7.86k
  } else {
1534
7.86k
    uint32_t i, children = zend_ast_get_num_children(ast);
1535
21.7k
    for (i = 0; i < children; ++i) {
1536
13.8k
      fn(&ast->child[i], context);
1537
13.8k
    }
1538
7.86k
  }
1539
10.1k
}
1540
1541
/*
1542
 * Operator Precedence
1543
 * ====================
1544
 * priority  associativity  operators
1545
 * ----------------------------------
1546
 *   10     left            include, include_once, eval, require, require_once
1547
 *   20     left            ,
1548
 *   30     left            or
1549
 *   40     left            xor
1550
 *   50     left            and
1551
 *   60     right           print
1552
 *   70     right           yield
1553
 *   80     right           =>
1554
 *   85     right           yield from
1555
 *   90     right           = += -= *= /= .= %= &= |= ^= <<= >>= **=
1556
 *  100     left            ? :
1557
 *  110     right           ??
1558
 *  120     left            ||
1559
 *  130     left            &&
1560
 *  140     left            |
1561
 *  150     left            ^
1562
 *  160     left            &
1563
 *  170     non-associative == != === !==
1564
 *  180     non-associative < <= > >= <=>
1565
 *  185     left            .
1566
 *  190     left            << >>
1567
 *  200     left            + -
1568
 *  210     left            * / %
1569
 *  220     right           !
1570
 *  230     non-associative instanceof
1571
 *  240     right           + - ++ -- ~ (type) @
1572
 *  250     right           **
1573
 *  260     left            [
1574
 *  270     non-associative clone new
1575
 */
1576
1577
static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent);
1578
1579
static ZEND_COLD void zend_ast_export_str(smart_str *str, const zend_string *s)
1580
207
{
1581
207
  size_t i;
1582
1583
1.71k
  for (i = 0; i < ZSTR_LEN(s); i++) {
1584
1.50k
    unsigned char c = ZSTR_VAL(s)[i];
1585
1.50k
    if (c == '\'' || c == '\\') {
1586
32
      smart_str_appendc(str, '\\');
1587
32
      smart_str_appendc(str, c);
1588
1.47k
    } else {
1589
1.47k
      smart_str_appendc(str, c);
1590
1.47k
    }
1591
1.50k
  }
1592
207
}
1593
1594
static ZEND_COLD void zend_ast_export_qstr(smart_str *str, char quote, const zend_string *s)
1595
16.1k
{
1596
16.1k
  size_t i;
1597
1598
88.2k
  for (i = 0; i < ZSTR_LEN(s); i++) {
1599
72.0k
    unsigned char c = ZSTR_VAL(s)[i];
1600
72.0k
    if (c < ' ') {
1601
18.5k
      switch (c) {
1602
772
        case '\n':
1603
772
          smart_str_appends(str, "\\n");
1604
772
          break;
1605
113
        case '\r':
1606
113
          smart_str_appends(str, "\\r");
1607
113
          break;
1608
74
        case '\t':
1609
74
          smart_str_appends(str, "\\t");
1610
74
          break;
1611
74
        case '\f':
1612
74
          smart_str_appends(str, "\\f");
1613
74
          break;
1614
91
        case '\v':
1615
91
          smart_str_appends(str, "\\v");
1616
91
          break;
1617
#ifdef ZEND_WIN32
1618
        case VK_ESCAPE:
1619
#else
1620
6
        case '\e':
1621
6
#endif
1622
6
          smart_str_appends(str, "\\e");
1623
6
          break;
1624
17.4k
        default:
1625
17.4k
          smart_str_appends(str, "\\0");
1626
17.4k
          smart_str_appendc(str, '0' + (c / 8));
1627
17.4k
          smart_str_appendc(str, '0' + (c % 8));
1628
17.4k
          break;
1629
18.5k
      }
1630
53.4k
    } else {
1631
53.4k
      if (c == quote || c == '$' || c == '\\') {
1632
772
        smart_str_appendc(str, '\\');
1633
772
      }
1634
53.4k
      smart_str_appendc(str, c);
1635
53.4k
    }
1636
72.0k
  }
1637
16.1k
}
1638
1639
static ZEND_COLD void zend_ast_export_indent(smart_str *str, int indent)
1640
1.74k
{
1641
4.73k
  while (indent > 0) {
1642
2.99k
    smart_str_appends(str, "    ");
1643
2.99k
    indent--;
1644
2.99k
  }
1645
1.74k
}
1646
1647
static ZEND_COLD void zend_ast_export_name(smart_str *str, zend_ast *ast, int priority, int indent)
1648
452
{
1649
452
  if (ast->kind == ZEND_AST_ZVAL) {
1650
366
    const zval *zv = zend_ast_get_zval(ast);
1651
1652
366
    if (Z_TYPE_P(zv) == IS_STRING) {
1653
366
      smart_str_append(str, Z_STR_P(zv));
1654
366
      return;
1655
366
    }
1656
366
  }
1657
86
  zend_ast_export_ex(str, ast, priority, indent);
1658
86
}
1659
1660
static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int priority, int indent)
1661
1.41k
{
1662
1.41k
  if (ast->kind == ZEND_AST_ZVAL) {
1663
1.24k
    const zval *zv = zend_ast_get_zval(ast);
1664
1665
1.24k
    if (Z_TYPE_P(zv) == IS_STRING) {
1666
1.24k
        if (ast->attr == ZEND_NAME_FQ) {
1667
151
        smart_str_appendc(str, '\\');
1668
1.09k
        } else if (ast->attr == ZEND_NAME_RELATIVE) {
1669
18
        smart_str_appends(str, "namespace\\");
1670
18
        }
1671
1.24k
      smart_str_append(str, Z_STR_P(zv));
1672
1.24k
      return;
1673
1.24k
    }
1674
1.24k
  }
1675
176
  zend_ast_export_ex(str, ast, priority, indent);
1676
176
}
1677
1678
static ZEND_COLD bool zend_ast_valid_var_char(char ch)
1679
9.45k
{
1680
9.45k
  unsigned char c = (unsigned char)ch;
1681
1682
9.45k
  if (c != '_' && c < 127 &&
1683
9.42k
      (c < '0' || c > '9') &&
1684
9.42k
      (c < 'A' || c > 'Z') &&
1685
9.42k
      (c < 'a' || c > 'z')) {
1686
9.41k
    return false;
1687
9.41k
  }
1688
40
  return true;
1689
9.45k
}
1690
1691
static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len)
1692
24.6k
{
1693
24.6k
  unsigned char c;
1694
24.6k
  size_t i;
1695
1696
24.6k
  if (len == 0) {
1697
0
    return false;
1698
0
  }
1699
24.6k
  c = (unsigned char)s[0];
1700
24.6k
  if (c != '_' && c < 127 &&
1701
24.4k
      (c < 'A' || c > 'Z') &&
1702
24.3k
      (c < 'a' || c > 'z')) {
1703
6
    return false;
1704
6
  }
1705
76.1k
  for (i = 1; i < len; i++) {
1706
51.5k
    c = (unsigned char)s[i];
1707
51.5k
    if (c != '_' && c < 127 &&
1708
49.3k
        (c < '0' || c > '9') &&
1709
49.1k
        (c < 'A' || c > 'Z') &&
1710
48.8k
        (c < 'a' || c > 'z')) {
1711
0
      return false;
1712
0
    }
1713
51.5k
  }
1714
24.6k
  return true;
1715
24.6k
}
1716
1717
static ZEND_COLD bool zend_ast_var_needs_braces(char ch)
1718
9.47k
{
1719
9.47k
  return ch == '[' || zend_ast_valid_var_char(ch);
1720
9.47k
}
1721
1722
static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int indent)
1723
24.7k
{
1724
24.7k
  if (ast->kind == ZEND_AST_ZVAL) {
1725
24.6k
    zval *zv = zend_ast_get_zval(ast);
1726
24.6k
    if (Z_TYPE_P(zv) == IS_STRING &&
1727
24.6k
        zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) {
1728
24.6k
      smart_str_append(str, Z_STR_P(zv));
1729
24.6k
      return;
1730
24.6k
    }
1731
24.6k
  } else if (ast->kind == ZEND_AST_VAR) {
1732
12
    zend_ast_export_ex(str, ast, 0, indent);
1733
12
    return;
1734
12
  }
1735
74
  smart_str_appendc(str, '{');
1736
74
  zend_ast_export_name(str, ast, 0, indent);
1737
74
  smart_str_appendc(str, '}');
1738
74
}
1739
1740
/* Use zend_ast_export_list() unless fewer than `list->children` children should
1741
 * be exported. */
1742
static ZEND_COLD void zend_ast_export_list_ex(smart_str *str, const zend_ast_list *list, bool separator, int priority, int indent, uint32_t children)
1743
995
{
1744
995
  ZEND_ASSERT(children <= list->children);
1745
995
  uint32_t i = 0;
1746
1747
1.80k
  while (i < children) {
1748
811
    if (i != 0 && separator) {
1749
268
      smart_str_appends(str, ", ");
1750
268
    }
1751
811
    zend_ast_export_ex(str, list->child[i], priority, indent);
1752
811
    i++;
1753
811
  }
1754
995
}
1755
1756
static ZEND_COLD void zend_ast_export_list(smart_str *str, const zend_ast_list *list, bool separator, int priority, int indent)
1757
995
{
1758
995
  zend_ast_export_list_ex(str, list, separator, priority, indent, list->children);
1759
995
}
1760
1761
static ZEND_COLD void zend_ast_export_encaps_list(smart_str *str, char quote, const zend_ast_list *list, int indent)
1762
163
{
1763
163
  uint32_t i = 0;
1764
163
  zend_ast *ast;
1765
1766
33.1k
  while (i < list->children) {
1767
32.9k
    ast = list->child[i];
1768
32.9k
    if (ast->kind == ZEND_AST_ZVAL) {
1769
16.1k
      const zval *zv = zend_ast_get_zval(ast);
1770
1771
16.1k
      ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
1772
16.1k
      zend_ast_export_qstr(str, quote, Z_STR_P(zv));
1773
16.7k
    } else if (ast->kind == ZEND_AST_VAR &&
1774
9.95k
               ast->child[0]->kind == ZEND_AST_ZVAL &&
1775
9.94k
               (i + 1 == list->children ||
1776
9.92k
                list->child[i + 1]->kind != ZEND_AST_ZVAL ||
1777
9.47k
                !zend_ast_var_needs_braces(
1778
9.47k
                    *Z_STRVAL_P(
1779
9.88k
                        zend_ast_get_zval(list->child[i + 1]))))) {
1780
9.88k
      zend_ast_export_ex(str, ast, 0, indent);
1781
9.88k
    } else {
1782
6.91k
      smart_str_appendc(str, '{');
1783
6.91k
      zend_ast_export_ex(str, ast, 0, indent);
1784
6.91k
      smart_str_appendc(str, '}');
1785
6.91k
    }
1786
32.9k
    i++;
1787
32.9k
  }
1788
163
}
1789
1790
static ZEND_COLD void zend_ast_export_name_list_ex(smart_str *str, const zend_ast_list *list, int indent, const char *separator)
1791
36
{
1792
36
  uint32_t i = 0;
1793
1794
84
  while (i < list->children) {
1795
48
    if (i != 0) {
1796
12
      smart_str_appends(str, separator);
1797
12
    }
1798
48
    zend_ast_export_name(str, list->child[i], 0, indent);
1799
48
    i++;
1800
48
  }
1801
36
}
1802
1803
24
#define zend_ast_export_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, ", ")
1804
12
#define zend_ast_export_catch_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, "|")
1805
1806
static ZEND_COLD void zend_ast_export_var_list(smart_str *str, const zend_ast_list *list, int indent)
1807
18
{
1808
18
  uint32_t i = 0;
1809
1810
54
  while (i < list->children) {
1811
36
    if (i != 0) {
1812
18
      smart_str_appends(str, ", ");
1813
18
    }
1814
36
    if (list->child[i]->attr & ZEND_BIND_REF) {
1815
18
      smart_str_appendc(str, '&');
1816
18
    }
1817
36
    smart_str_appendc(str, '$');
1818
36
    zend_ast_export_name(str, list->child[i], 20, indent);
1819
36
    i++;
1820
36
  }
1821
18
}
1822
1823
static ZEND_COLD void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int indent)
1824
1.50k
{
1825
1.50k
  if (!ast) {
1826
16
    return;
1827
16
  }
1828
1829
1.49k
  if (ast->kind == ZEND_AST_STMT_LIST ||
1830
865
      ast->kind == ZEND_AST_TRAIT_ADAPTATIONS) {
1831
631
    const zend_ast_list *list = (const zend_ast_list*)ast;
1832
631
    uint32_t i = 0;
1833
1834
1.68k
    while (i < list->children) {
1835
1.05k
      ast = list->child[i];
1836
1.05k
      zend_ast_export_stmt(str, ast, indent);
1837
1.05k
      i++;
1838
1.05k
    }
1839
859
  } else {
1840
859
    zend_ast_export_indent(str, indent);
1841
859
    zend_ast_export_ex(str, ast, 0, indent);
1842
859
    switch (ast->kind) {
1843
6
      case ZEND_AST_LABEL:
1844
36
      case ZEND_AST_IF:
1845
42
      case ZEND_AST_SWITCH:
1846
48
      case ZEND_AST_WHILE:
1847
54
      case ZEND_AST_TRY:
1848
60
      case ZEND_AST_FOR:
1849
66
      case ZEND_AST_FOREACH:
1850
66
      case ZEND_AST_FUNC_DECL:
1851
98
      case ZEND_AST_METHOD:
1852
243
      case ZEND_AST_CLASS:
1853
255
      case ZEND_AST_USE_TRAIT:
1854
255
      case ZEND_AST_NAMESPACE:
1855
267
      case ZEND_AST_DECLARE:
1856
267
        break;
1857
42
      case ZEND_AST_PROP_GROUP: {
1858
42
        const zend_ast *first_prop = zend_ast_get_list(ast->child[1])->child[0];
1859
42
        const zend_ast *hook_list = first_prop->child[3];
1860
42
        if (hook_list == NULL) {
1861
30
          smart_str_appendc(str, ';');
1862
30
        }
1863
42
        break;
1864
255
      }
1865
550
      default:
1866
550
        smart_str_appendc(str, ';');
1867
550
        break;
1868
859
    }
1869
859
    smart_str_appendc(str, '\n');
1870
859
  }
1871
1.49k
}
1872
1873
static ZEND_COLD void zend_ast_export_if_stmt(smart_str *str, const zend_ast_list *list, int indent)
1874
30
{
1875
30
  uint32_t i;
1876
30
  zend_ast *ast;
1877
1878
42
tail_call:
1879
42
  i = 0;
1880
102
  while (i < list->children) {
1881
72
    ast = list->child[i];
1882
72
    ZEND_ASSERT(ast->kind == ZEND_AST_IF_ELEM);
1883
72
    if (ast->child[0]) {
1884
48
      if (i == 0) {
1885
42
        smart_str_appends(str, "if (");
1886
42
      } else {
1887
6
        zend_ast_export_indent(str, indent);
1888
6
        smart_str_appends(str, "} elseif (");
1889
6
      }
1890
48
      zend_ast_export_ex(str, ast->child[0], 0, indent);
1891
48
      smart_str_appends(str, ") {\n");
1892
48
      zend_ast_export_stmt(str, ast->child[1], indent + 1);
1893
48
    } else {
1894
24
      zend_ast_export_indent(str, indent);
1895
24
      smart_str_appends(str, "} else ");
1896
24
      if (ast->child[1] && ast->child[1]->kind == ZEND_AST_IF) {
1897
12
        list = (const zend_ast_list*)ast->child[1];
1898
12
        goto tail_call;
1899
12
      } else {
1900
12
        smart_str_appends(str, "{\n");
1901
12
        zend_ast_export_stmt(str, ast->child[1], indent + 1);
1902
12
      }
1903
24
    }
1904
60
    i++;
1905
60
  }
1906
30
  zend_ast_export_indent(str, indent);
1907
30
  smart_str_appendc(str, '}');
1908
30
}
1909
1910
static ZEND_COLD void zend_ast_export_zval(smart_str *str, const zval *zv, int priority, int indent)
1911
990
{
1912
990
  ZVAL_DEREF(zv);
1913
990
  switch (Z_TYPE_P(zv)) {
1914
0
    case IS_NULL:
1915
0
      smart_str_appends(str, "null");
1916
0
      break;
1917
36
    case IS_FALSE:
1918
36
      smart_str_appends(str, "false");
1919
36
      break;
1920
0
    case IS_TRUE:
1921
0
      smart_str_appends(str, "true");
1922
0
      break;
1923
671
    case IS_LONG:
1924
671
      smart_str_append_long(str, Z_LVAL_P(zv));
1925
671
      break;
1926
31
    case IS_DOUBLE:
1927
31
      smart_str_append_double(
1928
31
        str, Z_DVAL_P(zv), (int) EG(precision), /* zero_fraction */ true);
1929
31
      break;
1930
207
    case IS_STRING:
1931
207
      smart_str_appendc(str, '\'');
1932
207
      zend_ast_export_str(str, Z_STR_P(zv));
1933
207
      smart_str_appendc(str, '\'');
1934
207
      break;
1935
45
    case IS_ARRAY: {
1936
45
      zend_long idx;
1937
45
      zend_string *key;
1938
45
      zval *val;
1939
45
      bool first = true;
1940
45
      smart_str_appendc(str, '[');
1941
219
      ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zv), idx, key, val) {
1942
219
        if (first) {
1943
45
          first = false;
1944
45
        } else {
1945
42
          smart_str_appends(str, ", ");
1946
42
        }
1947
219
        if (key) {
1948
0
          smart_str_appendc(str, '\'');
1949
0
          zend_ast_export_str(str, key);
1950
0
          smart_str_appends(str, "' => ");
1951
87
        } else {
1952
87
          smart_str_append_long(str, idx);
1953
87
          smart_str_appends(str, " => ");
1954
87
        }
1955
219
        zend_ast_export_zval(str, val, 0, indent);
1956
219
      } ZEND_HASH_FOREACH_END();
1957
45
      smart_str_appendc(str, ']');
1958
45
      break;
1959
0
    }
1960
0
    case IS_CONSTANT_AST:
1961
0
      zend_ast_export_ex(str, Z_ASTVAL_P(zv), priority, indent);
1962
0
      break;
1963
0
    default: ZEND_UNREACHABLE();
1964
990
  }
1965
990
}
1966
1967
172
static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, const zend_ast_decl *decl, int indent) {
1968
172
  if (decl->child[0]) {
1969
8
    smart_str_appends(str, " extends ");
1970
8
    zend_ast_export_ns_name(str, decl->child[0], 0, indent);
1971
8
  }
1972
172
  if (decl->child[1]) {
1973
6
    smart_str_appends(str, " implements ");
1974
6
    zend_ast_export_ex(str, decl->child[1], 0, indent);
1975
6
  }
1976
172
  smart_str_appends(str, " {\n");
1977
172
  zend_ast_export_stmt(str, decl->child[2], indent + 1);
1978
172
  zend_ast_export_indent(str, indent);
1979
172
  smart_str_appendc(str, '}');
1980
172
}
1981
1982
395
static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) {
1983
395
  const zend_ast_list *list = zend_ast_get_list(ast);
1984
790
  for (uint32_t i = 0; i < list->children; i++) {
1985
395
    const zend_ast *attr = list->child[i];
1986
1987
395
    if (i) {
1988
0
      smart_str_appends(str, ", ");
1989
0
    }
1990
395
    zend_ast_export_ns_name(str, attr->child[0], 0, indent);
1991
1992
395
    if (attr->child[1]) {
1993
17
      smart_str_appendc(str, '(');
1994
17
      zend_ast_export_ex(str, attr->child[1], 0, indent);
1995
17
      smart_str_appendc(str, ')');
1996
17
    }
1997
395
  }
1998
395
}
1999
2000
149
static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, bool newlines) {
2001
149
  const zend_ast_list *list = zend_ast_get_list(ast);
2002
149
  uint32_t i;
2003
2004
544
  for (i = 0; i < list->children; i++) {
2005
395
    smart_str_appends(str, "#[");
2006
395
    zend_ast_export_attribute_group(str, list->child[i], indent);
2007
395
    smart_str_appendc(str, ']');
2008
2009
395
    if (newlines) {
2010
373
      smart_str_appendc(str, '\n');
2011
373
      zend_ast_export_indent(str, indent);
2012
373
    } else {
2013
22
      smart_str_appendc(str, ' ');
2014
22
    }
2015
395
  }
2016
149
}
2017
2018
366
static ZEND_COLD void zend_ast_export_visibility(smart_str *str, uint32_t flags, zend_modifier_target target) {
2019
366
  if (flags & ZEND_ACC_PUBLIC) {
2020
70
    smart_str_appends(str, "public ");
2021
296
  } else if (flags & ZEND_ACC_PROTECTED) {
2022
12
    smart_str_appends(str, "protected ");
2023
284
  } else if (flags & ZEND_ACC_PRIVATE) {
2024
12
    smart_str_appends(str, "private ");
2025
12
  }
2026
2027
366
  if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_CPP) {
2028
134
    if (flags & ZEND_ACC_PRIVATE_SET) {
2029
4
      smart_str_appends(str, "private(set) ");
2030
130
    } else if (flags & ZEND_ACC_PROTECTED_SET) {
2031
2
      smart_str_appends(str, "protected(set) ");
2032
128
    } else if (flags & ZEND_ACC_PUBLIC_SET) {
2033
0
      smart_str_appends(str, "public(set) ");
2034
0
    }
2035
134
  }
2036
366
}
2037
2038
120
static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int indent) {
2039
120
  if (ast->kind == ZEND_AST_TYPE_UNION) {
2040
6
    const zend_ast_list *list = zend_ast_get_list(ast);
2041
18
    for (uint32_t i = 0; i < list->children; i++) {
2042
12
      if (i != 0) {
2043
6
        smart_str_appendc(str, '|');
2044
6
      }
2045
12
      zend_ast_export_type(str, list->child[i], indent);
2046
12
    }
2047
6
    return;
2048
6
  }
2049
114
  if (ast->kind == ZEND_AST_TYPE_INTERSECTION) {
2050
0
    const zend_ast_list *list = zend_ast_get_list(ast);
2051
0
    for (uint32_t i = 0; i < list->children; i++) {
2052
0
      if (i != 0) {
2053
0
        smart_str_appendc(str, '&');
2054
0
      }
2055
0
      zend_ast_export_type(str, list->child[i], indent);
2056
0
    }
2057
0
    return;
2058
0
  }
2059
114
  if (ast->attr & ZEND_TYPE_NULLABLE) {
2060
34
    smart_str_appendc(str, '?');
2061
34
  }
2062
114
  zend_ast_export_ns_name(str, ast, 0, indent);
2063
114
}
2064
2065
static ZEND_COLD void zend_ast_export_hook_list(smart_str *str, const zend_ast_list *hook_list, int indent)
2066
14
{
2067
14
  smart_str_appends(str, " {");
2068
14
  smart_str_appendc(str, '\n');
2069
14
  indent++;
2070
14
  zend_ast_export_indent(str, indent);
2071
2072
34
  for (uint32_t i = 0; i < hook_list->children; i++) {
2073
20
    const zend_ast_decl *hook = (const zend_ast_decl *)hook_list->child[i];
2074
20
    zend_ast_export_visibility(str, hook->flags, ZEND_MODIFIER_TARGET_PROPERTY);
2075
20
    if (hook->flags & ZEND_ACC_FINAL) {
2076
4
      smart_str_appends(str, "final ");
2077
4
    }
2078
20
    smart_str_append(str, hook->name);
2079
20
    zend_ast *body = hook->child[2];
2080
20
    if (body == NULL) {
2081
8
      smart_str_appendc(str, ';');
2082
12
    } else if (body->kind == ZEND_AST_PROPERTY_HOOK_SHORT_BODY) {
2083
6
      smart_str_appends(str, " => ");
2084
6
      zend_ast_export_ex(str, body->child[0], 0, indent);
2085
6
      smart_str_appendc(str, ';');
2086
6
    } else {
2087
6
      smart_str_appends(str, " {\n");
2088
6
      zend_ast_export_stmt(str, body, indent + 1);
2089
6
      zend_ast_export_indent(str, indent);
2090
6
      smart_str_appendc(str, '}');
2091
6
    }
2092
20
    if (i < (hook_list->children - 1)) {
2093
6
      smart_str_appendc(str, '\n');
2094
6
      zend_ast_export_indent(str, indent);
2095
6
    }
2096
20
  }
2097
14
  smart_str_appendc(str, '\n');
2098
14
  indent--;
2099
14
  zend_ast_export_indent(str, indent);
2100
14
  smart_str_appendc(str, '}');
2101
14
}
2102
2103
946
#define BINARY_OP(_op, _p, _pl, _pr) do { \
2104
946
    op = _op; \
2105
946
    p = _p; \
2106
946
    pl = _pl; \
2107
946
    pr = _pr; \
2108
946
    goto binary_op; \
2109
946
  } while (0)
2110
2111
121
#define PREFIX_OP(_op, _p, _pl) do { \
2112
121
    op = _op; \
2113
121
    p = _p; \
2114
121
    pl = _pl; \
2115
121
    goto prefix_op; \
2116
121
  } while (0)
2117
2118
22
#define FUNC_OP(_op) do { \
2119
22
    op = _op; \
2120
22
    goto func_op; \
2121
22
  } while (0)
2122
2123
24
#define POSTFIX_OP(_op, _p, _pl) do { \
2124
24
    op = _op; \
2125
24
    p = _p; \
2126
24
    pl = _pl; \
2127
24
    goto postfix_op; \
2128
24
  } while (0)
2129
2130
128
#define APPEND_NODE_1(_op) do { \
2131
128
    op = _op; \
2132
128
    goto append_node_1; \
2133
128
  } while (0)
2134
2135
58
#define APPEND_STR(_op) do { \
2136
58
    op = _op; \
2137
58
    goto append_str; \
2138
58
  } while (0)
2139
2140
52
#define APPEND_DEFAULT_VALUE(n) do { \
2141
52
    p = n; \
2142
52
    goto append_default_value; \
2143
52
  } while (0)
2144
2145
static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent)
2146
30.3k
{
2147
30.3k
  const zend_ast_decl *decl;
2148
30.3k
  int p, pl, pr;
2149
30.3k
  const char *op;
2150
2151
30.5k
tail_call:
2152
30.5k
  if (!ast) {
2153
198
    return;
2154
198
  }
2155
30.3k
  switch (ast->kind) {
2156
    /* special nodes */
2157
903
    case ZEND_AST_ZVAL:
2158
903
      zend_ast_export_zval(str, zend_ast_get_zval(ast), priority, indent);
2159
903
      break;
2160
132
    case ZEND_AST_CONSTANT: {
2161
132
      zend_string *name = zend_ast_get_constant_name(ast);
2162
132
      smart_str_append(str, name);
2163
132
      break;
2164
0
    }
2165
3
    case ZEND_AST_OP_ARRAY:
2166
3
      smart_str_appends(str, "Closure(");
2167
3
      smart_str_append(str, zend_ast_get_op_array(ast)->op_array->function_name);
2168
3
      smart_str_appendc(str, ')');
2169
3
      break;
2170
0
    case ZEND_AST_CONSTANT_CLASS:
2171
0
      smart_str_appendl(str, "__CLASS__", sizeof("__CLASS__")-1);
2172
0
      break;
2173
0
    case ZEND_AST_ZNODE:
2174
      /* This AST kind is only used for temporary nodes during compilation */
2175
0
      ZEND_UNREACHABLE();
2176
0
      break;
2177
2178
    /* declaration nodes */
2179
0
    case ZEND_AST_FUNC_DECL:
2180
89
    case ZEND_AST_CLOSURE:
2181
184
    case ZEND_AST_ARROW_FUNC:
2182
216
    case ZEND_AST_METHOD:
2183
216
      decl = (const zend_ast_decl *) ast;
2184
216
      if (decl->kind == ZEND_AST_ARROW_FUNC && (decl->attr & ZEND_PARENTHESIZED_ARROW_FUNC)) {
2185
4
        smart_str_appendc(str, '(');
2186
4
      }
2187
216
      if (decl->child[4]) {
2188
10
        bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC);
2189
10
        zend_ast_export_attributes(str, decl->child[4], indent, newlines);
2190
10
      }
2191
2192
216
      zend_ast_export_visibility(str, decl->flags, ZEND_MODIFIER_TARGET_METHOD);
2193
2194
216
      if (decl->flags & ZEND_ACC_STATIC) {
2195
12
        smart_str_appends(str, "static ");
2196
12
      }
2197
216
      if (decl->flags & ZEND_ACC_ABSTRACT) {
2198
6
        smart_str_appends(str, "abstract ");
2199
6
      }
2200
216
      if (decl->flags & ZEND_ACC_FINAL) {
2201
6
        smart_str_appends(str, "final ");
2202
6
      }
2203
216
      if (decl->kind == ZEND_AST_ARROW_FUNC) {
2204
95
        smart_str_appends(str, "fn");
2205
121
      } else {
2206
121
        smart_str_appends(str, "function ");
2207
121
      }
2208
216
      if (decl->flags & ZEND_ACC_RETURN_REFERENCE) {
2209
28
        smart_str_appendc(str, '&');
2210
28
      }
2211
216
      if (ast->kind != ZEND_AST_CLOSURE && ast->kind != ZEND_AST_ARROW_FUNC) {
2212
32
        smart_str_append(str, decl->name);
2213
32
      }
2214
216
      smart_str_appendc(str, '(');
2215
216
      zend_ast_export_ex(str, decl->child[0], 0, indent);
2216
216
      smart_str_appendc(str, ')');
2217
216
      zend_ast_export_ex(str, decl->child[1], 0, indent);
2218
216
      if (decl->child[3]) {
2219
32
        smart_str_appends(str, ": ");
2220
32
        zend_ast_export_type(str, decl->child[3], indent);
2221
32
      }
2222
216
      if (decl->child[2]) {
2223
210
        if (decl->kind == ZEND_AST_ARROW_FUNC) {
2224
95
          zend_ast *body = decl->child[2];
2225
95
          if (body->kind == ZEND_AST_RETURN) {
2226
0
            body = body->child[0];
2227
0
          }
2228
95
          smart_str_appends(str, " => ");
2229
95
          zend_ast_export_ex(str, body, 0, indent);
2230
95
          if (decl->attr & ZEND_PARENTHESIZED_ARROW_FUNC) {
2231
4
            smart_str_appendc(str, ')');
2232
4
          }
2233
95
          break;
2234
95
        }
2235
2236
115
        smart_str_appends(str, " {\n");
2237
115
        zend_ast_export_stmt(str, decl->child[2], indent + 1);
2238
115
        zend_ast_export_indent(str, indent);
2239
115
        smart_str_appendc(str, '}');
2240
115
        if (ast->kind != ZEND_AST_CLOSURE) {
2241
26
          smart_str_appendc(str, '\n');
2242
26
        }
2243
115
      } else {
2244
6
        smart_str_appends(str, ";\n");
2245
6
      }
2246
121
      break;
2247
145
    case ZEND_AST_CLASS:
2248
145
      decl = (const zend_ast_decl *) ast;
2249
145
      if (decl->child[3]) {
2250
117
        zend_ast_export_attributes(str, decl->child[3], indent, true);
2251
117
      }
2252
145
      if (decl->flags & ZEND_ACC_INTERFACE) {
2253
2
        smart_str_appends(str, "interface ");
2254
143
      } else if (decl->flags & ZEND_ACC_TRAIT) {
2255
2
        smart_str_appends(str, "trait ");
2256
141
      } else if (decl->flags & ZEND_ACC_ENUM) {
2257
14
        smart_str_appends(str, "enum ");
2258
127
      } else {
2259
127
        if (decl->flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
2260
6
          smart_str_appends(str, "abstract ");
2261
6
        }
2262
127
        if (decl->flags & ZEND_ACC_FINAL) {
2263
6
          smart_str_appends(str, "final ");
2264
6
        }
2265
127
        if (decl->flags & ZEND_ACC_READONLY_CLASS) {
2266
0
          smart_str_appends(str, "readonly ");
2267
0
        }
2268
127
        smart_str_appends(str, "class ");
2269
127
      }
2270
145
      smart_str_append(str, decl->name);
2271
145
      if (decl->flags & ZEND_ACC_ENUM && decl->child[4]) {
2272
6
        smart_str_appends(str, ": ");
2273
6
        zend_ast_export_type(str, decl->child[4], indent);
2274
6
      }
2275
145
      zend_ast_export_class_no_header(str, decl, indent);
2276
145
      smart_str_appendc(str, '\n');
2277
145
      break;
2278
2279
    /* list nodes */
2280
522
    case ZEND_AST_ARG_LIST:
2281
540
    case ZEND_AST_EXPR_LIST:
2282
756
    case ZEND_AST_PARAM_LIST:
2283
842
simple_list:
2284
842
      zend_ast_export_list(str, zend_ast_get_list(ast), true, 20, indent);
2285
842
      break;
2286
117
    case ZEND_AST_ARRAY:
2287
117
      smart_str_appendc(str, '[');
2288
117
      zend_ast_export_list(str, zend_ast_get_list(ast), true, 20, indent);
2289
117
      smart_str_appendc(str, ']');
2290
117
      break;
2291
155
    case ZEND_AST_ENCAPS_LIST:
2292
155
      smart_str_appendc(str, '"');
2293
155
      zend_ast_export_encaps_list(str, '"', zend_ast_get_list(ast), indent);
2294
155
      smart_str_appendc(str, '"');
2295
155
      break;
2296
0
    case ZEND_AST_STMT_LIST:
2297
6
    case ZEND_AST_TRAIT_ADAPTATIONS:
2298
6
      zend_ast_export_stmt(str, ast, indent);
2299
6
      break;
2300
30
    case ZEND_AST_IF:
2301
30
      zend_ast_export_if_stmt(str, zend_ast_get_list(ast), indent);
2302
30
      break;
2303
6
    case ZEND_AST_SWITCH_LIST:
2304
12
    case ZEND_AST_CATCH_LIST:
2305
16
    case ZEND_AST_MATCH_ARM_LIST:
2306
16
      zend_ast_export_list(str, zend_ast_get_list(ast), false, 0, indent);
2307
16
      break;
2308
18
    case ZEND_AST_CLOSURE_USES:
2309
18
      smart_str_appends(str, " use(");
2310
18
      zend_ast_export_var_list(str, zend_ast_get_list(ast), indent);
2311
18
      smart_str_appendc(str, ')');
2312
18
      break;
2313
42
    case ZEND_AST_PROP_GROUP: {
2314
42
      zend_ast *type_ast = ast->child[0];
2315
42
      zend_ast *prop_ast = ast->child[1];
2316
2317
42
      if (ast->child[2]) {
2318
2
        zend_ast_export_attributes(str, ast->child[2], indent, true);
2319
2
      }
2320
2321
42
      zend_ast_export_visibility(str, ast->attr, ZEND_MODIFIER_TARGET_PROPERTY);
2322
2323
42
      if (ast->attr & ZEND_ACC_STATIC) {
2324
6
        smart_str_appends(str, "static ");
2325
6
      }
2326
42
      if (ast->attr & ZEND_ACC_READONLY) {
2327
0
        smart_str_appends(str, "readonly ");
2328
0
      }
2329
2330
42
      if (type_ast) {
2331
8
        zend_ast_export_type(str, type_ast, indent);
2332
8
        smart_str_appendc(str, ' ');
2333
8
      }
2334
2335
42
      ast = prop_ast;
2336
42
      goto simple_list;
2337
12
    }
2338
2339
0
    case ZEND_AST_CONST_DECL: {
2340
0
      zend_ast_list *ast_list = zend_ast_get_list(ast);
2341
      /* Attributes are stored at the end of the list if present. */
2342
0
      if (ast_list->child[ast_list->children - 1]->kind == ZEND_AST_ATTRIBUTE_LIST) {
2343
0
        zend_ast_export_attributes(
2344
0
          str,
2345
0
          ast_list->child[ast_list->children - 1],
2346
0
          indent,
2347
0
          true
2348
0
        );
2349
        /* So that the list printing doesn't try to print the attributes,
2350
         * use zend_ast_export_list_ex() to override the number of children
2351
         * to print. */
2352
0
        smart_str_appends(str, "const ");
2353
0
        zend_ast_export_list_ex(str, ast_list, true, 20, indent, ast_list->children - 1);
2354
0
        break;
2355
0
      }
2356
0
      smart_str_appends(str, "const ");
2357
0
      goto simple_list;
2358
0
    }
2359
16
    case ZEND_AST_CLASS_CONST_GROUP:
2360
16
      if (ast->child[1]) {
2361
2
        zend_ast_export_attributes(str, ast->child[1], indent, true);
2362
2
      }
2363
2364
16
      zend_ast_export_visibility(str, ast->attr, ZEND_MODIFIER_TARGET_CONSTANT);
2365
16
      smart_str_appends(str, "const ");
2366
16
      if (ast->child[2]) {
2367
2
        zend_ast_export_type(str, ast->child[2], indent);
2368
2
        smart_str_appendc(str, ' ');
2369
2
      }
2370
2371
16
      ast = ast->child[0];
2372
2373
16
      goto simple_list;
2374
24
    case ZEND_AST_NAME_LIST:
2375
24
      zend_ast_export_name_list(str, zend_ast_get_list(ast), indent);
2376
24
      break;
2377
0
    case ZEND_AST_USE:
2378
0
      smart_str_appends(str, "use ");
2379
0
      if (ast->attr == T_FUNCTION) {
2380
0
        smart_str_appends(str, "function ");
2381
0
      } else if (ast->attr == T_CONST) {
2382
0
        smart_str_appends(str, "const ");
2383
0
      }
2384
0
      goto simple_list;
2385
2386
    /* 0 child nodes */
2387
0
    case ZEND_AST_MAGIC_CONST:
2388
0
      switch (ast->attr) {
2389
0
        case T_LINE:     APPEND_STR("__LINE__");
2390
0
        case T_FILE:     APPEND_STR("__FILE__");
2391
0
        case T_DIR:      APPEND_STR("__DIR__");
2392
0
        case T_TRAIT_C:  APPEND_STR("__TRAIT__");
2393
0
        case T_METHOD_C: APPEND_STR("__METHOD__");
2394
0
        case T_FUNC_C:   APPEND_STR("__FUNCTION__");
2395
0
        case T_PROPERTY_C: APPEND_STR("__PROPERTY__");
2396
0
        case T_NS_C:     APPEND_STR("__NAMESPACE__");
2397
0
        case T_CLASS_C:  APPEND_STR("__CLASS__");
2398
0
        default: ZEND_UNREACHABLE();
2399
0
      }
2400
0
      break;
2401
30
    case ZEND_AST_TYPE:
2402
30
      switch (ast->attr & ~ZEND_TYPE_NULLABLE) {
2403
24
        case IS_ARRAY:    APPEND_STR("array");
2404
0
        case IS_CALLABLE: APPEND_STR("callable");
2405
6
        case IS_STATIC:   APPEND_STR("static");
2406
0
        case IS_MIXED:    APPEND_STR("mixed");
2407
0
        default: ZEND_UNREACHABLE();
2408
30
      }
2409
0
      break;
2410
28
    case ZEND_AST_PLACEHOLDER_ARG:
2411
28
      if (ast->attr == ZEND_PLACEHOLDER_VARIADIC) {
2412
28
        APPEND_STR("...");
2413
28
      } else  {
2414
0
        APPEND_STR("?");
2415
0
      }
2416
0
      break;
2417
2418
    /* 1 child node */
2419
17.8k
    case ZEND_AST_VAR:
2420
17.8k
      smart_str_appendc(str, '$');
2421
17.8k
      zend_ast_export_var(str, ast->child[0], indent);
2422
17.8k
      break;
2423
339
    case ZEND_AST_CONST:
2424
339
      zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2425
339
      break;
2426
8
    case ZEND_AST_UNPACK:
2427
8
      smart_str_appends(str, "...");
2428
8
      ast = ast->child[0];
2429
8
      goto tail_call;
2430
4
    case ZEND_AST_UNARY_PLUS:  PREFIX_OP("+", 240, 241);
2431
39
    case ZEND_AST_UNARY_MINUS: PREFIX_OP("-", 240, 241);
2432
0
    case ZEND_AST_CAST:
2433
0
      switch (ast->attr) {
2434
0
        case IS_NULL:      PREFIX_OP("(unset)",  240, 241);
2435
0
        case _IS_BOOL:     PREFIX_OP("(bool)",   240, 241);
2436
0
        case IS_LONG:      PREFIX_OP("(int)",    240, 241);
2437
0
        case IS_DOUBLE:    PREFIX_OP("(float)", 240, 241);
2438
0
        case IS_STRING:    PREFIX_OP("(string)", 240, 241);
2439
0
        case IS_ARRAY:     PREFIX_OP("(array)",  240, 241);
2440
0
        case IS_OBJECT:    PREFIX_OP("(object)", 240, 241);
2441
0
        default: ZEND_UNREACHABLE();
2442
0
      }
2443
0
      break;
2444
2
    case ZEND_AST_CAST_VOID:
2445
2
      PREFIX_OP("(void)", 240, 241);
2446
0
      break;
2447
4
    case ZEND_AST_EMPTY:
2448
4
      FUNC_OP("empty");
2449
6
    case ZEND_AST_ISSET:
2450
6
      FUNC_OP("isset");
2451
8
    case ZEND_AST_SILENCE:
2452
8
      PREFIX_OP("@", 240, 241);
2453
12
    case ZEND_AST_SHELL_EXEC:
2454
12
      smart_str_appendc(str, '`');
2455
12
      if (ast->child[0]->kind == ZEND_AST_ENCAPS_LIST) {
2456
8
        zend_ast_export_encaps_list(str, '`', zend_ast_get_list(ast->child[0]), indent);
2457
8
      } else {
2458
4
        zval *zv;
2459
4
        ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_ZVAL);
2460
4
        zv = zend_ast_get_zval(ast->child[0]);
2461
4
        ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
2462
4
        zend_ast_export_qstr(str, '`', Z_STR_P(zv));
2463
4
      }
2464
12
      smart_str_appendc(str, '`');
2465
12
      break;
2466
6
    case ZEND_AST_PRINT:
2467
6
      PREFIX_OP("print ", 60, 61);
2468
6
    case ZEND_AST_INCLUDE_OR_EVAL:
2469
6
      switch (ast->attr) {
2470
0
        case ZEND_INCLUDE_ONCE: FUNC_OP("include_once");
2471
0
        case ZEND_INCLUDE:      FUNC_OP("include");
2472
0
        case ZEND_REQUIRE_ONCE: FUNC_OP("require_once");
2473
0
        case ZEND_REQUIRE:      FUNC_OP("require");
2474
6
        case ZEND_EVAL:         FUNC_OP("eval");
2475
0
        default: ZEND_UNREACHABLE();
2476
6
      }
2477
0
      break;
2478
47
    case ZEND_AST_UNARY_OP:
2479
47
      switch (ast->attr) {
2480
12
        case ZEND_BW_NOT:   PREFIX_OP("~", 240, 241);
2481
35
        case ZEND_BOOL_NOT: PREFIX_OP("!", 240, 241);
2482
0
        default: ZEND_UNREACHABLE();
2483
47
      }
2484
0
      break;
2485
0
    case ZEND_AST_PRE_INC:
2486
0
      PREFIX_OP("++", 240, 241);
2487
9
    case ZEND_AST_PRE_DEC:
2488
9
      PREFIX_OP("--", 240, 241);
2489
18
    case ZEND_AST_POST_INC:
2490
18
      POSTFIX_OP("++", 240, 241);
2491
6
    case ZEND_AST_POST_DEC:
2492
6
      POSTFIX_OP("--", 240, 241);
2493
2494
12
    case ZEND_AST_GLOBAL:
2495
12
      APPEND_NODE_1("global");
2496
6
    case ZEND_AST_UNSET:
2497
6
      FUNC_OP("unset");
2498
56
    case ZEND_AST_RETURN:
2499
56
      APPEND_NODE_1("return");
2500
6
    case ZEND_AST_LABEL:
2501
6
      zend_ast_export_name(str, ast->child[0], 0, indent);
2502
6
      smart_str_appendc(str, ':');
2503
6
      break;
2504
6
    case ZEND_AST_REF:
2505
6
      smart_str_appendc(str, '&');
2506
6
      ast = ast->child[0];
2507
6
      goto tail_call;
2508
0
    case ZEND_AST_HALT_COMPILER:
2509
0
      APPEND_STR("__HALT_COMPILER()");
2510
36
    case ZEND_AST_ECHO:
2511
36
      APPEND_NODE_1("echo");
2512
0
    case ZEND_AST_THROW:
2513
0
      APPEND_NODE_1("throw");
2514
6
    case ZEND_AST_GOTO:
2515
6
      smart_str_appends(str, "goto ");
2516
6
      zend_ast_export_name(str, ast->child[0], 0, indent);
2517
6
      break;
2518
12
    case ZEND_AST_BREAK:
2519
12
      APPEND_NODE_1("break");
2520
12
    case ZEND_AST_CONTINUE:
2521
12
      APPEND_NODE_1("continue");
2522
2523
    /* 2 child nodes */
2524
126
    case ZEND_AST_DIM:
2525
126
      zend_ast_export_ex(str, ast->child[0], 260, indent);
2526
126
      smart_str_appendc(str, '[');
2527
126
      if (ast->child[1]) {
2528
126
        zend_ast_export_ex(str, ast->child[1], 0, indent);
2529
126
      }
2530
126
      smart_str_appendc(str, ']');
2531
126
      break;
2532
169
    case ZEND_AST_PROP:
2533
6.84k
    case ZEND_AST_NULLSAFE_PROP:
2534
6.84k
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2535
6.84k
      smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_PROP ? "?->" : "->");
2536
6.84k
      zend_ast_export_var(str, ast->child[1], indent);
2537
6.84k
      break;
2538
20
    case ZEND_AST_STATIC_PROP:
2539
20
      zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2540
20
      smart_str_appends(str, "::$");
2541
20
      zend_ast_export_var(str, ast->child[1], indent);
2542
20
      break;
2543
437
    case ZEND_AST_CALL: {
2544
437
      zend_ast *left = ast->child[0];
2545
437
      if (left->kind == ZEND_AST_ARROW_FUNC || left->kind == ZEND_AST_CLOSURE) {
2546
91
        smart_str_appendc(str, '(');
2547
91
        zend_ast_export_ns_name(str, left, 0, indent);
2548
91
        smart_str_appendc(str, ')');
2549
346
      } else {
2550
346
        zend_ast_export_ns_name(str, left, 0, indent);
2551
346
      }
2552
437
      smart_str_appendc(str, '(');
2553
437
      zend_ast_export_ex(str, ast->child[1], 0, indent);
2554
437
      smart_str_appendc(str, ')');
2555
437
      break;
2556
169
    }
2557
28
    case ZEND_AST_CALLABLE_CONVERT: {
2558
28
      zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast;
2559
28
      ast = fcc_ast->args;
2560
28
      goto simple_list;
2561
169
    }
2562
24
    case ZEND_AST_CLASS_CONST:
2563
24
      zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2564
24
      smart_str_appends(str, "::");
2565
24
      zend_ast_export_name(str, ast->child[1], 0, indent);
2566
24
      break;
2567
0
    case ZEND_AST_CLASS_NAME:
2568
0
      if (ast->child[0] == NULL) {
2569
        /* The const expr representation stores the fetch type instead. */
2570
0
        switch (ast->attr) {
2571
0
          case ZEND_FETCH_CLASS_SELF:
2572
0
            smart_str_append(str, ZSTR_KNOWN(ZEND_STR_SELF));
2573
0
            break;
2574
0
          case ZEND_FETCH_CLASS_PARENT:
2575
0
            smart_str_append(str, ZSTR_KNOWN(ZEND_STR_PARENT));
2576
0
            break;
2577
0
          default: ZEND_UNREACHABLE();
2578
0
        }
2579
0
      } else {
2580
0
        zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2581
0
      }
2582
0
      smart_str_appends(str, "::class");
2583
0
      break;
2584
342
    case ZEND_AST_ASSIGN:            BINARY_OP(" = ",   90, 91, 90);
2585
0
    case ZEND_AST_ASSIGN_REF:        BINARY_OP(" =& ",  90, 91, 90);
2586
2
    case ZEND_AST_ASSIGN_OP:
2587
2
      switch (ast->attr) {
2588
0
        case ZEND_ADD:    BINARY_OP(" += ",  90, 91, 90);
2589
0
        case ZEND_SUB:    BINARY_OP(" -= ",  90, 91, 90);
2590
0
        case ZEND_MUL:    BINARY_OP(" *= ",  90, 91, 90);
2591
0
        case ZEND_DIV:    BINARY_OP(" /= ",  90, 91, 90);
2592
0
        case ZEND_MOD:    BINARY_OP(" %= ",  90, 91, 90);
2593
0
        case ZEND_SL:     BINARY_OP(" <<= ", 90, 91, 90);
2594
0
        case ZEND_SR:     BINARY_OP(" >>= ", 90, 91, 90);
2595
0
        case ZEND_CONCAT: BINARY_OP(" .= ",  90, 91, 90);
2596
0
        case ZEND_BW_OR:  BINARY_OP(" |= ",  90, 91, 90);
2597
0
        case ZEND_BW_AND: BINARY_OP(" &= ",  90, 91, 90);
2598
0
        case ZEND_BW_XOR: BINARY_OP(" ^= ",  90, 91, 90);
2599
2
        case ZEND_POW:    BINARY_OP(" **= ", 90, 91, 90);
2600
0
        default: ZEND_UNREACHABLE();
2601
2
      }
2602
0
      break;
2603
0
    case ZEND_AST_ASSIGN_COALESCE: BINARY_OP(" \?\?= ", 90, 91, 90);
2604
347
    case ZEND_AST_BINARY_OP:
2605
347
      switch (ast->attr) {
2606
12
        case ZEND_ADD:                 BINARY_OP(" + ",   200, 200, 201);
2607
20
        case ZEND_SUB:                 BINARY_OP(" - ",   200, 200, 201);
2608
0
        case ZEND_MUL:                 BINARY_OP(" * ",   210, 210, 211);
2609
0
        case ZEND_DIV:                 BINARY_OP(" / ",   210, 210, 211);
2610
2
        case ZEND_MOD:                 BINARY_OP(" % ",   210, 210, 211);
2611
12
        case ZEND_SL:                  BINARY_OP(" << ",  190, 190, 191);
2612
0
        case ZEND_SR:                  BINARY_OP(" >> ",  190, 190, 191);
2613
84
        case ZEND_CONCAT:              BINARY_OP(" . ",   185, 185, 186);
2614
2
        case ZEND_BW_OR:               BINARY_OP(" | ",   140, 140, 141);
2615
0
        case ZEND_BW_AND:              BINARY_OP(" & ",   160, 160, 161);
2616
2
        case ZEND_BW_XOR:              BINARY_OP(" ^ ",   150, 150, 151);
2617
72
        case ZEND_IS_IDENTICAL:        BINARY_OP(" === ", 170, 171, 171);
2618
0
        case ZEND_IS_NOT_IDENTICAL:    BINARY_OP(" !== ", 170, 171, 171);
2619
78
        case ZEND_IS_EQUAL:            BINARY_OP(" == ",  170, 171, 171);
2620
0
        case ZEND_IS_NOT_EQUAL:        BINARY_OP(" != ",  170, 171, 171);
2621
63
        case ZEND_IS_SMALLER:          BINARY_OP(" < ",   180, 181, 181);
2622
0
        case ZEND_IS_SMALLER_OR_EQUAL: BINARY_OP(" <= ",  180, 181, 181);
2623
0
        case ZEND_POW:                 BINARY_OP(" ** ",  250, 251, 250);
2624
0
        case ZEND_BOOL_XOR:            BINARY_OP(" xor ",  40,  40,  41);
2625
0
        case ZEND_SPACESHIP:           BINARY_OP(" <=> ", 180, 181, 181);
2626
0
        default: ZEND_UNREACHABLE();
2627
347
      }
2628
0
      break;
2629
25
    case ZEND_AST_GREATER:                 BINARY_OP(" > ",   180, 181, 181);
2630
0
    case ZEND_AST_GREATER_EQUAL:           BINARY_OP(" >= ",  180, 181, 181);
2631
150
    case ZEND_AST_AND:                     BINARY_OP(" && ",  130, 130, 131);
2632
44
    case ZEND_AST_OR:                      BINARY_OP(" || ",  120, 120, 121);
2633
30
    case ZEND_AST_PIPE:                    BINARY_OP(" |> ",  183, 183, 184);
2634
255
    case ZEND_AST_ARRAY_ELEM:
2635
255
      if (ast->child[1]) {
2636
42
        zend_ast_export_ex(str, ast->child[1], 80, indent);
2637
42
        smart_str_appends(str, " => ");
2638
42
      }
2639
255
      if (ast->attr)
2640
0
        smart_str_appendc(str, '&');
2641
255
      zend_ast_export_ex(str, ast->child[0], 80, indent);
2642
255
      break;
2643
60
    case ZEND_AST_NEW:
2644
60
      smart_str_appends(str, "new ");
2645
60
      if (ast->child[0]->kind == ZEND_AST_CLASS) {
2646
27
        const zend_ast_decl *decl = (const zend_ast_decl *) ast->child[0];
2647
27
        if (decl->child[3]) {
2648
8
          zend_ast_export_attributes(str, decl->child[3], indent, false);
2649
8
        }
2650
27
        smart_str_appends(str, "class");
2651
27
        if (!zend_ast_is_list(ast->child[1])
2652
24
            || zend_ast_get_list(ast->child[1])->children) {
2653
5
          smart_str_appendc(str, '(');
2654
5
          zend_ast_export_ex(str, ast->child[1], 0, indent);
2655
5
          smart_str_appendc(str, ')');
2656
5
        }
2657
27
        zend_ast_export_class_no_header(str, decl, indent);
2658
33
      } else {
2659
33
        zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2660
33
        smart_str_appendc(str, '(');
2661
33
        zend_ast_export_ex(str, ast->child[1], 0, indent);
2662
33
        smart_str_appendc(str, ')');
2663
33
      }
2664
60
      break;
2665
23
    case ZEND_AST_INSTANCEOF:
2666
23
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2667
23
      smart_str_appends(str, " instanceof ");
2668
23
      zend_ast_export_ns_name(str, ast->child[1], 0, indent);
2669
23
      break;
2670
12
    case ZEND_AST_YIELD:
2671
12
      if (priority > 70) smart_str_appendc(str, '(');
2672
12
      smart_str_appends(str, "yield ");
2673
12
      if (ast->child[0]) {
2674
12
        if (ast->child[1]) {
2675
6
          zend_ast_export_ex(str, ast->child[1], 70, indent);
2676
6
          smart_str_appends(str, " => ");
2677
6
        }
2678
12
        zend_ast_export_ex(str, ast->child[0], 70, indent);
2679
12
      }
2680
12
      if (priority > 70) smart_str_appendc(str, ')');
2681
12
      break;
2682
6
    case ZEND_AST_YIELD_FROM:
2683
6
      PREFIX_OP("yield from ", 85, 86);
2684
6
    case ZEND_AST_COALESCE: BINARY_OP(" ?? ", 110, 111, 110);
2685
12
    case ZEND_AST_STATIC:
2686
12
      smart_str_appends(str, "static $");
2687
12
      zend_ast_export_name(str, ast->child[0], 0, indent);
2688
12
      APPEND_DEFAULT_VALUE(1);
2689
6
    case ZEND_AST_WHILE:
2690
6
      smart_str_appends(str, "while (");
2691
6
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2692
6
      smart_str_appends(str, ") {\n");
2693
6
      zend_ast_export_stmt(str, ast->child[1], indent + 1);
2694
6
      zend_ast_export_indent(str, indent);
2695
6
      smart_str_appendc(str, '}');
2696
6
      break;
2697
12
    case ZEND_AST_DO_WHILE:
2698
12
      smart_str_appends(str, "do {\n");
2699
12
      zend_ast_export_stmt(str, ast->child[0], indent + 1);
2700
12
      zend_ast_export_indent(str, indent);
2701
12
      smart_str_appends(str, "} while (");
2702
12
      zend_ast_export_ex(str, ast->child[1], 0, indent);
2703
12
      smart_str_appendc(str, ')');
2704
12
      break;
2705
2706
0
    case ZEND_AST_IF_ELEM:
2707
0
      if (ast->child[0]) {
2708
0
        smart_str_appends(str, "if (");
2709
0
        zend_ast_export_ex(str, ast->child[0], 0, indent);
2710
0
        smart_str_appends(str, ") {\n");
2711
0
        zend_ast_export_stmt(str, ast->child[1], indent + 1);
2712
0
      } else {
2713
0
        smart_str_appends(str, "else {\n");
2714
0
        zend_ast_export_stmt(str, ast->child[1], indent + 1);
2715
0
      }
2716
0
      zend_ast_export_indent(str, indent);
2717
0
      smart_str_appendc(str, '}');
2718
0
      break;
2719
6
    case ZEND_AST_SWITCH:
2720
6
      smart_str_appends(str, "switch (");
2721
6
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2722
6
      smart_str_appends(str, ") {\n");
2723
6
      zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
2724
6
      zend_ast_export_indent(str, indent);
2725
6
      smart_str_appendc(str, '}');
2726
6
      break;
2727
36
    case ZEND_AST_SWITCH_CASE:
2728
36
      zend_ast_export_indent(str, indent);
2729
36
      if (ast->child[0]) {
2730
30
        smart_str_appends(str, "case ");
2731
30
        zend_ast_export_ex(str, ast->child[0], 0, indent);
2732
30
        smart_str_appends(str, ":\n");
2733
30
      } else {
2734
6
        smart_str_appends(str, "default:\n");
2735
6
      }
2736
36
      zend_ast_export_stmt(str, ast->child[1], indent + 1);
2737
36
      break;
2738
4
    case ZEND_AST_MATCH:
2739
4
      smart_str_appends(str, "match (");
2740
4
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2741
4
      smart_str_appends(str, ") {\n");
2742
4
      zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
2743
4
      zend_ast_export_indent(str, indent);
2744
4
      smart_str_appendc(str, '}');
2745
4
      break;
2746
12
    case ZEND_AST_MATCH_ARM:
2747
12
      zend_ast_export_indent(str, indent);
2748
12
      if (ast->child[0]) {
2749
8
        zend_ast_export_list(str, zend_ast_get_list(ast->child[0]), true, 0, indent);
2750
8
        smart_str_appends(str, " => ");
2751
8
      } else {
2752
4
        smart_str_appends(str, "default => ");
2753
4
      }
2754
12
      zend_ast_export_ex(str, ast->child[1], 0, 0);
2755
12
      smart_str_appends(str, ",\n");
2756
12
      break;
2757
12
    case ZEND_AST_DECLARE:
2758
12
      smart_str_appends(str, "declare(");
2759
12
      ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_CONST_DECL);
2760
12
      zend_ast_export_list(str, zend_ast_get_list(ast->child[0]), true, 0, indent);
2761
12
      smart_str_appendc(str, ')');
2762
12
      if (ast->child[1]) {
2763
6
        smart_str_appends(str, " {\n");
2764
6
        zend_ast_export_stmt(str, ast->child[1], indent + 1);
2765
6
        zend_ast_export_indent(str, indent);
2766
6
        smart_str_appendc(str, '}');
2767
6
      } else {
2768
6
        smart_str_appendc(str, ';');
2769
6
      }
2770
12
      break;
2771
48
    case ZEND_AST_PROP_ELEM:
2772
48
      smart_str_appendc(str, '$');
2773
48
      zend_ast_export_name(str, ast->child[0], 0, indent);
2774
2775
48
      zend_ast *default_value = ast->child[1];
2776
48
      if (default_value) {
2777
16
        smart_str_appends(str, " = ");
2778
16
        zend_ast_export_ex(str, default_value, 0, indent + 1);
2779
16
      }
2780
2781
48
      if (ast->child[3]) {
2782
12
        zend_ast_export_hook_list(str, zend_ast_get_list(ast->child[3]), indent);
2783
12
      }
2784
48
      break;
2785
40
    case ZEND_AST_CONST_ELEM:
2786
40
      zend_ast_export_name(str, ast->child[0], 0, indent);
2787
40
      APPEND_DEFAULT_VALUE(1);
2788
12
    case ZEND_AST_USE_TRAIT:
2789
12
      smart_str_appends(str, "use ");
2790
12
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2791
12
      if (ast->child[1]) {
2792
6
        smart_str_appends(str, " {\n");
2793
6
        zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
2794
6
        zend_ast_export_indent(str, indent);
2795
6
        smart_str_appendc(str, '}');
2796
6
      } else {
2797
6
        smart_str_appendc(str, ';');
2798
6
      }
2799
12
      break;
2800
6
    case ZEND_AST_TRAIT_PRECEDENCE:
2801
6
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2802
6
      smart_str_appends(str, " insteadof ");
2803
6
      zend_ast_export_ex(str, ast->child[1], 0, indent);
2804
6
      break;
2805
24
    case ZEND_AST_TRAIT_METHOD_REFERENCE:
2806
24
      if (ast->child[0]) {
2807
12
        zend_ast_export_name(str, ast->child[0], 0, indent);
2808
12
        smart_str_appends(str, "::");
2809
12
      }
2810
24
      zend_ast_export_name(str, ast->child[1], 0, indent);
2811
24
      break;
2812
0
    case ZEND_AST_NAMESPACE:
2813
0
      smart_str_appends(str, "namespace");
2814
0
      if (ast->child[0]) {
2815
0
        smart_str_appendc(str, ' ');
2816
0
        zend_ast_export_name(str, ast->child[0], 0, indent);
2817
0
      }
2818
0
      if (ast->child[1]) {
2819
0
        smart_str_appends(str, " {\n");
2820
0
        zend_ast_export_stmt(str, ast->child[1], indent + 1);
2821
0
        zend_ast_export_indent(str, indent);
2822
0
        smart_str_appends(str, "}\n");
2823
0
      } else {
2824
0
        smart_str_appendc(str, ';');
2825
0
      }
2826
0
      break;
2827
0
    case ZEND_AST_USE_ELEM:
2828
18
    case ZEND_AST_TRAIT_ALIAS:
2829
18
      zend_ast_export_name(str, ast->child[0], 0, indent);
2830
18
      if (ast->attr & ZEND_ACC_PUBLIC) {
2831
6
        smart_str_appends(str, " as public");
2832
12
      } else if (ast->attr & ZEND_ACC_PROTECTED) {
2833
6
        smart_str_appends(str, " as protected");
2834
6
      } else if (ast->attr & ZEND_ACC_PRIVATE) {
2835
0
        smart_str_appends(str, " as private");
2836
6
      } else if (ast->child[1]) {
2837
6
        smart_str_appends(str, " as");
2838
6
      }
2839
18
      if (ast->child[1]) {
2840
12
        smart_str_appendc(str, ' ');
2841
12
        zend_ast_export_name(str, ast->child[1], 0, indent);
2842
12
      }
2843
18
      break;
2844
26
    case ZEND_AST_NAMED_ARG:
2845
26
      smart_str_append(str, zend_ast_get_str(ast->child[0]));
2846
26
      smart_str_appends(str, ": ");
2847
26
      ast = ast->child[1];
2848
26
      goto tail_call;
2849
2850
    /* 3 child nodes */
2851
26
    case ZEND_AST_METHOD_CALL:
2852
32
    case ZEND_AST_NULLSAFE_METHOD_CALL:
2853
32
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2854
32
      smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL ? "?->" : "->");
2855
32
      zend_ast_export_var(str, ast->child[1], indent);
2856
32
      smart_str_appendc(str, '(');
2857
32
      zend_ast_export_ex(str, ast->child[2], 0, indent);
2858
32
      smart_str_appendc(str, ')');
2859
32
      break;
2860
26
    case ZEND_AST_STATIC_CALL:
2861
26
      zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2862
26
      smart_str_appends(str, "::");
2863
26
      zend_ast_export_var(str, ast->child[1], indent);
2864
26
      smart_str_appendc(str, '(');
2865
26
      zend_ast_export_ex(str, ast->child[2], 0, indent);
2866
26
      smart_str_appendc(str, ')');
2867
26
      break;
2868
14
    case ZEND_AST_CONDITIONAL:
2869
14
      if (priority > 100) smart_str_appendc(str, '(');
2870
14
      zend_ast_export_ex(str, ast->child[0], 100, indent);
2871
14
      if (ast->child[1]) {
2872
6
        smart_str_appends(str, " ? ");
2873
6
        zend_ast_export_ex(str, ast->child[1], 101, indent);
2874
6
        smart_str_appends(str, " : ");
2875
8
      } else {
2876
8
        smart_str_appends(str, " ?: ");
2877
8
      }
2878
14
      zend_ast_export_ex(str, ast->child[2], 101, indent);
2879
14
      if (priority > 100) smart_str_appendc(str, ')');
2880
14
      break;
2881
2882
6
    case ZEND_AST_TRY:
2883
6
      smart_str_appends(str, "try {\n");
2884
6
      zend_ast_export_stmt(str, ast->child[0], indent + 1);
2885
6
      zend_ast_export_indent(str, indent);
2886
6
      zend_ast_export_ex(str, ast->child[1], 0, indent);
2887
6
      if (ast->child[2]) {
2888
6
        smart_str_appends(str, "} finally {\n");
2889
6
        zend_ast_export_stmt(str, ast->child[2], indent + 1);
2890
6
        zend_ast_export_indent(str, indent);
2891
6
      }
2892
6
      smart_str_appendc(str, '}');
2893
6
      break;
2894
12
    case ZEND_AST_CATCH:
2895
12
      smart_str_appends(str, "} catch (");
2896
12
      zend_ast_export_catch_name_list(str, zend_ast_get_list(ast->child[0]), indent);
2897
12
      if (ast->child[1]) {
2898
12
        smart_str_appends(str, " $");
2899
12
        zend_ast_export_var(str, ast->child[1], indent);
2900
12
      }
2901
12
      smart_str_appends(str, ") {\n");
2902
12
      zend_ast_export_stmt(str, ast->child[2], indent + 1);
2903
12
      zend_ast_export_indent(str, indent);
2904
12
      break;
2905
72
    case ZEND_AST_PARAM:
2906
72
      if (ast->child[3]) {
2907
4
        zend_ast_export_attributes(str, ast->child[3], indent, false);
2908
4
      }
2909
72
      zend_ast_export_visibility(str, ast->attr, ZEND_MODIFIER_TARGET_CPP);
2910
72
      if (ast->attr & ZEND_ACC_FINAL) {
2911
2
        smart_str_appends(str, "final ");
2912
2
      }
2913
72
      if (ast->child[0]) {
2914
60
        zend_ast_export_type(str, ast->child[0], indent);
2915
60
        smart_str_appendc(str, ' ');
2916
60
      }
2917
72
      if (ast->attr & ZEND_PARAM_REF) {
2918
24
        smart_str_appendc(str, '&');
2919
24
      }
2920
72
      if (ast->attr & ZEND_PARAM_VARIADIC) {
2921
10
        smart_str_appends(str, "...");
2922
10
      }
2923
72
      smart_str_appendc(str, '$');
2924
72
      zend_ast_export_name(str, ast->child[1], 0, indent);
2925
72
      if (ast->child[2]) {
2926
22
        smart_str_appends(str, " = ");
2927
22
        zend_ast_export_ex(str, ast->child[2], 0, indent);
2928
22
      }
2929
72
      if (ast->child[5]) {
2930
2
        zend_ast_export_hook_list(str, zend_ast_get_list(ast->child[5]), indent);
2931
2
      }
2932
72
      break;
2933
20
    case ZEND_AST_ENUM_CASE:
2934
20
      if (ast->child[3]) {
2935
6
        zend_ast_export_attributes(str, ast->child[3], indent, true);
2936
6
      }
2937
20
      smart_str_appends(str, "case ");
2938
20
      zend_ast_export_name(str, ast->child[0], 0, indent);
2939
20
      if (ast->child[1]) {
2940
12
        smart_str_appends(str, " = ");
2941
12
        zend_ast_export_ex(str, ast->child[1], 0, indent);
2942
12
      }
2943
20
      break;
2944
2945
    /* 4 child nodes */
2946
6
    case ZEND_AST_FOR:
2947
6
      smart_str_appends(str, "for (");
2948
6
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2949
6
      smart_str_appendc(str, ';');
2950
6
      if (ast->child[1]) {
2951
6
        smart_str_appendc(str, ' ');
2952
6
        zend_ast_export_ex(str, ast->child[1], 0, indent);
2953
6
      }
2954
6
      smart_str_appendc(str, ';');
2955
6
      if (ast->child[2]) {
2956
6
        smart_str_appendc(str, ' ');
2957
6
        zend_ast_export_ex(str, ast->child[2], 0, indent);
2958
6
      }
2959
6
      smart_str_appends(str, ") {\n");
2960
6
      zend_ast_export_stmt(str, ast->child[3], indent + 1);
2961
6
      zend_ast_export_indent(str, indent);
2962
6
      smart_str_appendc(str, '}');
2963
6
      break;
2964
6
    case ZEND_AST_FOREACH:
2965
6
      smart_str_appends(str, "foreach (");
2966
6
      zend_ast_export_ex(str, ast->child[0], 0, indent);
2967
6
      smart_str_appends(str, " as ");
2968
6
      if (ast->child[2]) {
2969
6
        zend_ast_export_ex(str, ast->child[2], 0, indent);
2970
6
        smart_str_appends(str, " => ");
2971
6
      }
2972
6
      zend_ast_export_ex(str, ast->child[1], 0, indent);
2973
6
      smart_str_appends(str, ") {\n");
2974
6
      zend_ast_export_stmt(str, ast->child[3], indent + 1);
2975
6
      zend_ast_export_indent(str, indent);
2976
6
      smart_str_appendc(str, '}');
2977
6
      break;
2978
0
    default: ZEND_UNREACHABLE();
2979
30.3k
  }
2980
28.9k
  return;
2981
2982
28.9k
binary_op:
2983
946
  if (priority > p) smart_str_appendc(str, '(');
2984
946
  zend_ast_export_ex(str, ast->child[0], pl, indent);
2985
946
  smart_str_appends(str, op);
2986
946
  zend_ast_export_ex(str, ast->child[1], pr, indent);
2987
946
  if (priority > p) smart_str_appendc(str, ')');
2988
946
  return;
2989
2990
121
prefix_op:
2991
121
  if (priority > p) smart_str_appendc(str, '(');
2992
121
  smart_str_appends(str, op);
2993
121
  zend_ast_export_ex(str, ast->child[0], pl, indent);
2994
121
  if (priority > p) smart_str_appendc(str, ')');
2995
121
  return;
2996
2997
24
postfix_op:
2998
24
  if (priority > p) smart_str_appendc(str, '(');
2999
24
  zend_ast_export_ex(str, ast->child[0], pl, indent);
3000
24
  smart_str_appends(str, op);
3001
24
  if (priority > p) smart_str_appendc(str, ')');
3002
24
  return;
3003
3004
22
func_op:
3005
22
  smart_str_appends(str, op);
3006
22
  smart_str_appendc(str, '(');
3007
22
  zend_ast_export_ex(str, ast->child[0], 0, indent);
3008
22
  smart_str_appendc(str, ')');
3009
22
  return;
3010
3011
128
append_node_1:
3012
128
  smart_str_appends(str, op);
3013
128
  if (ast->child[0]) {
3014
110
    smart_str_appendc(str, ' ');
3015
110
    ast = ast->child[0];
3016
110
    goto tail_call;
3017
110
  }
3018
18
  return;
3019
3020
58
append_str:
3021
58
  smart_str_appends(str, op);
3022
58
  return;
3023
3024
52
append_default_value:
3025
52
  if (ast->child[p]) {
3026
46
    smart_str_appends(str, " = ");
3027
46
    ast = ast->child[p];
3028
46
    goto tail_call;
3029
46
  }
3030
6
  return;
3031
52
}
3032
3033
ZEND_API ZEND_COLD zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix)
3034
735
{
3035
735
  smart_str str = {0};
3036
3037
735
  smart_str_appends(&str, prefix);
3038
735
  zend_ast_export_ex(&str, ast, 0, 0);
3039
735
  smart_str_appends(&str, suffix);
3040
735
  smart_str_0(&str);
3041
735
  return str.s;
3042
735
}
3043
3044
zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
3045
2.00k
{
3046
2.00k
  ZEND_ASSERT(attr->kind == ZEND_AST_ATTRIBUTE_LIST);
3047
3048
2.00k
  switch (ast->kind) {
3049
216
  case ZEND_AST_FUNC_DECL:
3050
393
  case ZEND_AST_CLOSURE:
3051
598
  case ZEND_AST_METHOD:
3052
634
  case ZEND_AST_ARROW_FUNC:
3053
710
  case ZEND_AST_PROPERTY_HOOK:
3054
710
    ((zend_ast_decl *) ast)->child[4] = attr;
3055
710
    break;
3056
794
  case ZEND_AST_CLASS:
3057
794
    ((zend_ast_decl *) ast)->child[3] = attr;
3058
794
    break;
3059
114
  case ZEND_AST_PROP_GROUP:
3060
114
    ast->child[2] = attr;
3061
114
    break;
3062
134
  case ZEND_AST_PARAM:
3063
149
  case ZEND_AST_ENUM_CASE:
3064
149
    ast->child[3] = attr;
3065
149
    break;
3066
106
  case ZEND_AST_CLASS_CONST_GROUP:
3067
106
    ast->child[1] = attr;
3068
106
    break;
3069
135
  case ZEND_AST_CONST_DECL:
3070
    /* Since constants are already stored in a list, just add the attributes
3071
     * to that list instead of storing them elsewhere;
3072
     * zend_compile_const_decl() checks the kind of the list elements. */
3073
135
    ast = zend_ast_list_add(ast, attr);
3074
135
    break;
3075
0
  default: ZEND_UNREACHABLE();
3076
2.00k
  }
3077
3078
2.00k
  return ast;
3079
2.00k
}
3080
3081
zend_ast * ZEND_FASTCALL zend_ast_call_get_args(zend_ast *ast)
3082
142
{
3083
142
  if (ast->kind == ZEND_AST_CALL) {
3084
88
    return ast->child[1];
3085
88
  } else if (ast->kind == ZEND_AST_STATIC_CALL || ast->kind == ZEND_AST_METHOD_CALL) {
3086
54
    return ast->child[2];
3087
54
  }
3088
3089
0
  ZEND_UNREACHABLE();
3090
0
  return NULL;
3091
0
}