summaryrefslogtreecommitdiff
path: root/Zend/zend_attributes.c
diff options
context:
space:
mode:
authorMartin Schröder <m.schroeder2007@gmail.com>2020-06-28 19:16:33 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-06-29 10:45:51 +0200
commit053ef28b8d0c1e2af2cc5151cfe2bd4369ddde34 (patch)
tree54cebb4dfb10fae058a89f086f914ba93e16d254 /Zend/zend_attributes.c
parent46e38a192751be02ff95d56fb0c6c18ec4d7d6df (diff)
downloadphp-git-053ef28b8d0c1e2af2cc5151cfe2bd4369ddde34.tar.gz
Implement Attribute Amendments.
RFC: https://wiki.php.net/rfc/attribute_amendments Support for attribute grouping is left out, because the short attribute syntax RFC will likely make it obsolete. Closes GH-5751.
Diffstat (limited to 'Zend/zend_attributes.c')
-rw-r--r--Zend/zend_attributes.c178
1 files changed, 159 insertions, 19 deletions
diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c
index 935f37e5b9..c58ff95fb6 100644
--- a/Zend/zend_attributes.c
+++ b/Zend/zend_attributes.c
@@ -1,21 +1,66 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.00 of the Zend license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.zend.com/license/2_00.txt. |
+ | If you did not receive a copy of the Zend license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@zend.com so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Benjamin Eberlei <kontakt@beberlei.de> |
+ | Martin Schröder <m.schroeder2007@gmail.com> |
+ +----------------------------------------------------------------------+
+*/
+
#include "zend.h"
#include "zend_API.h"
#include "zend_attributes.h"
+#include "zend_attributes_arginfo.h"
+#include "zend_smart_str.h"
-ZEND_API zend_class_entry *zend_ce_php_attribute;
+ZEND_API zend_class_entry *zend_ce_attribute;
-static HashTable internal_validators;
+static HashTable internal_attributes;
-void zend_attribute_validate_phpattribute(zend_attribute *attr, int target)
+void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
{
- if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
- zend_error(E_COMPILE_ERROR, "Only classes can be marked with <<PhpAttribute>>");
+ if (attr->argc > 0) {
+ zval flags;
+
+ if (FAILURE == zend_get_attribute_value(&flags, attr, 0, scope)) {
+ return;
+ }
+
+ if (Z_TYPE(flags) != IS_LONG) {
+ zend_error_noreturn(E_ERROR,
+ "Attribute::__construct(): Argument #1 ($flags) must must be of type int, %s given",
+ zend_zval_type_name(&flags)
+ );
+ }
+
+ if (Z_LVAL(flags) & ~ZEND_ATTRIBUTE_FLAGS) {
+ zend_error_noreturn(E_ERROR, "Invalid attribute flags specified");
+ }
+
+ zval_ptr_dtor(&flags);
}
}
-ZEND_API zend_attributes_internal_validator zend_attribute_get_validator(zend_string *lcname)
+ZEND_METHOD(Attribute, __construct)
{
- return zend_hash_find_ptr(&internal_validators, lcname);
+ zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
+
+ ZEND_PARSE_PARAMETERS_START(0, 1)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(flags)
+ ZEND_PARSE_PARAMETERS_END();
+
+ ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), flags);
}
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
@@ -70,6 +115,65 @@ ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes,
return get_attribute_str(attributes, str, len, offset + 1);
}
+ZEND_API int zend_get_attribute_value(zval *ret, zend_attribute *attr, uint32_t i, zend_class_entry *scope)
+{
+ if (i >= attr->argc) {
+ return FAILURE;
+ }
+
+ ZVAL_COPY_OR_DUP(ret, &attr->argv[i]);
+
+ if (Z_TYPE_P(ret) == IS_CONSTANT_AST) {
+ if (SUCCESS != zval_update_constant_ex(ret, scope)) {
+ zval_ptr_dtor(ret);
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static const char *target_names[] = {
+ "class",
+ "function",
+ "method",
+ "property",
+ "class constant",
+ "parameter"
+};
+
+ZEND_API zend_string *zend_get_attribute_target_names(uint32_t flags)
+{
+ smart_str str = { 0 };
+
+ for (uint32_t i = 0; i < (sizeof(target_names) / sizeof(char *)); i++) {
+ if (flags & (1 << i)) {
+ if (smart_str_get_len(&str)) {
+ smart_str_appends(&str, ", ");
+ }
+
+ smart_str_appends(&str, target_names[i]);
+ }
+ }
+
+ return smart_str_extract(&str);
+}
+
+ZEND_API zend_bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr)
+{
+ zend_attribute *other;
+
+ ZEND_HASH_FOREACH_PTR(attributes, other) {
+ if (other != attr && other->offset == attr->offset) {
+ if (zend_string_equals(other->lcname, attr->lcname)) {
+ return 1;
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ return 0;
+}
+
static zend_always_inline void free_attribute(zend_attribute *attr, int persistent)
{
uint32_t i;
@@ -123,34 +227,70 @@ ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_bool pe
return attr;
}
-ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator)
+static void free_internal_attribute(zval *v)
{
+ pefree(Z_PTR_P(v), 1);
+}
+
+ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
+{
+ zend_internal_attribute *attr;
+
if (ce->type != ZEND_INTERNAL_CLASS) {
zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
}
+ attr = pemalloc(sizeof(zend_internal_attribute), 1);
+ attr->ce = ce;
+ attr->flags = flags;
+ attr->validator = NULL;
+
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
- zend_hash_update_ptr(&internal_validators, lcname, validator);
+ zend_hash_update_ptr(&internal_attributes, lcname, attr);
+ zend_add_class_attribute(ce, zend_ce_attribute->name, 0);
zend_string_release(lcname);
- zend_add_class_attribute(ce, zend_ce_php_attribute->name, 0);
+ return attr;
}
-void zend_register_attribute_ce(void)
+ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname)
{
- zend_hash_init(&internal_validators, 8, NULL, NULL, 1);
+ return zend_hash_find_ptr(&internal_attributes, lcname);
+}
+void zend_register_attribute_ce(void)
+{
+ zend_internal_attribute *attr;
zend_class_entry ce;
-
- INIT_CLASS_ENTRY(ce, "PhpAttribute", NULL);
- zend_ce_php_attribute = zend_register_internal_class(&ce);
- zend_ce_php_attribute->ce_flags |= ZEND_ACC_FINAL;
-
- zend_compiler_attribute_register(zend_ce_php_attribute, zend_attribute_validate_phpattribute);
+ zend_string *str;
+ zval tmp;
+
+ zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1);
+
+ INIT_CLASS_ENTRY(ce, "Attribute", class_Attribute_methods);
+ zend_ce_attribute = zend_register_internal_class(&ce);
+ zend_ce_attribute->ce_flags |= ZEND_ACC_FINAL;
+
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS"), ZEND_ATTRIBUTE_TARGET_CLASS);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_FUNCTION"), ZEND_ATTRIBUTE_TARGET_FUNCTION);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_METHOD"), ZEND_ATTRIBUTE_TARGET_METHOD);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PROPERTY"), ZEND_ATTRIBUTE_TARGET_PROPERTY);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS_CONSTANT"), ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PARAMETER"), ZEND_ATTRIBUTE_TARGET_PARAMETER);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_ALL"), ZEND_ATTRIBUTE_TARGET_ALL);
+ zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("IS_REPEATABLE"), ZEND_ATTRIBUTE_IS_REPEATABLE);
+
+ ZVAL_UNDEF(&tmp);
+ str = zend_string_init(ZEND_STRL("flags"), 1);
+ zend_declare_typed_property(zend_ce_attribute, str, &tmp, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, 0, 0));
+ zend_string_release(str);
+
+ attr = zend_internal_attribute_register(zend_ce_attribute, ZEND_ATTRIBUTE_TARGET_CLASS);
+ attr->validator = validate_attribute;
}
void zend_attributes_shutdown(void)
{
- zend_hash_destroy(&internal_validators);
+ zend_hash_destroy(&internal_attributes);
}