From 1e55e5d7b91d75943185dfa50bbe3d84e0577cdd Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Fri, 31 Jul 2020 12:56:37 +0200 Subject: [PATCH 1/2] Change Attributes Syntax from @@Attr to @[Attr] --- Zend/tests/attributes/001_placement.phpt | 26 ++++++------- Zend/tests/attributes/002_rfcexample.phpt | 4 +- Zend/tests/attributes/003_ast_nodes.phpt | 12 +++--- .../tests/attributes/004_name_resolution.phpt | 10 ++--- Zend/tests/attributes/005_objects.phpt | 20 +++++----- Zend/tests/attributes/006_filter.phpt | 16 ++++---- .../attributes/008_wrong_attribution.phpt | 2 +- .../009_doctrine_annotations_example.phpt | 24 ++++++------ .../010_unsupported_const_expression.phpt | 2 +- Zend/tests/attributes/011_inheritance.phpt | 10 ++--- Zend/tests/attributes/012_ast_export.phpt | 38 +++++++++---------- Zend/tests/attributes/013_class_scope.phpt | 16 ++++---- .../attributes/014_class_const_group.phpt | 2 +- Zend/tests/attributes/015_property_group.phpt | 2 +- .../016_custom_attribute_validation.phpt | 4 +- Zend/tests/attributes/017_closure_scope.phpt | 2 +- .../018_fatal_error_in_argument.phpt | 2 +- .../019_variable_attribute_name.phpt | 2 +- .../020_userland_attribute_validation.phpt | 12 +++--- ...021_attribute_flags_type_is_validated.phpt | 2 +- ...22_attribute_flags_value_is_validated.phpt | 2 +- .../023_ast_node_in_validation.phpt | 2 +- .../024_internal_target_validation.phpt | 2 +- .../025_internal_repeatable_validation.phpt | 4 +- Zend/tests/attributes/026_unpack_in_args.phpt | 2 +- .../attributes/027_trailing_comma_args.phpt | 4 +- Zend/tests/bug79897.phpt | 4 +- Zend/tests/ctor_promotion_attributes.phpt | 2 +- Zend/tests/named_params/attributes.phpt | 6 +-- .../attributes_duplicate_named_param.phpt | 2 +- .../named_params/attributes_named_flags.phpt | 4 +- .../attributes_named_flags_incorrect.phpt | 4 +- .../attributes_positional_after_named.phpt | 4 +- .../globalNonSimpleVariableError.phpt | 2 +- Zend/zend_ast.c | 4 +- Zend/zend_language_parser.y | 4 +- Zend/zend_language_scanner.l | 3 +- ext/tokenizer/tests/attributes.phpt | 4 +- ext/zend_test/test.c | 2 +- 39 files changed, 136 insertions(+), 133 deletions(-) diff --git a/Zend/tests/attributes/001_placement.phpt b/Zend/tests/attributes/001_placement.phpt index 9bf9c4d2f761..4dd5cdbf53a0 100644 --- a/Zend/tests/attributes/001_placement.phpt +++ b/Zend/tests/attributes/001_placement.phpt @@ -3,27 +3,27 @@ Attributes can be placed on all supported elements. --FILE-- 1; +$f3 = @[A1(10)] fn () => 1; $ref = new \ReflectionClass(Foo::class); @@ -43,11 +43,11 @@ $sources = [ foreach ($sources as $r) { $attr = $r->getAttributes(); var_dump(get_class($r), count($attr)); - + foreach ($attr as $a) { var_dump($a->getName(), $a->getArguments()); } - + echo "\n"; } diff --git a/Zend/tests/attributes/002_rfcexample.phpt b/Zend/tests/attributes/002_rfcexample.phpt index bc608c3eed0d..8d38983efb0f 100644 --- a/Zend/tests/attributes/002_rfcexample.phpt +++ b/Zend/tests/attributes/002_rfcexample.phpt @@ -6,7 +6,7 @@ Attributes: Example from Attributes RFC namespace My\Attributes { use Attribute; - @@Attribute + @[Attribute] class SingleArgument { public $argumentValue; @@ -19,7 +19,7 @@ namespace My\Attributes { namespace { use My\Attributes\SingleArgument; - @@SingleArgument("Hello World") + @[SingleArgument("Hello World")] class Foo { } diff --git a/Zend/tests/attributes/003_ast_nodes.phpt b/Zend/tests/attributes/003_ast_nodes.phpt index 21125bde13a0..a28339beb729 100644 --- a/Zend/tests/attributes/003_ast_nodes.phpt +++ b/Zend/tests/attributes/003_ast_nodes.phpt @@ -5,7 +5,7 @@ Attributes can deal with AST nodes. define('V1', strtoupper(php_sapi_name())); -@@A1([V1 => V1]) +@[A1([V1 => V1])] class C1 { public const BAR = 'bar'; @@ -20,7 +20,7 @@ var_dump(count($args), $args[0][V1] === V1); echo "\n"; -@@A1(V1, 1 + 2, C1::class) +@[A1(V1, 1 + 2, C1::class)] class C2 { } $ref = new \ReflectionClass(C2::class); @@ -35,7 +35,7 @@ var_dump($args[2] === C1::class); echo "\n"; -@@A1(self::FOO, C1::BAR) +@[A1(self::FOO, C1::BAR)] class C3 { private const FOO = 'foo'; @@ -52,20 +52,20 @@ var_dump($args[1] === C1::BAR); echo "\n"; -@@ExampleWithShift(4 >> 1) +@[ExampleWithShift(4 >> 1)] class C4 {} $ref = new \ReflectionClass(C4::class); var_dump($ref->getAttributes()[0]->getArguments()); echo "\n"; -@@Attribute +@[Attribute] class C5 { public function __construct() { } } -$ref = new \ReflectionFunction(@@C5(MissingClass::SOME_CONST) function () { }); +$ref = new \ReflectionFunction(@[C5(MissingClass::SOME_CONST)] function () { }); $attr = $ref->getAttributes(); var_dump(count($attr)); diff --git a/Zend/tests/attributes/004_name_resolution.phpt b/Zend/tests/attributes/004_name_resolution.phpt index 3c0e1190ffec..c3e4a2134ad1 100644 --- a/Zend/tests/attributes/004_name_resolution.phpt +++ b/Zend/tests/attributes/004_name_resolution.phpt @@ -25,11 +25,11 @@ namespace Foo { use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Attributes; - @@Entity("imported class") - @@ORM\Entity("imported namespace") - @@\Doctrine\ORM\Mapping\Entity("absolute from namespace") - @@\Entity("import absolute from global") - @@Attributes\Table() + @[Entity("imported class")] + @[ORM\Entity("imported namespace")] + @[\Doctrine\ORM\Mapping\Entity("absolute from namespace")] + @[\Entity("import absolute from global")] + @[Attributes\Table()] function foo() { } } diff --git a/Zend/tests/attributes/005_objects.phpt b/Zend/tests/attributes/005_objects.phpt index 83f523182b1b..5ea067dfa1f3 100644 --- a/Zend/tests/attributes/005_objects.phpt +++ b/Zend/tests/attributes/005_objects.phpt @@ -3,7 +3,7 @@ Attributes can be converted into objects. --FILE-- getAttributes() as $attr) { $obj = $attr->newInstance(); @@ -26,7 +26,7 @@ foreach ($ref->getAttributes() as $attr) { echo "\n"; -$ref = new \ReflectionFunction(@@A1 function () { }); +$ref = new \ReflectionFunction(@[A1] function () { }); try { $ref->getAttributes()[0]->newInstance(); @@ -36,7 +36,7 @@ try { echo "\n"; -$ref = new \ReflectionFunction(@@A1([]) function () { }); +$ref = new \ReflectionFunction(@[A1([])] function () { }); try { $ref->getAttributes()[0]->newInstance(); @@ -46,7 +46,7 @@ try { echo "\n"; -$ref = new \ReflectionFunction(@@A2 function () { }); +$ref = new \ReflectionFunction(@[A2] function () { }); try { $ref->getAttributes()[0]->newInstance(); @@ -56,13 +56,13 @@ try { echo "\n"; -@@Attribute +@[Attribute] class A3 { private function __construct() { } } -$ref = new \ReflectionFunction(@@A3 function () { }); +$ref = new \ReflectionFunction(@[A3] function () { }); try { $ref->getAttributes()[0]->newInstance(); @@ -72,10 +72,10 @@ try { echo "\n"; -@@Attribute +@[Attribute] class A4 { } -$ref = new \ReflectionFunction(@@A4(1) function () { }); +$ref = new \ReflectionFunction(@[A4(1)] function () { }); try { $ref->getAttributes()[0]->newInstance(); @@ -87,7 +87,7 @@ echo "\n"; class A5 { } -$ref = new \ReflectionFunction(@@A5 function () { }); +$ref = new \ReflectionFunction(@[A5] function () { }); try { $ref->getAttributes()[0]->newInstance(); diff --git a/Zend/tests/attributes/006_filter.phpt b/Zend/tests/attributes/006_filter.phpt index 69ee146b49f0..e541d64732c2 100644 --- a/Zend/tests/attributes/006_filter.phpt +++ b/Zend/tests/attributes/006_filter.phpt @@ -3,17 +3,17 @@ Attributes can be filtered by name and base type. --FILE-- getAttributes(A3::class); var_dump(count($attr)); -$ref = new \ReflectionFunction(@@A1 @@A2 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] function () { }); $attr = $ref->getAttributes(A2::class); var_dump(count($attr), $attr[0]->getName()); -$ref = new \ReflectionFunction(@@A1 @@A2 @@A2 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] @[A2] function () { }); $attr = $ref->getAttributes(A2::class); var_dump(count($attr), $attr[0]->getName(), $attr[1]->getName()); @@ -25,27 +25,27 @@ class A1 implements Base { } class A2 implements Base { } class A3 extends A2 { } -$ref = new \ReflectionFunction(@@A1 @@A2 @@A5 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] @[A5] function () { }); $attr = $ref->getAttributes(\stdClass::class, \ReflectionAttribute::IS_INSTANCEOF); var_dump(count($attr)); print_r(array_map(fn ($a) => $a->getName(), $attr)); -$ref = new \ReflectionFunction(@@A1 @@A2 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] function () { }); $attr = $ref->getAttributes(A1::class, \ReflectionAttribute::IS_INSTANCEOF); var_dump(count($attr)); print_r(array_map(fn ($a) => $a->getName(), $attr)); -$ref = new \ReflectionFunction(@@A1 @@A2 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] function () { }); $attr = $ref->getAttributes(Base::class, \ReflectionAttribute::IS_INSTANCEOF); var_dump(count($attr)); print_r(array_map(fn ($a) => $a->getName(), $attr)); -$ref = new \ReflectionFunction(@@A1 @@A2 @@A3 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] @[A3] function () { }); $attr = $ref->getAttributes(A2::class, \ReflectionAttribute::IS_INSTANCEOF); var_dump(count($attr)); print_r(array_map(fn ($a) => $a->getName(), $attr)); -$ref = new \ReflectionFunction(@@A1 @@A2 @@A3 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A2] @[A3] function () { }); $attr = $ref->getAttributes(Base::class, \ReflectionAttribute::IS_INSTANCEOF); var_dump(count($attr)); print_r(array_map(fn ($a) => $a->getName(), $attr)); diff --git a/Zend/tests/attributes/008_wrong_attribution.phpt b/Zend/tests/attributes/008_wrong_attribution.phpt index 21ea9783d1c2..7fdf0901caf0 100644 --- a/Zend/tests/attributes/008_wrong_attribution.phpt +++ b/Zend/tests/attributes/008_wrong_attribution.phpt @@ -3,7 +3,7 @@ Attributes: Prevent Attribute on non classes --FILE-- "The email '{{ value }}' is not a valid email.")) + @[ORM\Column("string", ORM\Column::UNIQUE)] + @[Assert\Email(array("message" => "The email '{{ value }}' is not a valid email."))] private $email; /** @@ -52,8 +52,8 @@ class User * maxMessage = "You cannot be taller than {{ limit }}cm to enter" * ) */ - @@Assert\Range(["min" => 120, "max" => 180, "minMessage" => "You must be at least {{ limit }}cm tall to enter"]) - @@ORM\Column(ORM\Column::T_INTEGER) + @[Assert\Range(["min" => 120, "max" => 180, "minMessage" => "You must be at least {{ limit }}cm tall to enter"])] + @[ORM\Column(ORM\Column::T_INTEGER)] protected $height; /** @@ -63,10 +63,10 @@ class User * inverseJoinColumns={@ORM\JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)} * ) */ - @@ORM\ManyToMany(Phonenumber::class) - @@ORM\JoinTable("users_phonenumbers") - @@ORM\JoinColumn("user_id", "id") - @@ORM\InverseJoinColumn("phonenumber_id", "id", ORM\JoinColumn::UNIQUE) + @[ORM\ManyToMany(Phonenumber::class)] + @[ORM\JoinTable("users_phonenumbers")] + @[ORM\JoinColumn("user_id", "id")] + @[ORM\InverseJoinColumn("phonenumber_id", "id", ORM\JoinColumn::UNIQUE)] private $phonenumbers; } diff --git a/Zend/tests/attributes/010_unsupported_const_expression.phpt b/Zend/tests/attributes/010_unsupported_const_expression.phpt index fb30e2c486bd..5406372fe828 100644 --- a/Zend/tests/attributes/010_unsupported_const_expression.phpt +++ b/Zend/tests/attributes/010_unsupported_const_expression.phpt @@ -3,7 +3,7 @@ Attribute arguments support only const expressions. --FILE-- diff --git a/Zend/tests/attributes/011_inheritance.phpt b/Zend/tests/attributes/011_inheritance.phpt index 25c943dea30e..8a6dad2e94fd 100644 --- a/Zend/tests/attributes/011_inheritance.phpt +++ b/Zend/tests/attributes/011_inheritance.phpt @@ -3,10 +3,10 @@ Attributes comply with inheritance rules. --FILE-- 1)); +assert(0 && ($a = @[A1(1, 2, 1 + 2)] fn () => 1)); -assert(0 && ($a = new @@A1 class() { - @@A1@@A2 const FOO = 'foo'; - @@A2 public $x; - @@A3 function a() { } +assert(0 && ($a = new @[A1] class() { + @[A1]@[A2] const FOO = 'foo'; + @[A2] public $x; + @[A3] function a() { } })); assert(0 && ($a = function () { - @@A1 class Test1 { } - @@A2 interface Test2 { } - @@A3 trait Test3 { } + @[A1] class Test1 { } + @[A2] interface Test2 { } + @[A3] trait Test3 { } })); ?> --EXPECTF-- -Warning: assert(): assert(0 && ($a = @@A1 @@A2 function ($a, @@A3(1) $b) { +Warning: assert(): assert(0 && ($a = @[A1] @[A2] function ($a, @[A3(1)] $b) { })) failed in %s on line %d -Warning: assert(): assert(0 && ($a = @@A1(1, 2, 1 + 2) fn() => 1)) failed in %s on line %d +Warning: assert(): assert(0 && ($a = @[A1(1, 2, 1 + 2)] fn() => 1)) failed in %s on line %d -Warning: assert(): assert(0 && ($a = new @@A1 class { - @@A1 - @@A2 +Warning: assert(): assert(0 && ($a = new @[A1] class { + @[A1] + @[A2] public const FOO = 'foo'; - @@A2 + @[A2] public $x; - @@A3 + @[A3] public function a() { } })) failed in %s on line %d Warning: assert(): assert(0 && ($a = function () { - @@A1 + @[A1] class Test1 { } - @@A2 + @[A2] interface Test2 { } - @@A3 + @[A3] trait Test3 { } diff --git a/Zend/tests/attributes/013_class_scope.phpt b/Zend/tests/attributes/013_class_scope.phpt index be6c7a60da4f..82976440837e 100644 --- a/Zend/tests/attributes/013_class_scope.phpt +++ b/Zend/tests/attributes/013_class_scope.phpt @@ -3,17 +3,17 @@ Attributes make use of class scope. --FILE-- b::c) +@[Attr(a->b::c)] function test() {} ?> diff --git a/Zend/tests/attributes/019_variable_attribute_name.phpt b/Zend/tests/attributes/019_variable_attribute_name.phpt index 9b8a3c22116d..571ef4660550 100644 --- a/Zend/tests/attributes/019_variable_attribute_name.phpt +++ b/Zend/tests/attributes/019_variable_attribute_name.phpt @@ -3,7 +3,7 @@ Attribute name cannot be a variable --FILE-- diff --git a/Zend/tests/attributes/020_userland_attribute_validation.phpt b/Zend/tests/attributes/020_userland_attribute_validation.phpt index 1025b5008e20..a2907d03b485 100644 --- a/Zend/tests/attributes/020_userland_attribute_validation.phpt +++ b/Zend/tests/attributes/020_userland_attribute_validation.phpt @@ -3,17 +3,17 @@ Attributes expose and verify target and repeatable data. --FILE-- getAttributes()[0]; var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_FUNCTION, $attr->isRepeated()); var_dump(get_class($attr->newInstance())); echo "\n"; -$ref = new \ReflectionObject(new @@A1 class() { }); +$ref = new \ReflectionObject(new @[A1] class() { }); $attr = $ref->getAttributes()[0]; var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_CLASS, $attr->isRepeated()); @@ -25,7 +25,7 @@ try { echo "\n"; -$ref = new \ReflectionFunction(@@A1 @@A1 function () { }); +$ref = new \ReflectionFunction(@[A1] @[A1] function () { }); $attr = $ref->getAttributes()[0]; var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_FUNCTION, $attr->isRepeated()); @@ -37,10 +37,10 @@ try { echo "\n"; -@@Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE) +@[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class A2 { } -$ref = new \ReflectionObject(new @@A2 @@A2 class() { }); +$ref = new \ReflectionObject(new @[A2] @[A2] class() { }); $attr = $ref->getAttributes()[0]; var_dump($attr->getName(), $attr->getTarget() == Attribute::TARGET_CLASS, $attr->isRepeated()); var_dump(get_class($attr->newInstance())); diff --git a/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt b/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt index 0f0b915ebe76..67733e8a7a93 100644 --- a/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt +++ b/Zend/tests/attributes/021_attribute_flags_type_is_validated.phpt @@ -3,7 +3,7 @@ Attribute flags type is validated. --FILE-- diff --git a/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt b/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt index 28ad550385d4..938796a374ee 100644 --- a/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt +++ b/Zend/tests/attributes/022_attribute_flags_value_is_validated.phpt @@ -3,7 +3,7 @@ Attribute flags value is validated. --FILE-- diff --git a/Zend/tests/attributes/023_ast_node_in_validation.phpt b/Zend/tests/attributes/023_ast_node_in_validation.phpt index ce44527f62fd..1337d08cca2b 100644 --- a/Zend/tests/attributes/023_ast_node_in_validation.phpt +++ b/Zend/tests/attributes/023_ast_node_in_validation.phpt @@ -3,7 +3,7 @@ Attribute flags value is validated. --FILE-- diff --git a/Zend/tests/attributes/024_internal_target_validation.phpt b/Zend/tests/attributes/024_internal_target_validation.phpt index 49a5ae68c8b1..aa9b09755f94 100644 --- a/Zend/tests/attributes/024_internal_target_validation.phpt +++ b/Zend/tests/attributes/024_internal_target_validation.phpt @@ -3,7 +3,7 @@ Internal attribute targets are validated. --FILE-- diff --git a/Zend/tests/attributes/025_internal_repeatable_validation.phpt b/Zend/tests/attributes/025_internal_repeatable_validation.phpt index b3c83e810f2a..52fea27d6c37 100644 --- a/Zend/tests/attributes/025_internal_repeatable_validation.phpt +++ b/Zend/tests/attributes/025_internal_repeatable_validation.phpt @@ -3,8 +3,8 @@ Internal attribute targets are validated. --FILE-- diff --git a/Zend/tests/attributes/026_unpack_in_args.phpt b/Zend/tests/attributes/026_unpack_in_args.phpt index 37f8fb5679ab..9222bc51242c 100644 --- a/Zend/tests/attributes/026_unpack_in_args.phpt +++ b/Zend/tests/attributes/026_unpack_in_args.phpt @@ -3,7 +3,7 @@ Cannot use unpacking in attribute argument list --FILE-- diff --git a/Zend/tests/attributes/027_trailing_comma_args.phpt b/Zend/tests/attributes/027_trailing_comma_args.phpt index 5ac47e08a858..c3a111d112eb 100644 --- a/Zend/tests/attributes/027_trailing_comma_args.phpt +++ b/Zend/tests/attributes/027_trailing_comma_args.phpt @@ -3,12 +3,12 @@ Trailing comma in attribute argument list --FILE-- getAttributes()[0]; diff --git a/Zend/tests/named_params/attributes_duplicate_named_param.phpt b/Zend/tests/named_params/attributes_duplicate_named_param.phpt index bcd9f9b71792..1ff6ac0c5d27 100644 --- a/Zend/tests/named_params/attributes_duplicate_named_param.phpt +++ b/Zend/tests/named_params/attributes_duplicate_named_param.phpt @@ -3,7 +3,7 @@ Named params in attributes: Duplicate named parameter error --FILE-- diff --git a/Zend/tests/named_params/attributes_named_flags.phpt b/Zend/tests/named_params/attributes_named_flags.phpt index f553aa530890..82aaa7fc8c26 100644 --- a/Zend/tests/named_params/attributes_named_flags.phpt +++ b/Zend/tests/named_params/attributes_named_flags.phpt @@ -3,11 +3,11 @@ Named flags parameter for Attribute attribute --FILE-- getAttributes()[0]->newInstance(); diff --git a/Zend/tests/named_params/attributes_named_flags_incorrect.phpt b/Zend/tests/named_params/attributes_named_flags_incorrect.phpt index 6f5b226157b1..e267d4bb187a 100644 --- a/Zend/tests/named_params/attributes_named_flags_incorrect.phpt +++ b/Zend/tests/named_params/attributes_named_flags_incorrect.phpt @@ -4,11 +4,11 @@ Named flags parameter for Attribute attribute (incorrect parameter name) getAttributes()[0]->newInstance(); diff --git a/Zend/tests/named_params/attributes_positional_after_named.phpt b/Zend/tests/named_params/attributes_positional_after_named.phpt index 61cee4dc1f2c..3ef0b7bb4705 100644 --- a/Zend/tests/named_params/attributes_positional_after_named.phpt +++ b/Zend/tests/named_params/attributes_positional_after_named.phpt @@ -3,10 +3,10 @@ Named params in attributes: Positional after named error --FILE-- diff --git a/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt b/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt index 6162cbc993ff..f41840cbb364 100644 --- a/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt +++ b/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt @@ -7,4 +7,4 @@ global $$foo->bar; ?> --EXPECTF-- -Parse error: syntax error, unexpected token "->", expecting ";" or "," in %s on line %d +Parse error: syntax error, unexpected token "->", expecting "," or ";" in %s on line %d diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index e2a2aca698d4..4d27e67a530e 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1356,7 +1356,7 @@ static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, for (i = 0; i < list->children; i++) { zend_ast *attr = list->child[i]; - smart_str_appends(str, "@@"); + smart_str_appends(str, "@["); zend_ast_export_ns_name(str, attr->child[0], 0, indent); if (attr->child[1]) { @@ -1373,6 +1373,8 @@ static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, smart_str_appendc(str, ')'); } + smart_str_appendc(str, ']'); + if (newlines) { smart_str_appendc(str, '\n'); zend_ast_export_indent(str, indent); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1a566e352d2d..dc697244d5cc 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -178,7 +178,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %token T_NS_C "'__NAMESPACE__'" %token END 0 "end of file" -%token T_ATTRIBUTE "'@@'" +%token T_ATTRIBUTE "'@['" %token T_PLUS_EQUAL "'+='" %token T_MINUS_EQUAL "'-='" %token T_MUL_EQUAL "'*='" @@ -346,7 +346,7 @@ attribute_decl: ; attribute: - T_ATTRIBUTE attribute_decl { $$ = $2; } + T_ATTRIBUTE attribute_decl ']' { $$ = $2; } ; attributes: diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index ca5804f4bffd..6a4c8edd498c 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1423,7 +1423,8 @@ NEWLINE ("\r"|"\n"|"\r\n") RETURN_TOKEN_WITH_IDENT(T_RETURN); } -"@@" { +"@[" { + enter_nesting('['); RETURN_TOKEN(T_ATTRIBUTE); } diff --git a/ext/tokenizer/tests/attributes.phpt b/ext/tokenizer/tests/attributes.phpt index 8795a4c5dcdd..3ee092e02017 100644 --- a/ext/tokenizer/tests/attributes.phpt +++ b/ext/tokenizer/tests/attributes.phpt @@ -3,7 +3,7 @@ Attributes are exposed as tokens. --FILE-- Date: Fri, 7 Aug 2020 09:18:26 +0200 Subject: [PATCH 2/2] Implemented grouped attribute syntax RFC. --- Zend/zend_ast.c | 20 ++++++++--- Zend/zend_ast.h | 1 + Zend/zend_compile.c | 70 ++++++++++++++++++++----------------- Zend/zend_language_parser.y | 11 ++++-- 4 files changed, 63 insertions(+), 39 deletions(-) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 4d27e67a530e..d3fb7cea2600 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -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++) { @@ -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'); diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 97236c5560c0..ea01beb1f7fe 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -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 */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5e61760e9029..6d398218b7e9 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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); + } } } } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index dc697244d5cc..4caa50a788c0 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -266,7 +266,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type identifier type_expr_without_static union_type_without_static %type inline_function union_type %type attributed_statement attributed_class_statement attributed_parameter -%type attribute_decl attribute attributes namespace_declaration_name +%type attribute_decl attribute attributes attribute_group namespace_declaration_name %type match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list %type returns_ref function fn is_reference is_variadic variable_modifiers @@ -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: