Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implemented grouped attribute syntax RFC.
  • Loading branch information
beberlei committed Aug 15, 2020
commit e515a5093a1b7697152a003f997ff9052fac230d
20 changes: 15 additions & 5 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,19 +1349,20 @@ static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_d
smart_str_appends(str, "}");
}

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

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

smart_str_appends(str, "@[");
if (i) {
smart_str_appends(str, ", ");
}
zend_ast_export_ns_name(str, attr->child[0], 0, indent);

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

smart_str_appendc(str, '(');
for (j = 0; j < args->children; j++) {
Expand All @@ -1372,8 +1373,17 @@ static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast,
}
smart_str_appendc(str, ')');
}
}
}

smart_str_appendc(str, ']');
static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;

for (i = 0; i < list->children; i++) {
smart_str_appends(str, "@[");
zend_ast_export_attribute_group(str, list->child[i], indent);
smart_str_appends(str, "]");

if (newlines) {
smart_str_appendc(str, '\n');
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ enum _zend_ast_kind {
ZEND_AST_USE,
ZEND_AST_TYPE_UNION,
ZEND_AST_ATTRIBUTE_LIST,
ZEND_AST_ATTRIBUTE_GROUP,
ZEND_AST_MATCH_ARM_LIST,

/* 0 child nodes */
Expand Down
70 changes: 38 additions & 32 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -6197,51 +6197,57 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
zend_internal_attribute *config;

zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i, j;
uint32_t g, i, j;

ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);

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

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

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

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

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

if (arg_ast->kind == ZEND_AST_UNPACK) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use unpacking in attribute argument list");
}
/* Populate arguments */
if (args) {
ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);

if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
arg_ast = arg_ast->child[1];
uses_named_args = 1;
zend_bool uses_named_args = 0;
for (j = 0; j < args->children; j++) {
zend_ast *arg_ast = args->child[j];

for (uint32_t k = 0; k < j; k++) {
if (attr->args[k].name &&
zend_string_equals(attr->args[k].name, attr->args[j].name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
ZSTR_VAL(attr->args[j].name));
if (arg_ast->kind == ZEND_AST_UNPACK) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use unpacking in attribute argument list");
}

if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
arg_ast = arg_ast->child[1];
uses_named_args = 1;

for (uint32_t k = 0; k < j; k++) {
if (attr->args[k].name &&
zend_string_equals(attr->args[k].name, attr->args[j].name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
ZSTR_VAL(attr->args[j].name));
}
}
} else if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use positional argument after named argument");
}
} else if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use positional argument after named argument");
}

zend_const_expr_to_zval(&attr->args[j].value, arg_ast);
zend_const_expr_to_zval(&attr->args[j].value, arg_ast);
}
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> identifier type_expr_without_static union_type_without_static
%type <ast> inline_function union_type
%type <ast> attributed_statement attributed_class_statement attributed_parameter
%type <ast> attribute_decl attribute attributes namespace_declaration_name
%type <ast> attribute_decl attribute attributes attribute_group namespace_declaration_name
%type <ast> match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list

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

attribute_group:
attribute_decl
{ $$ = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_GROUP, $1); }
| attribute_group ',' attribute_decl
{ $$ = zend_ast_list_add($1, $3); }
;

attribute:
T_ATTRIBUTE attribute_decl ']' { $$ = $2; }
T_ATTRIBUTE attribute_group possible_comma ']' { $$ = $2; }
;

attributes:
Expand Down