1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "php.h"
6 #include "php_ini.h"
7 #include "ext/standard/info.h"
8 #include "php_ast.h"
9 #include "ext/spl/spl_exceptions.h"
10
11 #include "zend_language_scanner.h"
12 #include "zend_language_scanner_defs.h"
13 #include "zend_language_parser.h"
14 #include "zend_exceptions.h"
15 #include "zend_hash.h"
16 #include "zend_smart_str.h"
17 #if PHP_VERSION_ID >= 80200
18 /* Used for AllowDynamicProperties */
19 #include "zend_attributes.h"
20 #endif
21
22 #if PHP_VERSION_ID < 70200
23 #error "The php-ast 1.1 release dropped support for php 7.0-7.1. Use php-ast 1.0.16 instead."
24 #endif
25
26 #ifndef ZEND_THIS
27 #define ZEND_THIS getThis()
28 #endif
29
30 #ifndef ZEND_ARG_INFO_WITH_DEFAULT_VALUE
31 #define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) \
32 ZEND_ARG_INFO(pass_by_ref, name)
33 #endif
34
35 #ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX
36 #define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \
37 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null)
38 #endif
39
40 #ifndef ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE
41 #define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \
42 ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null)
43 #endif
44
45 #include "ast_arginfo.h"
46
47 #define ast_throw_exception(exception_ce, ...) \
48 zend_throw_exception_ex(exception_ce, 0, __VA_ARGS__)
49
50 #define ast_declare_property(ce, name, value) \
51 zend_declare_property_ex((ce), (name), (value), ZEND_ACC_PUBLIC, NULL)
52
53 #define ast_register_flag_constant(name, value) \
54 REGISTER_NS_LONG_CONSTANT("ast\\flags", name, value, CONST_CS | CONST_PERSISTENT)
55
56 // These are in the order the properties were declared with ast_declare_property.
57 #define AST_NODE_PROP_KIND(object) OBJ_PROP_NUM((object), 0)
58 #define AST_NODE_PROP_FLAGS(object) OBJ_PROP_NUM((object), 1)
59 #define AST_NODE_PROP_LINENO(object) OBJ_PROP_NUM((object), 2)
60 #define AST_NODE_PROP_CHILDREN(object) OBJ_PROP_NUM((object), 3)
61
62 #define AST_NODE_SET_PROP_KIND(object, num) ZVAL_LONG(AST_NODE_PROP_KIND((object)), (num))
63 #define AST_NODE_SET_PROP_FLAGS(object, num) ZVAL_LONG(AST_NODE_PROP_FLAGS((object)), (num))
64 #define AST_NODE_SET_PROP_LINENO(object, num) ZVAL_LONG(AST_NODE_PROP_LINENO((object)), (num))
65 // Set the ast\Node->children array to the given reference-counted array without incrementing the reference count of the array.
66 // Do not use this macro with immutable arrays.
67 #define AST_NODE_SET_PROP_CHILDREN_ARRAY(object, array) ZVAL_ARR(AST_NODE_PROP_CHILDREN((object)), (array))
68
69 #define AST_METADATA_PROP_KIND(object) OBJ_PROP_NUM((object), 0)
70 #define AST_METADATA_PROP_NAME(object) OBJ_PROP_NUM((object), 1)
71 #define AST_METADATA_PROP_FLAGS(object) OBJ_PROP_NUM((object), 2)
72 #define AST_METADATA_PROP_FLAGS_COMBINABLE(object) OBJ_PROP_NUM((object), 3)
73
74 #define AST_CURRENT_VERSION 110
75
76 /* Additional flags for BINARY_OP */
77 #define AST_BINARY_IS_GREATER 256
78 #define AST_BINARY_IS_GREATER_OR_EQUAL 257
79 #define AST_BINARY_BOOL_OR 258
80 #define AST_BINARY_BOOL_AND 259
81 #define AST_BINARY_COALESCE 260
82
83 /* Flags for UNARY_OP to use instead of AST_SILENCE, AST_UNARY_PLUS, AST_UNARY_MINUS */
84 #define AST_SILENCE 260
85 #define AST_PLUS 261
86 #define AST_MINUS 262
87
88 #if PHP_VERSION_ID < 70300
89 # define ZEND_BIND_REF 1
90 #endif
91
92 #if PHP_VERSION_ID < 70400
93 # define ZEND_DIM_ALTERNATIVE_SYNTAX (1<<1)
94 # define ZEND_PARENTHESIZED_CONDITIONAL 1
95 #endif
96
97 /* Make IS_STATIC follow IS_ITERABLE in php 7.0 */
98 #if PHP_VERSION_ID < 80000
99 # define IS_STATIC 20
100 # define IS_MIXED 21
101 /* In PHP 7.0-7.4, PARAM_REF and PARAM_VARIADIC were 1 and 2. */
102 # define PARAM_MODIFIER_PUBLIC (1 << 2)
103 # define PARAM_MODIFIER_PROTECTED (1 << 3)
104 # define PARAM_MODIFIER_PRIVATE (1 << 4)
105 #else
106 # define PARAM_MODIFIER_PUBLIC ZEND_ACC_PUBLIC
107 # define PARAM_MODIFIER_PROTECTED ZEND_ACC_PROTECTED
108 # define PARAM_MODIFIER_PRIVATE ZEND_ACC_PRIVATE
109 #endif
110
111 #if PHP_VERSION_ID < 80100
112 # define IS_NEVER 22
113 #endif
114
115 #if PHP_VERSION_ID < 80200
116 # define ZEND_ENCAPS_VAR_DOLLAR_CURLY (1<<0)
117 # define ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR (1<<1)
118 #endif
119
120 #if PHP_VERSION_ID >= 80400
121 # define ZEND_DIM_ALTERNATIVE_SYNTAX (1<<1)
122 #endif
123
124 /* This contains state of the ast Node creator. */
125 typedef struct ast_state_info {
126 zend_long version;
127 zend_long declIdCounter;
128 } ast_state_info_t;
129
130 typedef struct _ast_flag_info {
131 uint16_t ast_kind;
132 zend_bool combinable;
133 const char **flags;
134 } ast_flag_info;
135
136 ZEND_DECLARE_MODULE_GLOBALS(ast)
137
138 ast_str_globals str_globals;
139
140 static zend_class_entry *ast_node_ce;
141 static zend_class_entry *ast_metadata_ce;
142
143 #define AST_FLAG(name) "ast\\flags\\" #name
144
145 static const char *name_flags[] = {
146 AST_FLAG(NAME_FQ),
147 AST_FLAG(NAME_NOT_FQ),
148 AST_FLAG(NAME_RELATIVE),
149 NULL
150 };
151
152 static const char *class_flags[] = {
153 AST_FLAG(CLASS_ABSTRACT),
154 AST_FLAG(CLASS_FINAL),
155 AST_FLAG(CLASS_TRAIT),
156 AST_FLAG(CLASS_INTERFACE),
157 AST_FLAG(CLASS_ANONYMOUS),
158 AST_FLAG(CLASS_ENUM),
159 AST_FLAG(CLASS_READONLY),
160 NULL
161 };
162
163 static const char *param_flags[] = {
164 AST_FLAG(PARAM_REF),
165 AST_FLAG(PARAM_VARIADIC),
166 AST_FLAG(PARAM_MODIFIER_PUBLIC),
167 AST_FLAG(PARAM_MODIFIER_PROTECTED),
168 AST_FLAG(PARAM_MODIFIER_PRIVATE),
169 NULL
170 };
171
172 static const char *type_flags[] = {
173 AST_FLAG(TYPE_NULL),
174 AST_FLAG(TYPE_FALSE),
175 AST_FLAG(TYPE_TRUE),
176 AST_FLAG(TYPE_BOOL),
177 AST_FLAG(TYPE_LONG),
178 AST_FLAG(TYPE_DOUBLE),
179 AST_FLAG(TYPE_STRING),
180 AST_FLAG(TYPE_ARRAY),
181 AST_FLAG(TYPE_OBJECT),
182 AST_FLAG(TYPE_CALLABLE),
183 AST_FLAG(TYPE_VOID),
184 AST_FLAG(TYPE_ITERABLE),
185 AST_FLAG(TYPE_STATIC),
186 AST_FLAG(TYPE_MIXED),
187 AST_FLAG(TYPE_NEVER),
188 NULL
189 };
190
191 static const char *unary_op_flags[] = {
192 AST_FLAG(UNARY_BOOL_NOT),
193 AST_FLAG(UNARY_BITWISE_NOT),
194 AST_FLAG(UNARY_MINUS),
195 AST_FLAG(UNARY_PLUS),
196 AST_FLAG(UNARY_SILENCE),
197 NULL
198 };
199
200 #define AST_SHARED_BINARY_OP_FLAGS \
201 AST_FLAG(BINARY_BITWISE_OR), \
202 AST_FLAG(BINARY_BITWISE_AND), \
203 AST_FLAG(BINARY_BITWISE_XOR), \
204 AST_FLAG(BINARY_CONCAT), \
205 AST_FLAG(BINARY_ADD), \
206 AST_FLAG(BINARY_SUB), \
207 AST_FLAG(BINARY_MUL), \
208 AST_FLAG(BINARY_DIV), \
209 AST_FLAG(BINARY_MOD), \
210 AST_FLAG(BINARY_POW), \
211 AST_FLAG(BINARY_SHIFT_LEFT), \
212 AST_FLAG(BINARY_SHIFT_RIGHT), \
213 AST_FLAG(BINARY_COALESCE) \
214
215 static const char *binary_op_flags[] = {
216 AST_SHARED_BINARY_OP_FLAGS,
217 AST_FLAG(BINARY_BOOL_AND),
218 AST_FLAG(BINARY_BOOL_OR),
219 AST_FLAG(BINARY_BOOL_XOR),
220 AST_FLAG(BINARY_IS_IDENTICAL),
221 AST_FLAG(BINARY_IS_NOT_IDENTICAL),
222 AST_FLAG(BINARY_IS_EQUAL),
223 AST_FLAG(BINARY_IS_NOT_EQUAL),
224 AST_FLAG(BINARY_IS_SMALLER),
225 AST_FLAG(BINARY_IS_SMALLER_OR_EQUAL),
226 AST_FLAG(BINARY_IS_GREATER),
227 AST_FLAG(BINARY_IS_GREATER_OR_EQUAL),
228 AST_FLAG(BINARY_SPACESHIP),
229 NULL
230 };
231
232 static const char *assign_op_flags[] = {
233 AST_SHARED_BINARY_OP_FLAGS,
234 NULL
235 };
236
237 static const char *magic_const_flags[] = {
238 AST_FLAG(MAGIC_LINE),
239 AST_FLAG(MAGIC_FILE),
240 AST_FLAG(MAGIC_DIR),
241 AST_FLAG(MAGIC_NAMESPACE),
242 AST_FLAG(MAGIC_FUNCTION),
243 AST_FLAG(MAGIC_METHOD),
244 AST_FLAG(MAGIC_CLASS),
245 AST_FLAG(MAGIC_TRAIT),
246 NULL
247 };
248
249 static const char *use_flags[] = {
250 AST_FLAG(USE_NORMAL),
251 AST_FLAG(USE_FUNCTION),
252 AST_FLAG(USE_CONST),
253 NULL
254 };
255
256 static const char *include_flags[] = {
257 AST_FLAG(EXEC_EVAL),
258 AST_FLAG(EXEC_INCLUDE),
259 AST_FLAG(EXEC_INCLUDE_ONCE),
260 AST_FLAG(EXEC_REQUIRE),
261 AST_FLAG(EXEC_REQUIRE_ONCE),
262 NULL
263 };
264
265 static const char *array_flags[] = {
266 AST_FLAG(ARRAY_SYNTAX_LIST),
267 AST_FLAG(ARRAY_SYNTAX_LONG),
268 AST_FLAG(ARRAY_SYNTAX_SHORT),
269 NULL
270 };
271
272 static const char *array_elem_flags[] = {
273 AST_FLAG(ARRAY_ELEM_REF),
274 NULL
275 };
276
277 static const char *closure_use_flags[] = {
278 AST_FLAG(CLOSURE_USE_REF),
279 NULL
280 };
281
282
283 #define AST_MODIFIER_FLAGS \
284 AST_FLAG(MODIFIER_PUBLIC), \
285 AST_FLAG(MODIFIER_PROTECTED), \
286 AST_FLAG(MODIFIER_PRIVATE), \
287 AST_FLAG(MODIFIER_STATIC), \
288 AST_FLAG(MODIFIER_ABSTRACT), \
289 AST_FLAG(MODIFIER_FINAL), \
290 AST_FLAG(MODIFIER_READONLY)
291
292 static const char *modifier_flags[] = {
293 AST_MODIFIER_FLAGS,
294 NULL
295 };
296
297 static const char *func_flags[] = {
298 AST_MODIFIER_FLAGS,
299 AST_FLAG(FUNC_RETURNS_REF),
300 AST_FLAG(FUNC_GENERATOR),
301 NULL
302 };
303
304 static const char *dim_flags[] = {
305 AST_FLAG(DIM_ALTERNATIVE_SYNTAX),
306 AST_FLAG(ENCAPS_VAR_DOLLAR_CURLY),
307 NULL
308 };
309
310 // Flags of AST_CONDITIONAL are marked as combinable in case any other flags get added in the future.
311 static const char *conditional_flags[] = {
312 AST_FLAG(PARENTHESIZED_CONDITIONAL),
313 NULL
314 };
315
316 static const char *var_flags[] = {
317 AST_FLAG(ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR),
318 AST_FLAG(ENCAPS_VAR_DOLLAR_CURLY),
319 NULL
320 };
321
322 static const ast_flag_info flag_info[] = {
323 { AST_NAME, 0, name_flags },
324 { ZEND_AST_CLASS, 1, class_flags },
325 { ZEND_AST_PARAM, 1, param_flags },
326 { ZEND_AST_TYPE, 0, type_flags },
327 { ZEND_AST_CAST, 0, type_flags },
328 { ZEND_AST_UNARY_OP, 0, unary_op_flags },
329 { ZEND_AST_BINARY_OP, 0, binary_op_flags },
330 { ZEND_AST_ASSIGN_OP, 0, assign_op_flags },
331 { ZEND_AST_MAGIC_CONST, 0, magic_const_flags },
332 { ZEND_AST_USE, 0, use_flags },
333 { ZEND_AST_GROUP_USE, 0, use_flags },
334 { ZEND_AST_USE_ELEM, 0, use_flags },
335 { ZEND_AST_INCLUDE_OR_EVAL, 0, include_flags },
336 { ZEND_AST_ARRAY, 0, array_flags },
337 { ZEND_AST_ARRAY_ELEM, 0, array_elem_flags },
338 { AST_CLOSURE_VAR, 0, closure_use_flags },
339 { ZEND_AST_METHOD, 1, func_flags },
340 { ZEND_AST_FUNC_DECL, 1, func_flags },
341 { ZEND_AST_CLOSURE, 1, func_flags },
342 { ZEND_AST_ARROW_FUNC, 1, func_flags },
343 { ZEND_AST_PROPERTY_HOOK, 1, func_flags },
344 { ZEND_AST_PROP_DECL, 1, modifier_flags },
345 { ZEND_AST_PROP_GROUP, 1, modifier_flags },
346 { ZEND_AST_CLASS_CONST_DECL, 1, modifier_flags },
347 { ZEND_AST_CLASS_CONST_GROUP, 1, modifier_flags },
348 { ZEND_AST_TRAIT_ALIAS, 1, modifier_flags },
349 { ZEND_AST_DIM, 1, dim_flags },
350 { ZEND_AST_CONDITIONAL, 1, conditional_flags },
351 { ZEND_AST_VAR, 1, var_flags },
352 };
353
ast_update_property(zval * object,zend_string * name,zval * value)354 static inline void ast_update_property(zval *object, zend_string *name, zval *value) {
355 #if PHP_VERSION_ID < 80000
356 zval name_zv;
357 ZVAL_STR(&name_zv, name);
358 Z_OBJ_HT_P(object)->write_property(object, &name_zv, value, NULL);
359 #else
360 Z_OBJ_HT_P(object)->write_property(Z_OBJ_P(object), name, value, NULL);
361 #endif
362 }
363
ast_update_property_long(zval * object,zend_string * name,zend_long value_raw)364 static inline void ast_update_property_long(zval *object, zend_string *name, zend_long value_raw) {
365 zval value_zv;
366 ZVAL_LONG(&value_zv, value_raw);
367 ast_update_property(object, name, &value_zv);
368 }
369
get_ast(zend_string * code,zend_arena ** ast_arena,zend_string * filename)370 static zend_ast *get_ast(zend_string *code, zend_arena **ast_arena, zend_string *filename) {
371 #if PHP_VERSION_ID >= 80100
372 if (filename) {
373 return zend_compile_string_to_ast(code, ast_arena, filename);
374 } else {
375 zend_ast *ast;
376 filename = zend_string_init("string code", sizeof("string code") - 1, 0);
377 ast = zend_compile_string_to_ast(code, ast_arena, filename);
378 zend_string_release_ex(filename, 0);
379 return ast;
380 }
381 #else
382 zval code_zv;
383 zend_bool original_in_compilation;
384 zend_lex_state original_lex_state;
385 zend_ast *ast;
386
387 ZVAL_STR_COPY(&code_zv, code);
388
389 original_in_compilation = CG(in_compilation);
390 CG(in_compilation) = 1;
391
392 zend_save_lexical_state(&original_lex_state);
393 zend_prepare_string_for_scanning(&code_zv, filename ? filename->val : "string code");
394 CG(ast) = NULL;
395 CG(ast_arena) = zend_arena_create(1024 * 32);
396 LANG_SCNG(yy_state) = yycINITIAL;
397
398 if (zendparse() != 0) {
399 zend_ast_destroy(CG(ast));
400 zend_arena_destroy(CG(ast_arena));
401 CG(ast) = NULL;
402 }
403
404 /* restore_lexical_state changes CG(ast) and CG(ast_arena) */
405 ast = CG(ast);
406 *ast_arena = CG(ast_arena);
407
408 zend_restore_lexical_state(&original_lex_state);
409 CG(in_compilation) = original_in_compilation;
410
411 zval_dtor(&code_zv);
412
413 return ast;
414 #endif
415 }
416
417 /* Returns whether node->attr (i.e. flags) is used by this node kind. Not to be confused with php 8.0's attributes. */
ast_kind_uses_attr(zend_ast_kind kind)418 static inline zend_bool ast_kind_uses_attr(zend_ast_kind kind) {
419 return kind == ZEND_AST_PARAM || kind == ZEND_AST_TYPE || kind == ZEND_AST_TRAIT_ALIAS
420 || kind == ZEND_AST_UNARY_OP || kind == ZEND_AST_BINARY_OP || kind == ZEND_AST_ASSIGN_OP
421 || kind == ZEND_AST_CAST || kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_ARRAY_ELEM
422 || kind == ZEND_AST_INCLUDE_OR_EVAL || kind == ZEND_AST_USE || kind == ZEND_AST_PROP_DECL
423 || kind == ZEND_AST_PROP_GROUP
424 || kind == ZEND_AST_GROUP_USE || kind == ZEND_AST_USE_ELEM
425 || kind == AST_NAME || kind == AST_CLOSURE_VAR || kind == ZEND_AST_CLASS_CONST_DECL
426 || kind == ZEND_AST_CLASS_CONST_GROUP
427 || kind == ZEND_AST_ARRAY || kind == ZEND_AST_DIM || kind == ZEND_AST_CONDITIONAL
428 || kind == ZEND_AST_VAR;
429 }
430
431 /* Returns true if nodes of this kind are represented with the C struct zend_ast_decl. */
ast_kind_is_decl(zend_ast_kind kind)432 static inline zend_bool ast_kind_is_decl(zend_ast_kind kind) {
433 return kind == ZEND_AST_FUNC_DECL || kind == ZEND_AST_CLOSURE
434 || kind == ZEND_AST_ARROW_FUNC
435 || kind == ZEND_AST_PROPERTY_HOOK
436 || kind == ZEND_AST_METHOD || kind == ZEND_AST_CLASS;
437 }
438
ast_is_name(zend_ast * ast,zend_ast * parent,uint32_t i)439 static inline zend_bool ast_is_name(zend_ast *ast, zend_ast *parent, uint32_t i) {
440 if (!ast) {
441 return 0;
442 }
443 if (ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(ast)) != IS_STRING) {
444 return 0;
445 }
446
447 if (parent->kind == ZEND_AST_NAME_LIST) {
448 return 1;
449 }
450 #if PHP_VERSION_ID >= 80100
451 if (parent->kind == ZEND_AST_TYPE_INTERSECTION) {
452 return 1;
453 }
454 #endif
455 #if PHP_VERSION_ID >= 80000
456 if (parent->kind == ZEND_AST_TYPE_UNION) {
457 return 1;
458 }
459 #endif
460
461 if (i == 0) {
462 return parent->kind == ZEND_AST_CATCH || parent->kind == ZEND_AST_CLASS
463 || parent->kind == ZEND_AST_PARAM || parent->kind == ZEND_AST_METHOD_REFERENCE
464 || parent->kind == ZEND_AST_CALL || parent->kind == ZEND_AST_CONST
465 || parent->kind == ZEND_AST_NEW || parent->kind == ZEND_AST_STATIC_CALL
466 || parent->kind == ZEND_AST_CLASS_CONST || parent->kind == ZEND_AST_STATIC_PROP
467 || parent->kind == ZEND_AST_PROP_GROUP || parent->kind == ZEND_AST_CLASS_NAME
468 #if PHP_VERSION_ID >= 80000
469 || parent->kind == ZEND_AST_ATTRIBUTE
470 #endif
471 ;
472 }
473
474 #if PHP_VERSION_ID >= 80300
475 if (i == 2) {
476 return parent->kind == ZEND_AST_CLASS_CONST_GROUP;
477 }
478 #endif
479
480 if (i == 1) {
481 return parent->kind == ZEND_AST_INSTANCEOF;
482 }
483
484 if (i == 3) {
485 return parent->kind == ZEND_AST_FUNC_DECL || parent->kind == ZEND_AST_CLOSURE
486 #if PHP_VERSION_ID >= 70400
487 || parent->kind == ZEND_AST_ARROW_FUNC
488 #endif
489 || parent->kind == ZEND_AST_METHOD;
490 }
491
492 #if PHP_VERSION_ID >= 80100
493 if (i == 4) {
494 return parent->kind == ZEND_AST_CLASS;
495 }
496 #endif
497
498 return 0;
499 }
500
501 /* Assumes that ast_is_name is already true */
ast_is_type(zend_ast * ast,zend_ast * parent,uint32_t i)502 static inline zend_bool ast_is_type(zend_ast *ast, zend_ast *parent, uint32_t i) {
503 #if PHP_VERSION_ID >= 80100
504 if (parent->kind == ZEND_AST_TYPE_INTERSECTION) {
505 return 1;
506 }
507 #endif
508 #if PHP_VERSION_ID >= 80000
509 if (parent->kind == ZEND_AST_TYPE_UNION) {
510 return 1;
511 }
512 #endif
513 if (i == 0) {
514 return parent->kind == ZEND_AST_PARAM
515 #if PHP_VERSION_ID >= 70400
516 || parent->kind == ZEND_AST_PROP_GROUP
517 #endif
518 ;
519 }
520 #if PHP_VERSION_ID >= 80300
521 if (i == 2) {
522 return parent->kind == ZEND_AST_CLASS_CONST_GROUP;
523 }
524 #endif
525 if (i == 3) {
526 return parent->kind == ZEND_AST_CLOSURE || parent->kind == ZEND_AST_FUNC_DECL
527 #if PHP_VERSION_ID >= 70400
528 || parent->kind == ZEND_AST_ARROW_FUNC
529 #endif
530 || parent->kind == ZEND_AST_METHOD;
531 }
532 #if PHP_VERSION_ID >= 80100
533 if (i == 4) {
534 return parent->kind == ZEND_AST_CLASS;
535 }
536 #endif
537 return 0;
538 }
539
ast_is_var_name(zend_ast * ast,zend_ast * parent,uint32_t i)540 static inline zend_bool ast_is_var_name(zend_ast *ast, zend_ast *parent, uint32_t i) {
541 return (parent->kind == ZEND_AST_STATIC && i == 0)
542 || (parent->kind == ZEND_AST_CATCH && i == 1 && ast != NULL);
543 }
544
545 /* Whether this node may need statement list normalization */
ast_should_normalize_list(zend_ast * ast,zend_ast * parent,uint32_t i)546 static inline zend_bool ast_should_normalize_list(zend_ast *ast, zend_ast *parent, uint32_t i) {
547 if (ast && ast->kind == ZEND_AST_STMT_LIST) {
548 return 0;
549 }
550
551 if (i == 0) {
552 return parent->kind == ZEND_AST_DO_WHILE;
553 }
554 if (i == 1) {
555 if (parent->kind == ZEND_AST_DECLARE) {
556 /* declare(); and declare() {} are not the same */
557 return ast != NULL;
558 }
559 return parent->kind == ZEND_AST_IF_ELEM || parent->kind == ZEND_AST_WHILE;
560 }
561 if (i == 2) {
562 return parent->kind == ZEND_AST_CATCH;
563 }
564 if (i == 3) {
565 return parent->kind == ZEND_AST_FOR || parent->kind == ZEND_AST_FOREACH;
566 }
567 return 0;
568 }
569
570 /* Adopted from zend_compile.c */
571 typedef struct _builtin_type_info {
572 const char* name;
573 const size_t name_len;
574 const zend_uchar type;
575 } builtin_type_info;
576 static const builtin_type_info builtin_types[] = {
577 {ZEND_STRL("int"), IS_LONG},
578 {ZEND_STRL("float"), IS_DOUBLE},
579 {ZEND_STRL("string"), IS_STRING},
580 {ZEND_STRL("bool"), _IS_BOOL},
581 {ZEND_STRL("void"), IS_VOID},
582 {ZEND_STRL("iterable"), IS_ITERABLE},
583 {ZEND_STRL("object"), IS_OBJECT},
584 {ZEND_STRL("null"), IS_NULL}, /* Null and false for php 8.0 union types */
585 {ZEND_STRL("false"), IS_FALSE},
586 // {ZEND_STRL("static"), IS_STATIC}, /* Impossible to be parsed before php 8 */
587 {ZEND_STRL("mixed"), IS_MIXED},
588 {ZEND_STRL("never"), IS_NEVER},
589 {ZEND_STRL("true"), IS_TRUE}, /* PHP 8.2 added the true type */
590 {NULL, 0, IS_UNDEF}
591 };
lookup_builtin_type(const zend_string * name)592 static inline zend_uchar lookup_builtin_type(const zend_string *name) {
593 const builtin_type_info *info = &builtin_types[0];
594 for (; info->name; ++info) {
595 if (ZSTR_LEN(name) == info->name_len
596 && !zend_binary_strcasecmp(ZSTR_VAL(name), ZSTR_LEN(name), info->name, info->name_len)
597 ) {
598 return info->type;
599 }
600 }
601 return 0;
602 }
603
604 #if PHP_VERSION_ID < 70400
ast_assign_op_to_binary_op(zend_ast_attr attr)605 static inline zend_ast_attr ast_assign_op_to_binary_op(zend_ast_attr attr) {
606 switch (attr) {
607 case ZEND_ASSIGN_BW_OR: return ZEND_BW_OR;
608 case ZEND_ASSIGN_BW_AND: return ZEND_BW_AND;
609 case ZEND_ASSIGN_BW_XOR: return ZEND_BW_XOR;
610 case ZEND_ASSIGN_CONCAT: return ZEND_CONCAT;
611 case ZEND_ASSIGN_ADD: return ZEND_ADD;
612 case ZEND_ASSIGN_SUB: return ZEND_SUB;
613 case ZEND_ASSIGN_MUL: return ZEND_MUL;
614 case ZEND_ASSIGN_DIV: return ZEND_DIV;
615 case ZEND_ASSIGN_MOD: return ZEND_MOD;
616 case ZEND_ASSIGN_POW: return ZEND_POW;
617 case ZEND_ASSIGN_SL: return ZEND_SL;
618 case ZEND_ASSIGN_SR: return ZEND_SR;
619 EMPTY_SWITCH_DEFAULT_CASE()
620 }
621 }
622 #endif
623
ast_get_children(zend_ast * ast,ast_state_info_t * state,uint32_t * count)624 static inline zend_ast **ast_get_children(zend_ast *ast, ast_state_info_t *state, uint32_t *count) {
625 if (ast_kind_is_decl(ast->kind)) {
626 zend_ast_decl *decl = (zend_ast_decl *) ast;
627 #if PHP_VERSION_ID >= 80100
628 *count = decl->kind == ZEND_AST_CLASS ? (state->version >= 85 ? 5 : 4) : 5;
629 #elif PHP_VERSION_ID >= 80000
630 *count = decl->kind == ZEND_AST_CLASS ? 4 : 5;
631 #else
632 *count = decl->kind == ZEND_AST_CLASS ? 3 : 4;
633 #endif
634 return decl->child;
635 } else if (zend_ast_is_list(ast)) {
636 zend_ast_list *list = zend_ast_get_list(ast);
637 *count = list->children;
638 return list->child;
639 } else {
640 *count = zend_ast_get_num_children(ast);
641 return ast->child;
642 }
643 }
644
645 static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state);
646
ast_create_virtual_node_ex(zval * zv,zend_ast_kind kind,zend_ast_attr attr,uint32_t lineno,ast_state_info_t * state,uint32_t num_children,...)647 static void ast_create_virtual_node_ex(
648 zval *zv, zend_ast_kind kind, zend_ast_attr attr, uint32_t lineno,
649 ast_state_info_t *state, uint32_t num_children, ...) {
650 va_list va;
651 uint32_t i;
652
653 object_init_ex(zv, ast_node_ce);
654
655 zend_object *obj = Z_OBJ_P(zv);
656
657 AST_NODE_SET_PROP_KIND(obj, kind);
658 AST_NODE_SET_PROP_FLAGS(obj, attr);
659 AST_NODE_SET_PROP_LINENO(obj, lineno);
660
661 array_init_size(AST_NODE_PROP_CHILDREN(obj), num_children);
662 HashTable *children = Z_ARRVAL_P(AST_NODE_PROP_CHILDREN(obj));
663
664 va_start(va, num_children);
665 for (i = 0; i < num_children; i++) {
666 zval *child_zv = va_arg(va, zval *);
667 zend_string *child_name = ast_kind_child_name(kind, i);
668 if (child_name) {
669 zend_hash_add_new(children, child_name, child_zv);
670 } else {
671 zend_hash_next_index_insert(children, child_zv);
672 }
673 }
674 va_end(va);
675 }
676
ast_create_virtual_node(zval * zv,zend_ast_kind kind,zend_ast_attr attr,zend_ast * child,ast_state_info_t * state)677 static void ast_create_virtual_node(
678 zval *zv, zend_ast_kind kind, zend_ast_attr attr, zend_ast *child, ast_state_info_t *state) {
679 zval child_zv;
680 ast_to_zval(&child_zv, child, state);
681 ast_create_virtual_node_ex(
682 zv, kind, attr, zend_ast_get_lineno(child), state, 1, &child_zv);
683 }
684
ast_name_to_zval(zend_ast * child,zend_ast * ast,zval * child_zv,int i,ast_state_info_t * state)685 static inline void ast_name_to_zval(zend_ast *child, zend_ast *ast, zval *child_zv, int i, ast_state_info_t *state) {
686 zend_uchar type;
687 zend_bool is_nullable = 0;
688 if (child->attr & ZEND_TYPE_NULLABLE) {
689 is_nullable = 1;
690 child->attr &= ~ZEND_TYPE_NULLABLE;
691 }
692
693 if (child->attr == ZEND_NAME_FQ) {
694 /* Ensure there is no leading \ for fully-qualified names. This can happen if
695 * something like ('\bar')() is used. */
696 zval *name = zend_ast_get_zval(child);
697 if (Z_STRVAL_P(name)[0] == '\\') {
698 zend_string *new_name = zend_string_init(
699 Z_STRVAL_P(name) + 1, Z_STRLEN_P(name) - 1, 0);
700 zend_string_release(Z_STR_P(name));
701 Z_STR_P(name) = new_name;
702 }
703 }
704
705 if (child->attr == ZEND_NAME_NOT_FQ
706 && ast_is_type(child, ast, i)
707 && (type = lookup_builtin_type(zend_ast_get_str(child)))
708 && (type != IS_MIXED || state->version >= 80)
709 ) {
710 /* Convert "int" etc typehints to TYPE nodes */
711 ast_create_virtual_node_ex(
712 child_zv, ZEND_AST_TYPE, type, zend_ast_get_lineno(child), state, 0);
713 } else {
714 ast_create_virtual_node(child_zv, AST_NAME, child->attr, child, state);
715 }
716
717 if (is_nullable) {
718 /* Create explicit AST_NULLABLE_TYPE node */
719 zval tmp;
720 ZVAL_COPY_VALUE(&tmp, child_zv);
721 ast_create_virtual_node_ex(
722 child_zv, AST_NULLABLE_TYPE, 0, zend_ast_get_lineno(child), state, 1, &tmp);
723 }
724 }
725
ast_fill_children_ht(HashTable * ht,zend_ast * ast,ast_state_info_t * state)726 static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, ast_state_info_t *state) {
727 uint32_t i, count;
728 zend_bool is_list = zend_ast_is_list(ast);
729 zend_ast **children = ast_get_children(ast, state, &count);
730 const zend_ast_kind ast_kind = ast->kind;
731 for (i = 0; i < count; ++i) {
732 zend_ast *child = children[i];
733 zend_string *child_name = !is_list ? ast_kind_child_name(ast_kind, i) : NULL;
734 zval child_zv;
735
736 if (ast_kind == ZEND_AST_STMT_LIST) {
737 if (child != NULL && child->kind == ZEND_AST_STMT_LIST) {
738 ast_fill_children_ht(ht, child, state);
739 continue;
740 }
741 if (child == NULL) {
742 continue;
743 }
744 }
745
746 #if PHP_VERSION_ID >= 80000
747 if (state->version < 80) {
748 switch (ast_kind) {
749 case ZEND_AST_PARAM:
750 if (i >= 3) {
751 /* Skip attributes and doc comment and hooks. */
752 continue;
753 }
754 break;
755 case ZEND_AST_METHOD:
756 case ZEND_AST_FUNC_DECL:
757 case ZEND_AST_CLOSURE:
758 case ZEND_AST_ARROW_FUNC:
759 if (i == 4) {
760 continue;
761 }
762 break;
763 case ZEND_AST_CLASS:
764 if (i >= 3) {
765 continue;
766 }
767 break;
768 case ZEND_AST_PROP_GROUP:
769 if (i == 2) {
770 continue;
771 }
772 break;
773 }
774 }
775 #if PHP_VERSION_ID >= 80100
776 if (ast_kind == ZEND_AST_CLASS && i == 4) {
777 if (state->version < 85) {
778 continue;
779 }
780 }
781 #endif
782 #if PHP_VERSION_ID >= 80300
783 if (ast_kind == ZEND_AST_CLASS_CONST_GROUP && i == 2) {
784 if (state->version < 100) {
785 continue;
786 }
787 }
788 #endif
789 #if PHP_VERSION_ID >= 80400
790 if (ast_kind == ZEND_AST_PROP_ELEM && i == 3) {
791 if (state->version < 110) {
792 continue;
793 }
794 }
795 if (ast_kind == ZEND_AST_PROPERTY_HOOK && (i == 1 || i == 3)) {
796 /* Property hooks don't have uses/returnType but they do have params/stmts/attributes. */
797 continue;
798 }
799 /* Constructor property promotion shorthand can have property hooks. */
800 if (ast_kind == ZEND_AST_PARAM && i == 5) {
801 if (state->version < 110) {
802 continue;
803 }
804 }
805 #endif
806
807 #endif
808 if (ast_is_name(child, ast, i)) {
809 ast_name_to_zval(child, ast, &child_zv, i, state);
810 } else if (child && child->kind == ZEND_AST_TYPE && (child->attr & ZEND_TYPE_NULLABLE)) {
811 child->attr &= ~ZEND_TYPE_NULLABLE;
812 ast_create_virtual_node(&child_zv, AST_NULLABLE_TYPE, 0, child, state);
813 } else if (ast_kind == ZEND_AST_CLOSURE_USES) {
814 ast_create_virtual_node(&child_zv, AST_CLOSURE_VAR, child->attr, child, state);
815 } else if (ast_is_var_name(child, ast, i)) {
816 ast_create_virtual_node(&child_zv, ZEND_AST_VAR, 0, child, state);
817 } else if (ast_should_normalize_list(child, ast, i)) {
818 if (child) {
819 zval tmp;
820 ast_to_zval(&tmp, child, state);
821 ast_create_virtual_node_ex(
822 &child_zv, ZEND_AST_STMT_LIST, 0, zend_ast_get_lineno(child), state, 1, &tmp);
823 } else {
824 ast_create_virtual_node_ex(
825 &child_zv, ZEND_AST_STMT_LIST, 0, zend_ast_get_lineno(ast), state, 0);
826 }
827 } else if (state->version >= 60 && i == 1
828 && (ast_kind == ZEND_AST_FUNC_DECL || ast_kind == ZEND_AST_METHOD)) {
829 /* Skip "uses" child, it is only relevant for closures */
830 continue;
831 #if PHP_VERSION_ID >= 70400
832 } else if (i == 1 && ast_kind == ZEND_AST_ARROW_FUNC) {
833 /* Skip "uses" child since it is always empty */
834 continue;
835 #endif
836 } else if (ast_kind == ZEND_AST_LIST && child != NULL) {
837 /* Emulate simple variable list */
838 ast_to_zval(&child_zv, child->child[0], state);
839 } else {
840 ast_to_zval(&child_zv, child, state);
841 }
842 if (child_name) {
843 #if PHP_VERSION_ID >= 80200
844 if (ast_kind == ZEND_AST_ARROW_FUNC && i == 2) {
845 /* Imitate the native arrow function ast structure used in php 7.4-8.1 for stmts */
846 /* (This is still different from regular functions, which have AST_STMT_LIST) */
847 /* TODO: In a new node type, remove the ZEND_AST_RETURN node instead. */
848 zval tmp;
849 ZVAL_COPY_VALUE(&tmp, &child_zv);
850 ast_create_virtual_node_ex(
851 &child_zv, ZEND_AST_RETURN, 0, zend_ast_get_lineno(child), state, 1, &tmp);
852 }
853 #endif
854 zend_hash_add_new(ht, child_name, &child_zv);
855 } else {
856 zend_hash_next_index_insert(ht, &child_zv);
857 }
858
859 }
860
861 #if PHP_VERSION_ID < 80000
862 if (state->version >= 80) {
863 if (ast_kind == ZEND_AST_PARAM) {
864 zval tmp;
865 ZVAL_NULL(&tmp);
866 zend_hash_add_new(ht, AST_STR(str_attributes), &tmp);
867 zend_hash_add_new(ht, AST_STR(str_docComment), &tmp);
868 return;
869 } else if (ast_kind == ZEND_AST_PROP_GROUP) {
870 zval tmp;
871 ZVAL_NULL(&tmp);
872 zend_hash_add_new(ht, AST_STR(str_attributes), &tmp);
873 return;
874 }
875 }
876 #endif
877
878 #if PHP_VERSION_ID < 80400
879 if (state->version >= 110) {
880 if (ast_kind == ZEND_AST_PARAM || ast_kind == ZEND_AST_PROP_ELEM) {
881 zval tmp;
882 ZVAL_NULL(&tmp);
883 zend_hash_add_new(ht, AST_STR(str_hooks), &tmp);
884 return;
885 }
886 }
887 #endif
888
889 if (ast_kind_is_decl(ast_kind)) {
890 zval id_zval;
891 #if PHP_VERSION_ID < 80000
892 if (state->version >= 80) {
893 zval tmp;
894 ZVAL_NULL(&tmp);
895 zend_hash_add_new(ht, AST_STR(str_attributes), &tmp);
896 }
897 #endif
898
899 #if PHP_VERSION_ID < 80100
900 if (ast_kind == ZEND_AST_CLASS) {
901 if (state->version >= 85) {
902 zval tmp;
903 ZVAL_NULL(&tmp);
904 zend_hash_add_new(ht, AST_STR(str_type), &tmp);
905 }
906 }
907 #endif
908 #if PHP_VERSION_ID < 80300
909 if (ast_kind == ZEND_AST_CLASS_CONST_GROUP) {
910 if (state->version >= 100) {
911 zval tmp;
912 ZVAL_NULL(&tmp);
913 zend_hash_add_new(ht, AST_STR(str_type), &tmp);
914 }
915 }
916 #endif
917 ZVAL_LONG(&id_zval, state->declIdCounter);
918 state->declIdCounter++;
919 zend_hash_add_new(ht, AST_STR(str___declId), &id_zval);
920 }
921 }
922
ast_to_zval(zval * zv,zend_ast * ast,ast_state_info_t * state)923 static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state) {
924 zval tmp_zv;
925
926 if (ast == NULL) {
927 ZVAL_NULL(zv);
928 return;
929 }
930
931 if (ast->kind == ZEND_AST_ZVAL) {
932 ZVAL_COPY(zv, zend_ast_get_zval(ast));
933 return;
934 }
935
936 switch (ast->kind) {
937 #if PHP_VERSION_ID < 70400
938 case ZEND_AST_ASSIGN_OP:
939 ast->attr = ast_assign_op_to_binary_op(ast->attr);
940 break;
941 #endif
942 case ZEND_AST_GREATER:
943 ast->kind = ZEND_AST_BINARY_OP;
944 ast->attr = AST_BINARY_IS_GREATER;
945 break;
946 case ZEND_AST_GREATER_EQUAL:
947 ast->kind = ZEND_AST_BINARY_OP;
948 ast->attr = AST_BINARY_IS_GREATER_OR_EQUAL;
949 break;
950 case ZEND_AST_OR:
951 ast->kind = ZEND_AST_BINARY_OP;
952 ast->attr = AST_BINARY_BOOL_OR;
953 break;
954 case ZEND_AST_AND:
955 ast->kind = ZEND_AST_BINARY_OP;
956 ast->attr = AST_BINARY_BOOL_AND;
957 break;
958 case ZEND_AST_COALESCE:
959 ast->kind = ZEND_AST_BINARY_OP;
960 ast->attr = AST_BINARY_COALESCE;
961 break;
962 case ZEND_AST_SILENCE:
963 ast->kind = ZEND_AST_UNARY_OP;
964 ast->attr = AST_SILENCE;
965 break;
966 case ZEND_AST_UNARY_PLUS:
967 ast->kind = ZEND_AST_UNARY_OP;
968 ast->attr = AST_PLUS;
969 break;
970 case ZEND_AST_UNARY_MINUS:
971 ast->kind = ZEND_AST_UNARY_OP;
972 ast->attr = AST_MINUS;
973 break;
974 #if PHP_VERSION_ID >= 80000
975 case ZEND_AST_CLASS_CONST_GROUP:
976 // ast->child is [AST_CLASS_CONST_DECL, optional attributes_list]
977 if (state->version < 80) {
978 // Keep class constants as a list of numerically indexed values in php 8
979 ast->child[0]->attr = ast->attr;
980 ast_to_zval(zv, ast->child[0], state);
981 return;
982 }
983 break;
984 #endif
985 #if PHP_VERSION_ID >= 70400
986 case ZEND_AST_PROP_GROUP:
987 if (state->version < 70) {
988 // In versions less than 70, just omit property type information entirely.
989 // ast->child is [type_ast, prop_ast]
990 ast_to_zval(zv, ast->child[1], state);
991 // The property visibility is on the AST_PROP_GROUP node.
992 // Add it to the AST_PROP_DECL node for old
993 AST_NODE_SET_PROP_FLAGS(Z_OBJ_P(zv), ast->attr);
994 return;
995 }
996 break;
997 case ZEND_AST_ASSIGN_COALESCE:
998 ast->kind = ZEND_AST_ASSIGN_OP;
999 ast->attr = AST_BINARY_COALESCE;
1000 break;
1001 case ZEND_AST_CLASS_NAME:
1002 if (state->version < 70) {
1003 zval name_zval;
1004 ast_to_zval(&name_zval, ast->child[0], state);
1005 zval class_name_zval;
1006 ast_create_virtual_node_ex(
1007 &class_name_zval, AST_NAME, ast->child[0]->attr, zend_ast_get_lineno(ast), state, 1, &name_zval);
1008 zval const_zval;
1009 ZVAL_STR_COPY(&const_zval, AST_STR(str_class));
1010 ast_create_virtual_node_ex(
1011 zv, ZEND_AST_CLASS_CONST, 0, zend_ast_get_lineno(ast), state, 2, &class_name_zval, &const_zval);
1012 return;
1013 }
1014 break;
1015 #ifdef ZEND_PARENTHESIZED_CONCAT
1016 case ZEND_AST_BINARY_OP:
1017 if (ast->attr == ZEND_PARENTHESIZED_CONCAT) {
1018 ast->attr = ZEND_CONCAT;
1019 }
1020 break;
1021 #endif
1022 #else
1023 case ZEND_AST_CLASS_CONST:
1024 if (state->version >= 70) {
1025 // Convert to an AST_CLASS_NAME instead. This is the opposite of the work done in the ZEND_AST_CLASS_NAME case.
1026 zend_ast *const_name_ast = ast->child[1];
1027 zend_string *str = zend_ast_get_str(const_name_ast);
1028 if (zend_string_equals_ci(AST_STR(str_class), str)) {
1029 zend_ast *class_name_ast = ast->child[0];
1030 zval class_name_zval;
1031 if (class_name_ast->kind == ZEND_AST_ZVAL) {
1032 // e.g. Foo::class
1033 zval class_name_raw_zval;
1034 ZVAL_COPY(&class_name_raw_zval, zend_ast_get_zval(class_name_ast));
1035 ast_create_virtual_node_ex(
1036 &class_name_zval, AST_NAME, class_name_ast->attr, zend_ast_get_lineno(class_name_ast), state, 1, &class_name_raw_zval);
1037 } else {
1038 // e.g. []::class (not a parse error, but a runtime error)
1039 ast_to_zval(&class_name_zval, class_name_ast, state);
1040 }
1041
1042 ast_create_virtual_node_ex(
1043 zv, ZEND_AST_CLASS_NAME, 0, zend_ast_get_lineno(ast), state, 1, &class_name_zval);
1044 return;
1045 }
1046 }
1047 break;
1048 #endif
1049 }
1050
1051 object_init_ex(zv, ast_node_ce);
1052
1053 zend_object *obj = Z_OBJ_P(zv);
1054
1055 zend_ast_kind kind = ast->kind;
1056 AST_NODE_SET_PROP_KIND(obj, kind);
1057
1058 AST_NODE_SET_PROP_LINENO(obj, zend_ast_get_lineno(ast));
1059
1060 array_init(AST_NODE_PROP_CHILDREN(obj));
1061 HashTable *children = Z_ARRVAL_P(AST_NODE_PROP_CHILDREN(obj));
1062
1063 if (ast_kind_is_decl(kind)) {
1064 zend_ast_decl *decl = (zend_ast_decl *) ast;
1065 uint32_t flags = decl->flags;
1066 #if PHP_VERSION_ID >= 80200
1067 if (kind == ZEND_AST_CLASS) {
1068 flags &= ~ZEND_ACC_NO_DYNAMIC_PROPERTIES;
1069 }
1070 #endif
1071
1072 AST_NODE_SET_PROP_FLAGS(obj, flags);
1073
1074 // This is an undeclared dynamic property and has no cache slot.
1075 ast_update_property_long(zv, AST_STR(str_endLineno), decl->end_lineno);
1076
1077 if (kind == ZEND_AST_CLOSURE || kind == ZEND_AST_ARROW_FUNC) {
1078 if (state->version < 110) {
1079 ZVAL_STR(&tmp_zv, AST_STR(str_bracketed_closure));
1080 } else {
1081 /* These never have names. */
1082 ZVAL_UNDEF(&tmp_zv);
1083 }
1084 } else if (decl->name) {
1085 ZVAL_STR(&tmp_zv, decl->name);
1086 Z_TRY_ADDREF(tmp_zv);
1087 } else {
1088 ZVAL_NULL(&tmp_zv);
1089 }
1090 if (!Z_ISUNDEF(tmp_zv)) {
1091 zend_hash_add_new(children, AST_STR(str_name), &tmp_zv);
1092 }
1093
1094 if (decl->doc_comment) {
1095 ZVAL_STR(&tmp_zv, decl->doc_comment);
1096 Z_TRY_ADDREF(tmp_zv);
1097 } else {
1098 ZVAL_NULL(&tmp_zv);
1099 }
1100
1101 zend_hash_add_new(children, AST_STR(str_docComment), &tmp_zv);
1102 } else {
1103 AST_NODE_SET_PROP_FLAGS(obj, ast->attr);
1104 }
1105
1106 ast_fill_children_ht(children, ast, state);
1107 #if PHP_VERSION_ID < 70400
1108 if (ast->kind == ZEND_AST_PROP_DECL && state->version >= 70) {
1109 zval type_zval;
1110 zval prop_group_zval;
1111 ZVAL_COPY_VALUE(&prop_group_zval, zv);
1112 ZVAL_NULL(&type_zval);
1113 // For version 70, create an AST_PROP_GROUP wrapping the created AST_PROP_DECL.
1114 if (state->version >= 80) {
1115 // For version 80, add a null attributes node.
1116 ast_create_virtual_node_ex(
1117 zv, ZEND_AST_PROP_GROUP, ast->attr, zend_ast_get_lineno(ast), state, 3, &type_zval, &prop_group_zval, &type_zval);
1118 } else {
1119 ast_create_virtual_node_ex(
1120 zv, ZEND_AST_PROP_GROUP, ast->attr, zend_ast_get_lineno(ast), state, 2, &type_zval, &prop_group_zval);
1121 }
1122 AST_NODE_SET_PROP_FLAGS(obj, 0);
1123 }
1124 #endif
1125 #if PHP_VERSION_ID < 80000
1126 if (ast->kind == ZEND_AST_CLASS_CONST_DECL && state->version >= 80) {
1127 zval const_decl_zval;
1128 zval attributes_zval;
1129 ZVAL_COPY_VALUE(&const_decl_zval, zv);
1130 ZVAL_NULL(&attributes_zval);
1131 AST_NODE_SET_PROP_FLAGS(obj, 0);
1132 // For version 80, create an AST_CLASS_CONST_GROUP wrapping the created AST_CLASS_CONST_DECL
1133 ast_create_virtual_node_ex(
1134 zv, ZEND_AST_CLASS_CONST_GROUP, ast->attr, zend_ast_get_lineno(ast), state, 2, &const_decl_zval, &attributes_zval);
1135 }
1136 #endif
1137 }
1138
1139 static const zend_long versions[] = {50, 60, 70, 80, 85, 90, 100, 110};
1140 static const size_t versions_count = sizeof(versions)/sizeof(versions[0]);
1141
ast_version_deprecated(zend_long version)1142 static inline zend_bool ast_version_deprecated(zend_long version) {
1143 return version < 70;
1144 }
1145
ast_version_info(void)1146 static zend_string *ast_version_info(void) {
1147 smart_str str = {0};
1148 size_t i;
1149
1150 smart_str_appends(&str, "Current version is ");
1151 smart_str_append_long(&str, AST_CURRENT_VERSION);
1152 smart_str_appends(&str, ". All versions (including experimental): {");
1153 for (i = 0; i < versions_count; ++i) {
1154 if (i != 0) smart_str_appends(&str, ", ");
1155 smart_str_append_long(&str, versions[i]);
1156 }
1157 smart_str_appends(&str, "}");
1158
1159 smart_str_0(&str);
1160 return str.s;
1161 }
1162
ast_version_known(zend_long version)1163 static inline zend_bool ast_version_known(zend_long version) {
1164 size_t i;
1165 for (i = 0; i < versions_count; ++i) {
1166 if (version == versions[i]) {
1167 return 1;
1168 }
1169 }
1170 return 0;
1171 }
1172
ast_check_version(zend_long version)1173 static int ast_check_version(zend_long version) {
1174 zend_string *version_info;
1175
1176 if (ast_version_known(version)) {
1177 if (ast_version_deprecated(version)) {
1178 php_error_docref(NULL, E_DEPRECATED,
1179 "Version " ZEND_LONG_FMT " is deprecated", version);
1180 }
1181 return SUCCESS;
1182 }
1183
1184 version_info = ast_version_info();
1185 if (version != -1) {
1186 ast_throw_exception(spl_ce_LogicException,
1187 "Unknown version " ZEND_LONG_FMT ". %s", version, ZSTR_VAL(version_info));
1188 } else {
1189 ast_throw_exception(spl_ce_LogicException,
1190 "No version specified. %s", ZSTR_VAL(version_info));
1191 }
1192 zend_string_release(version_info);
1193 return FAILURE;
1194 }
1195
PHP_FUNCTION(parse_file)1196 PHP_FUNCTION(parse_file) {
1197 zend_string *filename, *code;
1198 zend_long version = -1;
1199 ast_state_info_t state;
1200 zend_ast *ast;
1201 zend_arena *arena;
1202 php_stream *stream;
1203 zend_error_handling error_handling;
1204
1205 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "P|l", &filename, &version) == FAILURE) {
1206 return;
1207 }
1208
1209 if (ast_check_version(version) == FAILURE) {
1210 return;
1211 }
1212
1213 zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
1214 stream = php_stream_open_wrapper_ex(filename->val, "rb", REPORT_ERRORS, NULL, NULL);
1215 if (!stream) {
1216 zend_restore_error_handling(&error_handling);
1217 return;
1218 }
1219
1220 code = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
1221 php_stream_close(stream);
1222 zend_restore_error_handling(&error_handling);
1223
1224 if (!code) {
1225 /* php_stream_copy_to_mem will return NULL if the file is empty, strangely. */
1226 code = ZSTR_EMPTY_ALLOC();
1227 }
1228
1229 ast = get_ast(code, &arena, filename);
1230 if (!ast) {
1231 zend_string_free(code);
1232 return;
1233 }
1234
1235 state.version = version;
1236 state.declIdCounter = 0;
1237 ast_to_zval(return_value, ast, &state);
1238
1239 zend_string_free(code);
1240 zend_ast_destroy(ast);
1241 zend_arena_destroy(arena);
1242 }
1243
PHP_FUNCTION(parse_code)1244 PHP_FUNCTION(parse_code) {
1245 zend_string *code, *filename = NULL;
1246 zend_long version = -1;
1247 ast_state_info_t state;
1248 zend_ast *ast;
1249 zend_arena *arena;
1250
1251 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "S|lP", &code, &version, &filename) == FAILURE) {
1252 return;
1253 }
1254
1255 if (ast_check_version(version) == FAILURE) {
1256 return;
1257 }
1258
1259 ast = get_ast(code, &arena, filename);
1260 if (!ast) {
1261 return;
1262 }
1263
1264 state.version = version;
1265 state.declIdCounter = 0;
1266 ast_to_zval(return_value, ast, &state);
1267
1268 zend_ast_destroy(ast);
1269 zend_arena_destroy(arena);
1270 }
1271
PHP_FUNCTION(get_kind_name)1272 PHP_FUNCTION(get_kind_name) {
1273 zend_long kind;
1274 const char *name;
1275
1276 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "l", &kind) == FAILURE) {
1277 return;
1278 }
1279
1280 name = ast_kind_to_name(kind);
1281 if (!name) {
1282 ast_throw_exception(spl_ce_LogicException, "Unknown kind " ZEND_LONG_FMT, kind);
1283 return;
1284 }
1285
1286 RETURN_STRING(name);
1287 }
1288
PHP_FUNCTION(kind_uses_flags)1289 PHP_FUNCTION(kind_uses_flags) {
1290 zend_long kind;
1291
1292 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "l", &kind) == FAILURE) {
1293 return;
1294 }
1295
1296 RETURN_BOOL(ast_kind_uses_attr(kind) || ast_kind_is_decl(kind));
1297 }
1298
ast_get_flag_info(uint16_t ast_kind)1299 static inline const ast_flag_info *ast_get_flag_info(uint16_t ast_kind) {
1300 size_t i, flag_info_count = sizeof(flag_info)/sizeof(ast_flag_info);
1301 for (i = 0; i < flag_info_count; i++) {
1302 const ast_flag_info *info = &flag_info[i];
1303 if (info->ast_kind == ast_kind) {
1304 return info;
1305 }
1306 }
1307 return NULL;
1308 }
1309
ast_build_metadata(zval * result)1310 static void ast_build_metadata(zval *result) {
1311 size_t i;
1312 array_init_size(result, ast_kinds_count);
1313 for (i = 0; i < ast_kinds_count; i++) {
1314 zend_ast_kind kind = ast_kinds[i];
1315 const ast_flag_info *flag_info = ast_get_flag_info(kind);
1316 zval info_zv, tmp_zv;
1317 zend_object *obj;
1318
1319 object_init_ex(&info_zv, ast_metadata_ce);
1320 obj = Z_OBJ(info_zv);
1321
1322 /* kind */
1323 ZVAL_LONG(AST_METADATA_PROP_KIND(obj), kind);
1324
1325 /* name */
1326 ZVAL_STRING(AST_METADATA_PROP_NAME(obj), ast_kind_to_name(kind));
1327
1328 /* flags */
1329 array_init(&tmp_zv);
1330 if (flag_info) {
1331 const char **flag;
1332 for (flag = flag_info->flags; *flag; flag++) {
1333 add_next_index_string(&tmp_zv, *flag);
1334 }
1335 }
1336 ZVAL_ARR(AST_METADATA_PROP_FLAGS(obj), Z_ARRVAL(tmp_zv));
1337
1338 /* flagsCombinable */
1339 ZVAL_BOOL(AST_METADATA_PROP_FLAGS_COMBINABLE(obj), flag_info && flag_info->combinable);
1340
1341 add_index_zval(result, kind, &info_zv);
1342 }
1343 }
1344
PHP_FUNCTION(get_metadata)1345 PHP_FUNCTION(get_metadata) {
1346 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "") == FAILURE) {
1347 return;
1348 }
1349
1350 if (Z_ISUNDEF(AST_G(metadata))) {
1351 ast_build_metadata(&AST_G(metadata));
1352 }
1353
1354 ZVAL_COPY(return_value, &AST_G(metadata));
1355 }
1356
PHP_FUNCTION(get_supported_versions)1357 PHP_FUNCTION(get_supported_versions) {
1358 zend_bool exclude_deprecated = 0;
1359 size_t i;
1360
1361 if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|b", &exclude_deprecated) == FAILURE) {
1362 return;
1363 }
1364
1365 array_init(return_value);
1366 for (i = 0; i < versions_count; i++) {
1367 zend_long version = versions[i];
1368 if (!exclude_deprecated || !ast_version_deprecated(version)) {
1369 add_next_index_long(return_value, version);
1370 }
1371 }
1372 }
1373
PHP_METHOD(ast_Node,__construct)1374 PHP_METHOD(ast_Node, __construct) {
1375 int num_args = ZEND_NUM_ARGS();
1376 if (num_args == 0) {
1377 /* If arguments aren't passed, leave them as their default values. */
1378 return;
1379 }
1380
1381 zend_long kind;
1382 zend_long flags;
1383 zval *children;
1384 zend_long lineno;
1385 zend_bool kindNull, flagsNull, linenoNull;
1386
1387 ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 4)
1388 Z_PARAM_OPTIONAL
1389 Z_PARAM_LONG_EX(kind, kindNull, 1, 0)
1390 Z_PARAM_LONG_EX(flags, flagsNull, 1, 0)
1391 Z_PARAM_ARRAY_EX(children, 1, 0)
1392 Z_PARAM_LONG_EX(lineno, linenoNull, 1, 0)
1393 ZEND_PARSE_PARAMETERS_END();
1394
1395 zend_object *obj = Z_OBJ_P(ZEND_THIS);
1396
1397 switch (num_args) {
1398 case 4:
1399 if (!linenoNull) {
1400 AST_NODE_SET_PROP_LINENO(obj, lineno);
1401 }
1402 /* Falls through - break missing intentionally */
1403 case 3:
1404 if (children != NULL) {
1405 ZVAL_COPY(AST_NODE_PROP_CHILDREN(obj), children);
1406 }
1407 /* Falls through - break missing intentionally */
1408 case 2:
1409 if (!flagsNull) {
1410 AST_NODE_SET_PROP_FLAGS(obj, flags);
1411 }
1412 /* Falls through - break missing intentionally */
1413 case 1:
1414 if (!kindNull) {
1415 AST_NODE_SET_PROP_KIND(obj, kind);
1416 }
1417 /* Falls through - break missing intentionally */
1418 case 0:
1419 break;
1420 }
1421 }
1422
PHP_MINFO_FUNCTION(ast)1423 PHP_MINFO_FUNCTION(ast) {
1424 zend_string *info = ast_version_info();
1425
1426 php_info_print_table_start();
1427 php_info_print_table_row(2, "ast support", "enabled");
1428 php_info_print_table_row(2, "extension version", PHP_AST_VERSION);
1429 php_info_print_table_row(2, "AST version", ZSTR_VAL(info));
1430 php_info_print_table_end();
1431
1432 zend_string_release(info);
1433 }
1434
PHP_RINIT_FUNCTION(ast)1435 PHP_RINIT_FUNCTION(ast) {
1436 ZVAL_UNDEF(&AST_G(metadata));
1437 return SUCCESS;
1438 }
1439
PHP_RSHUTDOWN_FUNCTION(ast)1440 PHP_RSHUTDOWN_FUNCTION(ast) {
1441 zval_ptr_dtor(&AST_G(metadata));
1442 return SUCCESS;
1443 }
1444
PHP_MINIT_FUNCTION(ast)1445 PHP_MINIT_FUNCTION(ast) {
1446 zend_class_entry tmp_ce;
1447 zval zv_null;
1448 ZVAL_NULL(&zv_null);
1449
1450 #define X(str, value) \
1451 AST_STR(str_ ## str) = zend_new_interned_string( \
1452 zend_string_init(value, sizeof(value) - 1, 1));
1453 AST_STR_DEFS
1454 #undef X
1455
1456 ast_register_kind_constants(INIT_FUNC_ARGS_PASSTHRU);
1457
1458 ast_register_flag_constant("NAME_FQ", ZEND_NAME_FQ);
1459 ast_register_flag_constant("NAME_NOT_FQ", ZEND_NAME_NOT_FQ);
1460 ast_register_flag_constant("NAME_RELATIVE", ZEND_NAME_RELATIVE);
1461
1462 ast_register_flag_constant("MODIFIER_PUBLIC", ZEND_ACC_PUBLIC);
1463 ast_register_flag_constant("MODIFIER_PROTECTED", ZEND_ACC_PROTECTED);
1464 ast_register_flag_constant("MODIFIER_PRIVATE", ZEND_ACC_PRIVATE);
1465 ast_register_flag_constant("MODIFIER_STATIC", ZEND_ACC_STATIC);
1466 ast_register_flag_constant("MODIFIER_ABSTRACT", ZEND_ACC_ABSTRACT);
1467 ast_register_flag_constant("MODIFIER_FINAL", ZEND_ACC_FINAL);
1468 ast_register_flag_constant("MODIFIER_READONLY", ZEND_ACC_READONLY);
1469
1470 ast_register_flag_constant("PARAM_MODIFIER_PUBLIC", PARAM_MODIFIER_PUBLIC);
1471 ast_register_flag_constant("PARAM_MODIFIER_PROTECTED", PARAM_MODIFIER_PROTECTED);
1472 ast_register_flag_constant("PARAM_MODIFIER_PRIVATE", PARAM_MODIFIER_PRIVATE);
1473
1474 ast_register_flag_constant("RETURNS_REF", ZEND_ACC_RETURN_REFERENCE);
1475 ast_register_flag_constant("FUNC_RETURNS_REF", ZEND_ACC_RETURN_REFERENCE);
1476 ast_register_flag_constant("FUNC_GENERATOR", ZEND_ACC_GENERATOR);
1477
1478 ast_register_flag_constant("ARRAY_ELEM_REF", 1);
1479 ast_register_flag_constant("CLOSURE_USE_REF", ZEND_BIND_REF);
1480
1481 ast_register_flag_constant("CLASS_ABSTRACT", ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
1482 ast_register_flag_constant("CLASS_FINAL", ZEND_ACC_FINAL);
1483 ast_register_flag_constant("CLASS_TRAIT", ZEND_ACC_TRAIT);
1484 ast_register_flag_constant("CLASS_INTERFACE", ZEND_ACC_INTERFACE);
1485 ast_register_flag_constant("CLASS_ANONYMOUS", ZEND_ACC_ANON_CLASS);
1486 ast_register_flag_constant("CLASS_ENUM", ZEND_ACC_ENUM);
1487 ast_register_flag_constant("CLASS_READONLY", ZEND_ACC_READONLY_CLASS);
1488
1489 ast_register_flag_constant("PARAM_REF", ZEND_PARAM_REF);
1490 ast_register_flag_constant("PARAM_VARIADIC", ZEND_PARAM_VARIADIC);
1491
1492 ast_register_flag_constant("TYPE_NULL", IS_NULL);
1493 ast_register_flag_constant("TYPE_FALSE", IS_FALSE);
1494 ast_register_flag_constant("TYPE_TRUE", IS_TRUE);
1495 ast_register_flag_constant("TYPE_BOOL", _IS_BOOL);
1496 ast_register_flag_constant("TYPE_LONG", IS_LONG);
1497 ast_register_flag_constant("TYPE_DOUBLE", IS_DOUBLE);
1498 ast_register_flag_constant("TYPE_STRING", IS_STRING);
1499 ast_register_flag_constant("TYPE_ARRAY", IS_ARRAY);
1500 ast_register_flag_constant("TYPE_OBJECT", IS_OBJECT);
1501 ast_register_flag_constant("TYPE_CALLABLE", IS_CALLABLE);
1502 ast_register_flag_constant("TYPE_VOID", IS_VOID);
1503 ast_register_flag_constant("TYPE_ITERABLE", IS_ITERABLE);
1504 ast_register_flag_constant("TYPE_STATIC", IS_STATIC);
1505 ast_register_flag_constant("TYPE_MIXED", IS_MIXED);
1506 ast_register_flag_constant("TYPE_NEVER", IS_NEVER);
1507
1508 ast_register_flag_constant("UNARY_BOOL_NOT", ZEND_BOOL_NOT);
1509 ast_register_flag_constant("UNARY_BITWISE_NOT", ZEND_BW_NOT);
1510 ast_register_flag_constant("UNARY_SILENCE", AST_SILENCE);
1511 ast_register_flag_constant("UNARY_PLUS", AST_PLUS);
1512 ast_register_flag_constant("UNARY_MINUS", AST_MINUS);
1513
1514 ast_register_flag_constant("BINARY_BOOL_AND", AST_BINARY_BOOL_AND);
1515 ast_register_flag_constant("BINARY_BOOL_OR", AST_BINARY_BOOL_OR);
1516 ast_register_flag_constant("BINARY_BOOL_XOR", ZEND_BOOL_XOR);
1517 ast_register_flag_constant("BINARY_BITWISE_OR", ZEND_BW_OR);
1518 ast_register_flag_constant("BINARY_BITWISE_AND", ZEND_BW_AND);
1519 ast_register_flag_constant("BINARY_BITWISE_XOR", ZEND_BW_XOR);
1520 ast_register_flag_constant("BINARY_CONCAT", ZEND_CONCAT);
1521 ast_register_flag_constant("BINARY_ADD", ZEND_ADD);
1522 ast_register_flag_constant("BINARY_SUB", ZEND_SUB);
1523 ast_register_flag_constant("BINARY_MUL", ZEND_MUL);
1524 ast_register_flag_constant("BINARY_DIV", ZEND_DIV);
1525 ast_register_flag_constant("BINARY_MOD", ZEND_MOD);
1526 ast_register_flag_constant("BINARY_POW", ZEND_POW);
1527 ast_register_flag_constant("BINARY_SHIFT_LEFT", ZEND_SL);
1528 ast_register_flag_constant("BINARY_SHIFT_RIGHT", ZEND_SR);
1529 ast_register_flag_constant("BINARY_IS_IDENTICAL", ZEND_IS_IDENTICAL);
1530 ast_register_flag_constant("BINARY_IS_NOT_IDENTICAL", ZEND_IS_NOT_IDENTICAL);
1531 ast_register_flag_constant("BINARY_IS_EQUAL", ZEND_IS_EQUAL);
1532 ast_register_flag_constant("BINARY_IS_NOT_EQUAL", ZEND_IS_NOT_EQUAL);
1533 ast_register_flag_constant("BINARY_IS_SMALLER", ZEND_IS_SMALLER);
1534 ast_register_flag_constant("BINARY_IS_SMALLER_OR_EQUAL", ZEND_IS_SMALLER_OR_EQUAL);
1535 ast_register_flag_constant("BINARY_IS_GREATER", AST_BINARY_IS_GREATER);
1536 ast_register_flag_constant("BINARY_IS_GREATER_OR_EQUAL", AST_BINARY_IS_GREATER_OR_EQUAL);
1537 ast_register_flag_constant("BINARY_SPACESHIP", ZEND_SPACESHIP);
1538 ast_register_flag_constant("BINARY_COALESCE", AST_BINARY_COALESCE);
1539
1540 ast_register_flag_constant("EXEC_EVAL", ZEND_EVAL);
1541 ast_register_flag_constant("EXEC_INCLUDE", ZEND_INCLUDE);
1542 ast_register_flag_constant("EXEC_INCLUDE_ONCE", ZEND_INCLUDE_ONCE);
1543 ast_register_flag_constant("EXEC_REQUIRE", ZEND_REQUIRE);
1544 ast_register_flag_constant("EXEC_REQUIRE_ONCE", ZEND_REQUIRE_ONCE);
1545
1546 ast_register_flag_constant("USE_NORMAL", ZEND_SYMBOL_CLASS);
1547 ast_register_flag_constant("USE_FUNCTION", ZEND_SYMBOL_FUNCTION);
1548 ast_register_flag_constant("USE_CONST", ZEND_SYMBOL_CONST);
1549
1550 ast_register_flag_constant("MAGIC_LINE", T_LINE);
1551 ast_register_flag_constant("MAGIC_FILE", T_FILE);
1552 ast_register_flag_constant("MAGIC_DIR", T_DIR);
1553 ast_register_flag_constant("MAGIC_NAMESPACE", T_NS_C);
1554 ast_register_flag_constant("MAGIC_FUNCTION", T_FUNC_C);
1555 ast_register_flag_constant("MAGIC_METHOD", T_METHOD_C);
1556 ast_register_flag_constant("MAGIC_CLASS", T_CLASS_C);
1557 ast_register_flag_constant("MAGIC_TRAIT", T_TRAIT_C);
1558
1559 ast_register_flag_constant("ARRAY_SYNTAX_LIST", ZEND_ARRAY_SYNTAX_LIST);
1560 ast_register_flag_constant("ARRAY_SYNTAX_LONG", ZEND_ARRAY_SYNTAX_LONG);
1561 ast_register_flag_constant("ARRAY_SYNTAX_SHORT", ZEND_ARRAY_SYNTAX_SHORT);
1562
1563 ast_register_flag_constant("DIM_ALTERNATIVE_SYNTAX", ZEND_DIM_ALTERNATIVE_SYNTAX);
1564
1565 ast_register_flag_constant("PARENTHESIZED_CONDITIONAL", ZEND_PARENTHESIZED_CONDITIONAL);
1566
1567 ast_register_flag_constant("ENCAPS_VAR_DOLLAR_CURLY", ZEND_ENCAPS_VAR_DOLLAR_CURLY);
1568 ast_register_flag_constant("ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR", ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR);
1569
1570 INIT_CLASS_ENTRY(tmp_ce, "ast\\Node", class_ast_Node_methods);
1571 ast_node_ce = zend_register_internal_class(&tmp_ce);
1572 ast_declare_property(ast_node_ce, AST_STR(str_kind), &zv_null);
1573 ast_declare_property(ast_node_ce, AST_STR(str_flags), &zv_null);
1574 ast_declare_property(ast_node_ce, AST_STR(str_lineno), &zv_null);
1575 ast_declare_property(ast_node_ce, AST_STR(str_children), &zv_null);
1576 #ifdef ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES
1577 zend_add_class_attribute(ast_node_ce, zend_ce_allow_dynamic_properties->name, 0);
1578 ast_node_ce->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
1579 #endif
1580
1581 INIT_CLASS_ENTRY(tmp_ce, "ast\\Metadata", NULL);
1582 ast_metadata_ce = zend_register_internal_class(&tmp_ce);
1583 ast_declare_property(ast_metadata_ce, AST_STR(str_kind), &zv_null);
1584 ast_declare_property(ast_metadata_ce, AST_STR(str_name), &zv_null);
1585 ast_declare_property(ast_metadata_ce, AST_STR(str_flags), &zv_null);
1586 ast_declare_property(ast_metadata_ce, AST_STR(str_flagsCombinable), &zv_null);
1587
1588 return SUCCESS;
1589 }
1590
PHP_MSHUTDOWN_FUNCTION(ast)1591 PHP_MSHUTDOWN_FUNCTION(ast) {
1592 #define X(str, value) zend_string_release(AST_STR(str_ ## str));
1593 AST_STR_DEFS
1594 #undef X
1595
1596 return SUCCESS;
1597 }
1598
1599 zend_module_entry ast_module_entry = {
1600 STANDARD_MODULE_HEADER,
1601 "ast",
1602 ext_functions,
1603 PHP_MINIT(ast),
1604 PHP_MSHUTDOWN(ast),
1605 PHP_RINIT(ast),
1606 PHP_RSHUTDOWN(ast),
1607 PHP_MINFO(ast),
1608 PHP_AST_VERSION,
1609 PHP_MODULE_GLOBALS(ast),
1610 NULL,
1611 NULL,
1612 NULL,
1613 STANDARD_MODULE_PROPERTIES_EX
1614 };
1615
1616 #ifdef COMPILE_DL_AST
1617 ZEND_GET_MODULE(ast)
1618 #endif
1619