Skip to content

Commit b0370e6

Browse files
committed
Support php 8.0 "Constructor Promotion" and attributes
Because AST_CLASS_CONST_DECL is a list of nodes, don't add the key "attributes" to the hash table in older AST versions. Add visibility modifiers to AST_PARAM, but only in php 8.0+. MODIFIER_PUBLIC and PARAM_REF are the same value in php 7.4.
1 parent feae85b commit b0370e6

16 files changed

+516
-36
lines changed

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ php:
99
- 7.4
1010
- nightly
1111

12+
matrix:
13+
allow_failures:
14+
- php: master
15+
1216
before_script:
1317
- phpize
1418
- ./configure

README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,12 @@ ast\flags\CLASS_TRAIT
253253
ast\flags\CLASS_INTERFACE
254254
ast\flags\CLASS_ANONYMOUS
255255
256-
// Used by ast\AST_PARAM (cominable)
256+
// Used by ast\AST_PARAM (combinable)
257257
ast\flags\PARAM_REF
258258
ast\flags\PARAM_VARIADIC
259+
ast\flags\MODIFIER_PUBLIC
260+
ast\flags\MODIFIER_PROTECTED
261+
ast\flags\MODIFIER_PRIVATE
259262
260263
// Used by ast\AST_TYPE (exclusive)
261264
ast\flags\TYPE_ARRAY
@@ -361,20 +364,22 @@ This section lists the AST node kinds that are supported and the names of their
361364

362365
```
363366
AST_ARRAY_ELEM: value, key
364-
AST_ARROW_FUNC: name, docComment, params, stmts, returnType
367+
AST_ARROW_FUNC: name, docComment, params, stmts, returnType, attributes
365368
AST_ASSIGN: var, expr
366369
AST_ASSIGN_OP: var, expr
367370
AST_ASSIGN_REF: var, expr
371+
AST_ATTRIBUTE: class, args // php 8.0+ attributes
368372
AST_BINARY_OP: left, right
369373
AST_BREAK: depth
370374
AST_CALL: expr, args
371375
AST_CAST: expr
372376
AST_CATCH: class, var, stmts
373377
AST_CLASS: name, docComment, extends, implements, stmts
374378
AST_CLASS_CONST: class, const
379+
AST_CLASS_CONST_GROUP class, attributes // version 80+
375380
AST_CLASS_NAME: class // version 70+
376381
AST_CLONE: expr
377-
AST_CLOSURE: name, docComment, params, uses, stmts, returnType
382+
AST_CLOSURE: name, docComment, params, uses, stmts, returnType, attributes
378383
AST_CLOSURE_VAR: name
379384
AST_CONDITIONAL: cond, true, false
380385
AST_CONST: name
@@ -388,7 +393,7 @@ AST_EMPTY: expr
388393
AST_EXIT: expr
389394
AST_FOR: init, cond, loop, stmts
390395
AST_FOREACH: expr, value, key, stmts
391-
AST_FUNC_DECL: name, docComment, params, stmts, returnType
396+
AST_FUNC_DECL: name, docComment, params, stmts, returnType, attributes
392397
uses // prior to version 60
393398
AST_GLOBAL: var
394399
AST_GOTO: label
@@ -400,23 +405,23 @@ AST_INSTANCEOF: expr, class
400405
AST_ISSET: var
401406
AST_LABEL: name
402407
AST_MAGIC_CONST:
403-
AST_METHOD: name, docComment, params, stmts, returnType
408+
AST_METHOD: name, docComment, params, stmts, returnType, attributes
404409
uses // prior to version 60
405410
AST_METHOD_CALL: expr, method, args
406411
AST_METHOD_REFERENCE: class, method
407412
AST_NAME: name
408413
AST_NAMESPACE: name, stmts
409414
AST_NEW: class, args
410415
AST_NULLABLE_TYPE: type // Used only since PHP 7.1
411-
AST_PARAM: type, name, default
416+
AST_PARAM: type, name, default, attributes, docComment
412417
AST_POST_DEC: var
413418
AST_POST_INC: var
414419
AST_PRE_DEC: var
415420
AST_PRE_INC: var
416421
AST_PRINT: expr
417422
AST_PROP: expr, prop
418423
AST_PROP_ELEM: name, default, docComment
419-
AST_PROP_GROUP: type, props // version 70+
424+
AST_PROP_GROUP: type, props, attributes // version 70+
420425
AST_REF: var // only used in foreach ($a as &$v)
421426
AST_RETURN: expr
422427
AST_SHELL_EXEC: expr
@@ -443,6 +448,7 @@ AST_YIELD_FROM: expr
443448
// List nodes (numerically indexed children):
444449
AST_ARG_LIST
445450
AST_ARRAY
451+
AST_ATTRIBUTE_LIST // php 8.0+ attributes
446452
AST_CATCH_LIST
447453
AST_CLASS_CONST_DECL
448454
AST_CLOSURE_USES
@@ -483,6 +489,7 @@ are listed.
483489
Available since 1.0.7 (XXX).
484490

485491
* `mixed` type hints are now reported as an `AST_TYPE` with type `TYPE_MIXED` instead of an `AST_NAME`.
492+
* `AST_CLASS_CONST_GROUP` nodes are emitted for php 8.0 class constant declarations with a `const` and an optional `attributes` node.
486493

487494
### 70 (current)
488495

ast.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ static const char *class_flags[] = {
107107
static const char *param_flags[] = {
108108
AST_FLAG(PARAM_REF),
109109
AST_FLAG(PARAM_VARIADIC),
110+
#if PHP_VERSION_ID >= 80000
111+
AST_FLAG(MODIFIER_PUBLIC),
112+
AST_FLAG(MODIFIER_PROTECTED),
113+
AST_FLAG(MODIFIER_PRIVATE),
114+
#endif
110115
NULL
111116
};
112117

@@ -287,6 +292,8 @@ static const ast_flag_info flag_info[] = {
287292
{ ZEND_AST_CONDITIONAL, 1, conditional_flags },
288293
};
289294

295+
// NOTE(tandre) in php 8, to get a writeable pointer to a property, Z_OBJ_HT_P(zv)->get_property_ptr_ptr(Z_OBJ_P(zv), AST_STR(str_propname), BP_VAR_RW, AST_CACHE_SLOT_PROPNAME); can be used.
296+
290297
static inline void ast_update_property(zval *object, zend_string *name, zval *value, void **cache_slot) {
291298
#if PHP_VERSION_ID < 80000
292299
zval name_zv;
@@ -368,7 +375,7 @@ static inline zend_bool ast_is_name(zend_ast *ast, zend_ast *parent, uint32_t i)
368375
return 1;
369376
}
370377
#if PHP_VERSION_ID >= 80000
371-
if (parent->kind == ZEND_AST_TYPE_UNION) {
378+
if (parent->kind == ZEND_AST_TYPE_UNION || parent->kind == ZEND_AST_ATTRIBUTE) {
372379
return 1;
373380
}
374381
#endif
@@ -507,7 +514,11 @@ static inline zend_ast_attr ast_assign_op_to_binary_op(zend_ast_attr attr) {
507514
static inline zend_ast **ast_get_children(zend_ast *ast, uint32_t *count) {
508515
if (ast_kind_is_decl(ast->kind)) {
509516
zend_ast_decl *decl = (zend_ast_decl *) ast;
517+
#if PHP_VERSION_ID >= 80000
518+
*count = decl->kind == ZEND_AST_CLASS ? 4 : 5;
519+
#else
510520
*count = decl->kind == ZEND_AST_CLASS ? 3 : 4;
521+
#endif
511522
return decl->child;
512523
} else if (zend_ast_is_list(ast)) {
513524
zend_ast_list *list = zend_ast_get_list(ast);
@@ -622,6 +633,23 @@ static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, ast_state_info_t
622633
}
623634
}
624635

636+
#if PHP_VERSION_ID >= 80000
637+
if (child == NULL) {
638+
if (i == 4) {
639+
if (ast_kind == ZEND_AST_PARAM || ast_kind == ZEND_AST_METHOD || ast_kind == ZEND_AST_FUNC_DECL || ast_kind == ZEND_AST_CLOSURE || ast_kind == ZEND_AST_ARROW_FUNC) {
640+
continue;
641+
}
642+
} else if (i == 3) {
643+
if (ast_kind == ZEND_AST_PARAM || ast_kind == ZEND_AST_CLASS) {
644+
continue;
645+
}
646+
} else if (i == 2) {
647+
if (ast_kind == ZEND_AST_PROP_GROUP) {
648+
continue;
649+
}
650+
}
651+
}
652+
#endif
625653
/* This AST_CATCH check should occur before ast_is_name() */
626654
#if PHP_VERSION_ID < 70100
627655
if (ast_kind == ZEND_AST_CATCH && i == 0) {
@@ -755,6 +783,15 @@ static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state) {
755783
ast->kind = ZEND_AST_UNARY_OP;
756784
ast->attr = AST_MINUS;
757785
break;
786+
#if PHP_VERSION_ID >= 80000
787+
case ZEND_AST_CLASS_CONST_GROUP:
788+
// ast->child is [AST_CLASS_CONST_DECL, optional attributes_list]
789+
if (state->version < 80) {
790+
// Keep class constants as a list of numerically indexed values in php 8
791+
ast_to_zval(zv, ast->child[0], state);
792+
return;
793+
}
794+
#endif
758795
#if PHP_VERSION_ID >= 70400
759796
case ZEND_AST_PROP_GROUP:
760797
if (state->version < 70) {
@@ -884,6 +921,16 @@ static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state) {
884921
ast_update_property_long(&prop_group_zval, AST_STR(str_flags), 0, AST_CACHE_SLOT_FLAGS);
885922
}
886923
#endif
924+
#if PHP_VERSION_ID < 80000
925+
if (ast->kind == ZEND_AST_CLASS_CONST_DECL && state->version >= 80) {
926+
zval const_decl_zval = *zv;
927+
zval attributes_zval = *zv;
928+
ZVAL_NULL(&attributes_zval);
929+
// For version 80, create an AST_CLASS_CONST_GROUP wrapping the created AST_CLASS_CONST_DECL
930+
ast_create_virtual_node_ex(
931+
zv, ZEND_AST_CLASS_CONST_GROUP, 0, zend_ast_get_lineno(ast), state, 2, &const_decl_zval, &attributes_zval);
932+
}
933+
#endif
887934
}
888935

889936
static const zend_long versions[] = {50, 60, 70, 80};

ast_data.c

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const zend_ast_kind ast_kinds[] = {
1919
ZEND_AST_TRAIT_ADAPTATIONS,
2020
ZEND_AST_USE,
2121
ZEND_AST_TYPE_UNION,
22+
ZEND_AST_ATTRIBUTE_LIST,
2223
AST_NAME,
2324
AST_CLOSURE_VAR,
2425
AST_NULLABLE_TYPE,
@@ -58,6 +59,7 @@ const zend_ast_kind ast_kinds[] = {
5859
ZEND_AST_BREAK,
5960
ZEND_AST_CONTINUE,
6061
ZEND_AST_CLASS_NAME,
62+
ZEND_AST_CLASS_CONST_GROUP,
6163
ZEND_AST_DIM,
6264
ZEND_AST_PROP,
6365
ZEND_AST_STATIC_PROP,
@@ -88,14 +90,15 @@ const zend_ast_kind ast_kinds[] = {
8890
ZEND_AST_USE_ELEM,
8991
ZEND_AST_TRAIT_ALIAS,
9092
ZEND_AST_GROUP_USE,
93+
ZEND_AST_ATTRIBUTE,
9194
ZEND_AST_METHOD_CALL,
9295
ZEND_AST_STATIC_CALL,
9396
ZEND_AST_CONDITIONAL,
9497
ZEND_AST_TRY,
9598
ZEND_AST_CATCH,
96-
ZEND_AST_PARAM,
9799
ZEND_AST_FOR,
98100
ZEND_AST_FOREACH,
101+
ZEND_AST_PARAM,
99102
};
100103

101104
const size_t ast_kinds_count = sizeof(ast_kinds) / sizeof(ast_kinds[0]);
@@ -120,6 +123,7 @@ const char *ast_kind_to_name(zend_ast_kind kind) {
120123
case ZEND_AST_TRAIT_ADAPTATIONS: return "AST_TRAIT_ADAPTATIONS";
121124
case ZEND_AST_USE: return "AST_USE";
122125
case ZEND_AST_TYPE_UNION: return "AST_TYPE_UNION";
126+
case ZEND_AST_ATTRIBUTE_LIST: return "AST_ATTRIBUTE_LIST";
123127
case AST_NAME: return "AST_NAME";
124128
case AST_CLOSURE_VAR: return "AST_CLOSURE_VAR";
125129
case AST_NULLABLE_TYPE: return "AST_NULLABLE_TYPE";
@@ -159,6 +163,7 @@ const char *ast_kind_to_name(zend_ast_kind kind) {
159163
case ZEND_AST_BREAK: return "AST_BREAK";
160164
case ZEND_AST_CONTINUE: return "AST_CONTINUE";
161165
case ZEND_AST_CLASS_NAME: return "AST_CLASS_NAME";
166+
case ZEND_AST_CLASS_CONST_GROUP: return "AST_CLASS_CONST_GROUP";
162167
case ZEND_AST_DIM: return "AST_DIM";
163168
case ZEND_AST_PROP: return "AST_PROP";
164169
case ZEND_AST_STATIC_PROP: return "AST_STATIC_PROP";
@@ -189,14 +194,15 @@ const char *ast_kind_to_name(zend_ast_kind kind) {
189194
case ZEND_AST_USE_ELEM: return "AST_USE_ELEM";
190195
case ZEND_AST_TRAIT_ALIAS: return "AST_TRAIT_ALIAS";
191196
case ZEND_AST_GROUP_USE: return "AST_GROUP_USE";
197+
case ZEND_AST_ATTRIBUTE: return "AST_ATTRIBUTE";
192198
case ZEND_AST_METHOD_CALL: return "AST_METHOD_CALL";
193199
case ZEND_AST_STATIC_CALL: return "AST_STATIC_CALL";
194200
case ZEND_AST_CONDITIONAL: return "AST_CONDITIONAL";
195201
case ZEND_AST_TRY: return "AST_TRY";
196202
case ZEND_AST_CATCH: return "AST_CATCH";
197-
case ZEND_AST_PARAM: return "AST_PARAM";
198203
case ZEND_AST_FOR: return "AST_FOR";
199204
case ZEND_AST_FOREACH: return "AST_FOREACH";
205+
case ZEND_AST_PARAM: return "AST_PARAM";
200206
}
201207

202208
return NULL;
@@ -225,6 +231,7 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
225231
case 1: return AST_STR(str_uses);
226232
case 2: return AST_STR(str_stmts);
227233
case 3: return AST_STR(str_returnType);
234+
case 4: return AST_STR(str_attributes);
228235
}
229236
return NULL;
230237
case ZEND_AST_CLOSURE:
@@ -233,6 +240,7 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
233240
case 1: return AST_STR(str_uses);
234241
case 2: return AST_STR(str_stmts);
235242
case 3: return AST_STR(str_returnType);
243+
case 4: return AST_STR(str_attributes);
236244
}
237245
return NULL;
238246
case ZEND_AST_METHOD:
@@ -241,6 +249,7 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
241249
case 1: return AST_STR(str_uses);
242250
case 2: return AST_STR(str_stmts);
243251
case 3: return AST_STR(str_returnType);
252+
case 4: return AST_STR(str_attributes);
244253
}
245254
return NULL;
246255
case ZEND_AST_ARROW_FUNC:
@@ -249,6 +258,7 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
249258
case 1: return AST_STR(str_uses);
250259
case 2: return AST_STR(str_stmts);
251260
case 3: return AST_STR(str_returnType);
261+
case 4: return AST_STR(str_attributes);
252262
}
253263
return NULL;
254264
case ZEND_AST_CLASS:
@@ -407,6 +417,12 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
407417
case 0: return AST_STR(str_class);
408418
}
409419
return NULL;
420+
case ZEND_AST_CLASS_CONST_GROUP:
421+
switch (child) {
422+
case 0: return AST_STR(str_const);
423+
case 1: return AST_STR(str_attributes);
424+
}
425+
return NULL;
410426
case ZEND_AST_DIM:
411427
switch (child) {
412428
case 0: return AST_STR(str_expr);
@@ -589,6 +605,12 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
589605
case 1: return AST_STR(str_uses);
590606
}
591607
return NULL;
608+
case ZEND_AST_ATTRIBUTE:
609+
switch (child) {
610+
case 0: return AST_STR(str_class);
611+
case 1: return AST_STR(str_args);
612+
}
613+
return NULL;
592614
case ZEND_AST_METHOD_CALL:
593615
switch (child) {
594616
case 0: return AST_STR(str_expr);
@@ -624,13 +646,6 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
624646
case 2: return AST_STR(str_stmts);
625647
}
626648
return NULL;
627-
case ZEND_AST_PARAM:
628-
switch (child) {
629-
case 0: return AST_STR(str_type);
630-
case 1: return AST_STR(str_name);
631-
case 2: return AST_STR(str_default);
632-
}
633-
return NULL;
634649
case ZEND_AST_FOR:
635650
switch (child) {
636651
case 0: return AST_STR(str_init);
@@ -647,6 +662,15 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
647662
case 3: return AST_STR(str_stmts);
648663
}
649664
return NULL;
665+
case ZEND_AST_PARAM:
666+
switch (child) {
667+
case 0: return AST_STR(str_type);
668+
case 1: return AST_STR(str_name);
669+
case 2: return AST_STR(str_default);
670+
case 3: return AST_STR(str_attributes);
671+
case 4: return AST_STR(str_docComment);
672+
}
673+
return NULL;
650674
}
651675

652676
return NULL;
@@ -671,6 +695,7 @@ void ast_register_kind_constants(INIT_FUNC_ARGS) {
671695
REGISTER_NS_LONG_CONSTANT("ast", "AST_TRAIT_ADAPTATIONS", ZEND_AST_TRAIT_ADAPTATIONS, CONST_CS | CONST_PERSISTENT);
672696
REGISTER_NS_LONG_CONSTANT("ast", "AST_USE", ZEND_AST_USE, CONST_CS | CONST_PERSISTENT);
673697
REGISTER_NS_LONG_CONSTANT("ast", "AST_TYPE_UNION", ZEND_AST_TYPE_UNION, CONST_CS | CONST_PERSISTENT);
698+
REGISTER_NS_LONG_CONSTANT("ast", "AST_ATTRIBUTE_LIST", ZEND_AST_ATTRIBUTE_LIST, CONST_CS | CONST_PERSISTENT);
674699
REGISTER_NS_LONG_CONSTANT("ast", "AST_NAME", AST_NAME, CONST_CS | CONST_PERSISTENT);
675700
REGISTER_NS_LONG_CONSTANT("ast", "AST_CLOSURE_VAR", AST_CLOSURE_VAR, CONST_CS | CONST_PERSISTENT);
676701
REGISTER_NS_LONG_CONSTANT("ast", "AST_NULLABLE_TYPE", AST_NULLABLE_TYPE, CONST_CS | CONST_PERSISTENT);
@@ -710,6 +735,7 @@ void ast_register_kind_constants(INIT_FUNC_ARGS) {
710735
REGISTER_NS_LONG_CONSTANT("ast", "AST_BREAK", ZEND_AST_BREAK, CONST_CS | CONST_PERSISTENT);
711736
REGISTER_NS_LONG_CONSTANT("ast", "AST_CONTINUE", ZEND_AST_CONTINUE, CONST_CS | CONST_PERSISTENT);
712737
REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS_NAME", ZEND_AST_CLASS_NAME, CONST_CS | CONST_PERSISTENT);
738+
REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS_CONST_GROUP", ZEND_AST_CLASS_CONST_GROUP, CONST_CS | CONST_PERSISTENT);
713739
REGISTER_NS_LONG_CONSTANT("ast", "AST_DIM", ZEND_AST_DIM, CONST_CS | CONST_PERSISTENT);
714740
REGISTER_NS_LONG_CONSTANT("ast", "AST_PROP", ZEND_AST_PROP, CONST_CS | CONST_PERSISTENT);
715741
REGISTER_NS_LONG_CONSTANT("ast", "AST_STATIC_PROP", ZEND_AST_STATIC_PROP, CONST_CS | CONST_PERSISTENT);
@@ -740,12 +766,13 @@ void ast_register_kind_constants(INIT_FUNC_ARGS) {
740766
REGISTER_NS_LONG_CONSTANT("ast", "AST_USE_ELEM", ZEND_AST_USE_ELEM, CONST_CS | CONST_PERSISTENT);
741767
REGISTER_NS_LONG_CONSTANT("ast", "AST_TRAIT_ALIAS", ZEND_AST_TRAIT_ALIAS, CONST_CS | CONST_PERSISTENT);
742768
REGISTER_NS_LONG_CONSTANT("ast", "AST_GROUP_USE", ZEND_AST_GROUP_USE, CONST_CS | CONST_PERSISTENT);
769+
REGISTER_NS_LONG_CONSTANT("ast", "AST_ATTRIBUTE", ZEND_AST_ATTRIBUTE, CONST_CS | CONST_PERSISTENT);
743770
REGISTER_NS_LONG_CONSTANT("ast", "AST_METHOD_CALL", ZEND_AST_METHOD_CALL, CONST_CS | CONST_PERSISTENT);
744771
REGISTER_NS_LONG_CONSTANT("ast", "AST_STATIC_CALL", ZEND_AST_STATIC_CALL, CONST_CS | CONST_PERSISTENT);
745772
REGISTER_NS_LONG_CONSTANT("ast", "AST_CONDITIONAL", ZEND_AST_CONDITIONAL, CONST_CS | CONST_PERSISTENT);
746773
REGISTER_NS_LONG_CONSTANT("ast", "AST_TRY", ZEND_AST_TRY, CONST_CS | CONST_PERSISTENT);
747774
REGISTER_NS_LONG_CONSTANT("ast", "AST_CATCH", ZEND_AST_CATCH, CONST_CS | CONST_PERSISTENT);
748-
REGISTER_NS_LONG_CONSTANT("ast", "AST_PARAM", ZEND_AST_PARAM, CONST_CS | CONST_PERSISTENT);
749775
REGISTER_NS_LONG_CONSTANT("ast", "AST_FOR", ZEND_AST_FOR, CONST_CS | CONST_PERSISTENT);
750776
REGISTER_NS_LONG_CONSTANT("ast", "AST_FOREACH", ZEND_AST_FOREACH, CONST_CS | CONST_PERSISTENT);
777+
REGISTER_NS_LONG_CONSTANT("ast", "AST_PARAM", ZEND_AST_PARAM, CONST_CS | CONST_PERSISTENT);
751778
}

0 commit comments

Comments
 (0)