diff options
Diffstat (limited to 'Zend/zend_attributes.c')
-rw-r--r-- | Zend/zend_attributes.c | 178 |
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); } |