xref: /php-ast/ast.c (revision 1fc2c3a1)
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