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