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