Skip to content

Commit c69e2de

Browse files
committed
Implemented grouped attribute syntax RFC.
1 parent 6ddc196 commit c69e2de

File tree

5 files changed

+79
-53
lines changed

5 files changed

+79
-53
lines changed

Zend/tests/attributes/012_ast_export.phpt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,32 @@ assert(0 && ($a = function () {
2525

2626
?>
2727
--EXPECTF--
28-
Warning: assert(): assert(0 && ($a = @[A1] @[A2] function ($a, @[A3(1)] $b) {
28+
Warning: assert(): assert(0 && ($a = @[@[A1]]@[@[A2]] function ($a, @[@[A3(1)]] $b) {
2929
})) failed in %s on line %d
3030

31-
Warning: assert(): assert(0 && ($a = @[A1(1, 2, 1 + 2)] fn() => 1)) failed in %s on line %d
31+
Warning: assert(): assert(0 && ($a = @[@[A1(1, 2, 1 + 2)]] fn() => 1)) failed in %s on line %d
3232

33-
Warning: assert(): assert(0 && ($a = new @[A1] class {
34-
@[A1]
35-
@[A2]
33+
Warning: assert(): assert(0 && ($a = new @[@[A1]] class {
34+
@[@[A1]]@[@[A2]]
3635
public const FOO = 'foo';
37-
@[A2]
36+
@[@[A2]]
3837
public $x;
39-
@[A3]
38+
@[@[A3]]
4039
public function a() {
4140
}
4241

4342
})) failed in %s on line %d
4443

4544
Warning: assert(): assert(0 && ($a = function () {
46-
@[A1]
45+
@[@[A1]]
4746
class Test1 {
4847
}
4948

50-
@[A2]
49+
@[@[A2]]
5150
interface Test2 {
5251
}
5352

54-
@[A3]
53+
@[@[A3]]
5554
trait Test3 {
5655
}
5756

Zend/zend_ast.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,19 +1349,21 @@ static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_d
13491349
smart_str_appends(str, "}");
13501350
}
13511351

1352-
static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
1352+
static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) {
13531353
zend_ast_list *list = zend_ast_get_list(ast);
1354-
uint32_t i;
1354+
uint32_t i, j;
13551355

13561356
for (i = 0; i < list->children; i++) {
13571357
zend_ast *attr = list->child[i];
13581358

13591359
smart_str_appends(str, "@[");
1360+
if (i) {
1361+
smart_str_appends(str, ", ");
1362+
}
13601363
zend_ast_export_ns_name(str, attr->child[0], 0, indent);
13611364

13621365
if (attr->child[1]) {
13631366
zend_ast_list *args = zend_ast_get_list(attr->child[1]);
1364-
uint32_t j;
13651367

13661368
smart_str_appendc(str, '(');
13671369
for (j = 0; j < args->children; j++) {
@@ -1374,13 +1376,24 @@ static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast,
13741376
}
13751377

13761378
smart_str_appendc(str, ']');
1379+
}
1380+
}
13771381

1378-
if (newlines) {
1379-
smart_str_appendc(str, '\n');
1380-
zend_ast_export_indent(str, indent);
1381-
} else {
1382-
smart_str_appendc(str, ' ');
1383-
}
1382+
static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
1383+
zend_ast_list *list = zend_ast_get_list(ast);
1384+
uint32_t i;
1385+
1386+
for (i = 0; i < list->children; i++) {
1387+
smart_str_appends(str, "@[");
1388+
zend_ast_export_attribute_group(str, list->child[i], indent);
1389+
smart_str_appends(str, "]");
1390+
}
1391+
1392+
if (newlines) {
1393+
smart_str_appendc(str, '\n');
1394+
zend_ast_export_indent(str, indent);
1395+
} else {
1396+
smart_str_appendc(str, ' ');
13841397
}
13851398
}
13861399

Zend/zend_ast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ enum _zend_ast_kind {
6363
ZEND_AST_USE,
6464
ZEND_AST_TYPE_UNION,
6565
ZEND_AST_ATTRIBUTE_LIST,
66+
ZEND_AST_ATTRIBUTE_GROUP,
6667
ZEND_AST_MATCH_ARM_LIST,
6768

6869
/* 0 child nodes */

Zend/zend_compile.c

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6197,51 +6197,57 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
61976197
zend_internal_attribute *config;
61986198

61996199
zend_ast_list *list = zend_ast_get_list(ast);
6200-
uint32_t i, j;
6200+
uint32_t g, i, j;
62016201

62026202
ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);
62036203

6204-
for (i = 0; i < list->children; i++) {
6205-
ZEND_ASSERT(list->child[i]->kind == ZEND_AST_ATTRIBUTE);
6204+
for (g = 0; g < list->children; g++) {
6205+
zend_ast_list *group = zend_ast_get_list(list->child[g]);
62066206

6207-
zend_ast *el = list->child[i];
6208-
zend_string *name = zend_resolve_class_name_ast(el->child[0]);
6209-
zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
6207+
ZEND_ASSERT(group->kind == ZEND_AST_ATTRIBUTE_GROUP);
62106208

6211-
attr = zend_add_attribute(attributes, 0, offset, name, args ? args->children : 0);
6212-
zend_string_release(name);
6209+
for (i = 0; i < group->children; i++) {
6210+
ZEND_ASSERT(group->child[i]->kind == ZEND_AST_ATTRIBUTE);
62136211

6214-
/* Populate arguments */
6215-
if (args) {
6216-
ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);
6212+
zend_ast *el = group->child[i];
6213+
zend_string *name = zend_resolve_class_name_ast(el->child[0]);
6214+
zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
62176215

6218-
zend_bool uses_named_args = 0;
6219-
for (j = 0; j < args->children; j++) {
6220-
zend_ast *arg_ast = args->child[j];
6216+
attr = zend_add_attribute(attributes, 0, offset, name, args ? args->children : 0);
6217+
zend_string_release(name);
62216218

6222-
if (arg_ast->kind == ZEND_AST_UNPACK) {
6223-
zend_error_noreturn(E_COMPILE_ERROR,
6224-
"Cannot use unpacking in attribute argument list");
6225-
}
6219+
/* Populate arguments */
6220+
if (args) {
6221+
ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);
62266222

6227-
if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
6228-
attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
6229-
arg_ast = arg_ast->child[1];
6230-
uses_named_args = 1;
6223+
zend_bool uses_named_args = 0;
6224+
for (j = 0; j < args->children; j++) {
6225+
zend_ast *arg_ast = args->child[j];
62316226

6232-
for (uint32_t k = 0; k < j; k++) {
6233-
if (attr->args[k].name &&
6234-
zend_string_equals(attr->args[k].name, attr->args[j].name)) {
6235-
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
6236-
ZSTR_VAL(attr->args[j].name));
6227+
if (arg_ast->kind == ZEND_AST_UNPACK) {
6228+
zend_error_noreturn(E_COMPILE_ERROR,
6229+
"Cannot use unpacking in attribute argument list");
6230+
}
6231+
6232+
if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
6233+
attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
6234+
arg_ast = arg_ast->child[1];
6235+
uses_named_args = 1;
6236+
6237+
for (uint32_t k = 0; k < j; k++) {
6238+
if (attr->args[k].name &&
6239+
zend_string_equals(attr->args[k].name, attr->args[j].name)) {
6240+
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
6241+
ZSTR_VAL(attr->args[j].name));
6242+
}
62376243
}
6244+
} else if (uses_named_args) {
6245+
zend_error_noreturn(E_COMPILE_ERROR,
6246+
"Cannot use positional argument after named argument");
62386247
}
6239-
} else if (uses_named_args) {
6240-
zend_error_noreturn(E_COMPILE_ERROR,
6241-
"Cannot use positional argument after named argument");
6242-
}
62436248

6244-
zend_const_expr_to_zval(&attr->args[j].value, arg_ast);
6249+
zend_const_expr_to_zval(&attr->args[j].value, arg_ast);
6250+
}
62456251
}
62466252
}
62476253
}

Zend/zend_language_parser.y

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
266266
%type <ast> identifier type_expr_without_static union_type_without_static
267267
%type <ast> inline_function union_type
268268
%type <ast> attributed_statement attributed_class_statement attributed_parameter
269-
%type <ast> attribute_decl attribute attributes namespace_declaration_name
269+
%type <ast> attribute_decl attribute attributes attribute_group namespace_declaration_name
270270
%type <ast> match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list
271271

272272
%type <num> returns_ref function fn is_reference is_variadic variable_modifiers
@@ -345,8 +345,15 @@ attribute_decl:
345345
{ $$ = zend_ast_create(ZEND_AST_ATTRIBUTE, $1, $2); }
346346
;
347347

348+
attribute_group:
349+
attribute_decl
350+
{ $$ = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_GROUP, $1); }
351+
| attribute_group ',' attribute_decl
352+
{ $$ = zend_ast_list_add($1, $3); }
353+
;
354+
348355
attribute:
349-
T_ATTRIBUTE attribute_decl ']' { $$ = $2; }
356+
T_ATTRIBUTE attribute_group possible_comma ']' { $$ = $2; }
350357
;
351358

352359
attributes:

0 commit comments

Comments
 (0)