From e062dffe6c81751133121519a9ae3cbe854a509a Mon Sep 17 00:00:00 2001 From: Zeev Suraski Date: Fri, 6 Dec 2002 17:09:44 +0000 Subject: [PATCH] - Implement public/protected/private methods. - Prevent instantiation of classes with abstract methods. Based in part on Marcus's patch. --- Zend/zend.c | 1 + Zend/zend.h | 3 + Zend/zend_API.c | 1 + Zend/zend_compile.c | 130 ++++++++++++++++++++++++++++------- Zend/zend_compile.h | 22 ++++-- Zend/zend_execute.c | 100 ++++++++++++++++++++++++--- Zend/zend_globals.h | 2 + Zend/zend_hash.h | 1 + Zend/zend_language_parser.y | 66 ++++++++++-------- Zend/zend_language_scanner.l | 6 +- 10 files changed, 268 insertions(+), 64 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index b60f8033ac..b4b6d0ef06 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -354,6 +354,7 @@ static void register_standard_class(void) zend_standard_class_def->handle_property_set = NULL; zend_standard_class_def->refcount = 1; zend_standard_class_def->constants_updated = 0; + zend_standard_class_def->ce_flags = 0; zend_hash_add(GLOBAL_CLASS_TABLE, "stdclass", sizeof("stdclass"), &zend_standard_class_def, sizeof(zend_class_entry *), NULL); } diff --git a/Zend/zend.h b/Zend/zend.h index bcb93d85da..123a241d5b 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -295,6 +295,8 @@ typedef struct _zend_overloaded_element { /* A lot of stuff needs shifiting around in order to include zend_compile.h here */ union _zend_function; +#define ZEND_CE_ABSTRACT ZEND_ACC_ABSTRACT /* same as ZEND_ACC_ABSTRACT */ + struct _zend_class_entry { char type; char *name; @@ -302,6 +304,7 @@ struct _zend_class_entry { struct _zend_class_entry *parent; int refcount; zend_bool constants_updated; + zend_uint ce_flags; HashTable function_table; HashTable default_properties; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 4763670886..78393d4b71 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1236,6 +1236,7 @@ ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_c class_entry->parent = NULL; class_entry->refcount = 1; class_entry->constants_updated = 0; + class_entry->ce_flags = 0; zend_hash_init(&class_entry->default_properties, 0, NULL, ZVAL_PTR_DTOR, 1); zend_hash_init(&class_entry->private_properties, 0, NULL, ZVAL_PTR_DTOR, 1); zend_hash_init(&class_entry->protected_properties, 0, NULL, ZVAL_PTR_DTOR, 1); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index d50c424f33..071502ddac 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -909,6 +909,16 @@ void zend_do_free(znode *op1 TSRMLS_DC) } } + +int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier) +{ + if (current_access_type->u.constant.value.lval & ZEND_FN_PPP_MASK) { + zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed"); + } + return (current_access_type->u.constant.value.lval | new_modifier->u.constant.value.lval); +} + + void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC) { zend_op_array op_array; @@ -950,6 +960,9 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n zend_error(E_COMPILE_ERROR, "Cannot redeclare %s()", name); } } + if (fn_flags & ZEND_ACC_ABSTRACT) { + CG(active_class_entry)->ce_flags |= ZEND_ACC_ABSTRACT; + } if ((short_class_name_length == name_len) && (!memcmp(short_class_name, name, name_len))) { CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array); @@ -1502,7 +1515,6 @@ ZEND_API void function_add_ref(zend_function *function) } } - static void do_inherit_parent_constructor(zend_class_entry *ce) { zend_function *function; @@ -1529,27 +1541,75 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) ce->__call = ce->parent->__call; } -static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent) { + +char *zend_visibility_string(zend_uint fn_flags) +{ + if (fn_flags & ZEND_ACC_PRIVATE) { + return "private"; + } + if (fn_flags & ZEND_ACC_PROTECTED) { + return "protected"; + } + if (fn_flags & ZEND_ACC_PUBLIC) { + return "public"; + } + return ""; +} + + +static void do_inherit_method(zend_function *function) +{ + /* The class entry of the derived function intentionally remains the same + * as that of the parent class. That allows us to know in which context + * we're running, and handle private method calls properly. + */ + if (function->common.fn_flags & ZEND_ACC_ABSTRACT) { + function->op_array.scope->ce_flags |= ZEND_ACC_ABSTRACT; + } + function_add_ref(function); +} + + +static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent) +{ zend_uint child_flags = child->common.fn_flags; zend_uint parent_flags = parent->common.fn_flags; + /* we do not inherit private methods */ +/* assert(!(parent_flags & ZEND_ACC_PRIVATE)); */ + /* You cannot change from static to non static and vice versa. */ - if ((child_flags & FN_STATIC) != (parent_flags & FN_STATIC)) { - if (child->common.fn_flags & FN_STATIC) { - zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child)); + if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) { + if (child->common.fn_flags & ZEND_ACC_STATIC) { + zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); } else { - zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child)); + zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); } } - /* Disallow makeing an inherited method abstract. + /* Disallow making an inherited method abstract. + * Also check the visibility and copy it if needed. This must be done last + * since we may change the child flags here. + * Again first detect more than one error to make normal operation faster. */ - if (child_flags & FN_ABSTRACT) { - zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s() abstract in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child)); + if ((child_flags & (ZEND_FN_PPP_MASK|ZEND_ACC_ABSTRACT)) != (parent_flags & ZEND_FN_PPP_MASK)) { + if (child_flags & ZEND_ACC_ABSTRACT) { + zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); + } + if (!(child_flags & ZEND_FN_PPP_MASK) || (((child_flags|parent_flags) & ZEND_FN_PPP_MASK) == ZEND_ACC_PUBLIC)) { + /* this is no error since we copy visibility here */ + /* child->common.fn_flags &= ~ZEND_FN_PPP_MASK; do not clear added public */ + child->common.fn_flags |= parent_flags & ZEND_FN_PPP_MASK; + } else { + zend_error(E_COMPILE_ERROR, "Cannot redeclare %s %s::%s() as %s %s::%s()", + zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), parent->common.function_name, + zend_visibility_string(child_flags), ZEND_FN_SCOPE_NAME(child), child->common.function_name); + } } return SUCCESS; } + void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) { zval *tmp; @@ -1560,14 +1620,17 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) /* STATIC_MEMBERS_FIXME */ /* zend_hash_merge(ce->static_members, parent_ce->static_members, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); */ zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); - zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (void (*)(void *)) function_add_ref, sizeof(zend_function), (zend_bool (*)(void *, void *))do_inherit_method_check); + zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (zend_bool (*)(void *, void *)) do_inherit_method_check); ce->parent = parent_ce; - if (!ce->handle_property_get) - ce->handle_property_get = parent_ce->handle_property_get; - if (!ce->handle_property_set) + if (!ce->handle_property_get) { + ce->handle_property_get = parent_ce->handle_property_get; + } + if (!ce->handle_property_set) { ce->handle_property_set = parent_ce->handle_property_set; - if (!ce->handle_function_call) + } + if (!ce->handle_function_call) { ce->handle_function_call = parent_ce->handle_function_call; + } do_inherit_parent_constructor(ce); } @@ -1582,6 +1645,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze new_class_entry->name_length = name_length; new_class_entry->refcount = 1; new_class_entry->constants_updated = 0; + new_class_entry->ce_flags = 0; zend_str_tolower(new_class_entry->name, new_class_entry->name_length); @@ -2055,6 +2119,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod } new_class_entry->refcount = 1; new_class_entry->constants_updated = 0; + new_class_entry->ce_flags = 0; zend_str_tolower(new_class_entry->name, new_class_entry->name_length); @@ -2134,7 +2199,8 @@ void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_le *dest_length = prop_name_length; } -void zend_do_declare_property(znode *var_name, znode *value, int declaration_type TSRMLS_DC) + +void zend_do_declare_property(znode *var_name, znode *value TSRMLS_DC) { zval *property; @@ -2147,8 +2213,8 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ property->type = IS_NULL; } - switch (declaration_type) { - case T_PRIVATE: + switch (CG(access_type)) { + case ZEND_ACC_PRIVATE: { char *priv_name; int priv_name_length; @@ -2162,7 +2228,7 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ zend_hash_update(&CG(active_class_entry)->private_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); break; } - case T_PROTECTED: + case ZEND_ACC_PROTECTED: { char *prot_name; int prot_name_length; @@ -2188,19 +2254,37 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ efree(prot_name); break; } - case T_VAR: + case ZEND_ACC_PUBLIC: zend_hash_update(&CG(active_class_entry)->default_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); break; - case T_STATIC: + case ZEND_ACC_STATIC: zend_hash_update(CG(active_class_entry)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); break; - case T_CONST: - zend_hash_update(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); - break; } FREE_PNODE(var_name); } + +void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC) +{ + zval *property; + + ALLOC_ZVAL(property); + + if (value) { + *property = value->u.constant; + } else { + INIT_PZVAL(property); + property->type = IS_NULL; + } + + zend_hash_update(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); + + FREE_PNODE(var_name); +} + + + void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC) { zend_op opline; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index d712f5f965..7291a3a9b5 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -88,9 +88,21 @@ typedef struct _zend_brk_cont_element { } zend_brk_cont_element; -#define FN_STATIC 0x01 +#define ZEND_ACC_STATIC 0x01 +#define ZEND_ACC_ABSTRACT 0x02 -#define FN_ABSTRACT 0x02 +/* No visibility is the same as public visibility. + * For inheritance no visibility means inheriting the visibility. + */ +#define ZEND_ACC_PUBLIC 0x10 +#define ZEND_ACC_PROTECTED 0x20 +#define ZEND_ACC_PRIVATE 0x40 + +/* AND mask for accessing only public/protected/private of fn_flags + */ +#define ZEND_FN_PPP_MASK 0xF0 + +char *zend_visibility_string(zend_uint fn_flags); struct _zend_op_array { zend_uchar type; /* MUST be the first element of this struct! */ @@ -138,7 +150,7 @@ typedef struct _zend_internal_function { void (*handler)(INTERNAL_FUNCTION_PARAMETERS); } zend_internal_function; -#define FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? (function)->common.scope->name : "") +#define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? (function)->common.scope->name : "") typedef union _zend_function { zend_uchar type; /* MUST be the first element of this struct! */ @@ -295,6 +307,7 @@ void zend_do_add_char(znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); +int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC); @@ -337,7 +350,8 @@ void zend_do_default_before_statement(znode *case_list, znode *default_token TSR void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znode *parent_class_name TSRMLS_DC); void zend_do_end_class_declaration(znode *class_token TSRMLS_DC); -void zend_do_declare_property(znode *var_name, znode *value, int declaration_type TSRMLS_DC); +void zend_do_declare_property(znode *var_name, znode *value TSRMLS_DC); +void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC); void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 97cdcb05fe..6259477501 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2251,6 +2251,55 @@ int zend_init_ctor_call_handler(ZEND_OPCODE_HANDLER_ARGS) NEXT_OPCODE(); } + +/* Ensures that we're allowed to call a private method. + * Will update EX(fbc) with the correct handler as necessary. + */ +inline int zend_check_private(zend_execute_data *execute_data, zend_class_entry *ce, int fn_flags, char *function_name_strval, int function_name_strlen TSRMLS_DC) +{ + if (!ce) { + return 0; + } + + /* We may call a private function in one of two cases: + * 1. The scope of the function is the same as the class entry of our object + * 2. The class of our object is different, but a private function exists + * in one of the ancestor that corresponds to our object's ce. + */ + if (EX(fbc)->common.scope == ce) { + /* rule #1 checks out ok, allow the function call */ + return 1; + } + + /* Check rule #2 */ + while (ce) { + if (ce == EG(scope)) { + if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==SUCCESS + && EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE + && EX(fbc)->common.scope == EG(scope)) { + return 1; + } + break; + } + ce = ce->parent; + } + return 0; +} + +/* Ensures that we're allowed to call a protected method. + */ +inline int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope, int fn_flags) +{ + while (ce) { + if (ce==scope) { + return 1; + } + ce = ce->parent; + } + return 0; +} + + int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) { zval *function_name; @@ -2268,15 +2317,33 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) EX(object) = get_obj_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R TSRMLS_CC); if (EX(object) && EX(object)->type == IS_OBJECT) { + + /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error(E_ERROR, "Call to undefined function: %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + } + + if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) { + /* No further checks necessary, most common case */ + } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) { + /* Ensure that if we're calling a private function, we're allowed to do so. + */ + if (!zend_check_private(execute_data, EX(object)->value.obj.handlers->get_class_entry(EX(object) TSRMLS_CC), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) { + zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : ""); + } + } else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) { + /* Ensure that if we're calling a protected function, we're allowed to do so. + */ + if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) { + zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : ""); + } } } else { zend_error(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if (EX(fbc)->common.fn_flags & FN_STATIC) { + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { if (!PZVAL_IS_REF(EX(object))) { @@ -2305,7 +2372,6 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) { zval *function_name; - zend_function *function; zval tmp; zend_class_entry *ce; zend_bool is_const; @@ -2335,8 +2401,25 @@ int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) EX(calling_scope) = ce; - if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) { - zend_error(E_ERROR, "Call to undefined function: %s::%s()", ce->name, function_name_strval); + if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==FAILURE) { + zend_error(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); + } + EX(calling_scope) = EX(fbc)->common.scope; + + if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) { + /* No further checks necessary, most common case */ + } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) { + /* Ensure that if we're calling a private function, we're allowed to do so. + */ + if (!zend_check_private(execute_data, EG(scope), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) { + zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : ""); + } + } else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) { + /* Ensure that if we're calling a protected function, we're allowed to do so. + */ + if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) { + zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : ""); + } } if (!is_const) { @@ -2344,9 +2427,7 @@ int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2)); } - EX(fbc) = function; - - if (function->common.fn_flags & FN_STATIC) { + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { if ((EX(object) = EG(This))) { @@ -2916,6 +2997,9 @@ int zend_switch_free_handler(ZEND_OPCODE_HANDLER_ARGS) int zend_new_handler(ZEND_OPCODE_HANDLER_ARGS) { + if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & ZEND_ACC_ABSTRACT) { + zend_error(E_ERROR, "Cannot instanciate abstract class %s", EX_T(EX(opline)->op1.u.var).EA.class_entry->name); + } EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr; ALLOC_ZVAL(EX_T(EX(opline)->result.u.var).var.ptr); object_init_ex(EX_T(EX(opline)->result.u.var).var.ptr, EX_T(EX(opline)->op1.u.var).EA.class_entry); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 8e1fc29a3a..aec96b7b30 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -123,6 +123,8 @@ struct _zend_compiler_globals { zend_bool increment_lineno; zend_llist import_commands; + + int access_type; }; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 6962d06629..2451d4ae50 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -39,6 +39,7 @@ typedef int (*compare_func_t)(const void *, const void * TSRMLS_DC); typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC); typedef void (*dtor_func_t)(void *pDest); typedef void (*copy_ctor_func_t)(void *pElement); +typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam); struct _hashtable; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 45b2b78bc0..926c2190bf 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -110,10 +110,7 @@ %token T_THROW %token T_USE %token T_GLOBAL -%token T_STATIC -%token T_ABSTRACT -%token T_PRIVATE -%token T_PROTECTED +%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC %token T_VAR %token T_UNSET %token T_ISSET @@ -273,6 +270,12 @@ class_declaration_statement: ; +is_reference: + /* empty */ { $$.op_type = ZEND_RETURN_VAL; } + | '&' { $$.op_type = ZEND_RETURN_REF; } +; + + unticked_function_declaration_statement: T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, 0 TSRMLS_CC); } '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); } @@ -437,46 +440,53 @@ class_statement_list: class_statement: - class_variable_declaration ';' + variable_modifier { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';' | class_constant_declaration ';' - | is_static T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '(' + | method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); } + | T_ABSTRACT method_modifiers T_FUNCTION { $3.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$3, &$6, 1, $5.op_type, $2.u.constant.value.lval | ZEND_ACC_ABSTRACT TSRMLS_CC); } '(' + parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$3 TSRMLS_CC); } ';' | T_CLASS T_STRING extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); } - | T_ABSTRACT T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, FN_ABSTRACT TSRMLS_CC); } '(' - parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$2 TSRMLS_CC); } ; -is_static: - T_STATIC { $$.u.constant.value.lval = FN_STATIC; } - | /* empty */ { $$.u.constant.value.lval = 0; } +variable_modifier: + access_modifier { $$ = $1; } + | T_VAR { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; } + | T_STATIC { $$.u.constant.value.lval = ZEND_ACC_STATIC; } ; - -is_reference: - /* empty */ { $$.op_type = ZEND_RETURN_VAL; } - | '&' { $$.op_type = ZEND_RETURN_REF; } + +method_modifiers: + /* empty */ { $$.u.constant.value.lval = 0; } + | non_empty_method_modifiers { $$ = $1; } ; -class_variable_declaration: - class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL, $1.op_type TSRMLS_CC); } - | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5, $1.op_type TSRMLS_CC); } - | class_declaration_type T_VARIABLE { $$ = $1; zend_do_declare_property(&$2, NULL, $1.op_type TSRMLS_CC); } - | class_declaration_type T_VARIABLE '=' static_scalar { $$ = $1; zend_do_declare_property(&$2, &$4, $1.op_type TSRMLS_CC); } +non_empty_method_modifiers: + T_STATIC { $$.u.constant.value.lval = ZEND_ACC_STATIC; } + | access_modifier { $$ = $1; } + | non_empty_method_modifiers T_STATIC { $$.u.constant.value.lval = $1.u.constant.value.lval | ZEND_ACC_STATIC; } + | non_empty_method_modifiers access_modifier { $$.u.constant.value.lval = zend_do_verify_access_types(&$1, &$2); } ; -class_declaration_type: - T_VAR { $$.op_type = T_VAR; } - | T_STATIC { $$.op_type = T_STATIC; } - | T_PRIVATE { $$.op_type = T_PRIVATE; } - | T_PROTECTED { $$.op_type = T_PROTECTED; } +access_modifier: + T_PUBLIC { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; } + | T_PROTECTED { $$.u.constant.value.lval = ZEND_ACC_PROTECTED; } + | T_PRIVATE { $$.u.constant.value.lval = ZEND_ACC_PRIVATE; } +; + +class_variable_declaration: + class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL TSRMLS_CC); } + | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5 TSRMLS_CC); } + | T_VARIABLE { zend_do_declare_property(&$1, NULL TSRMLS_CC); } + | T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3 TSRMLS_CC); } ; class_constant_declaration: - | T_CONST ',' T_STRING '=' static_scalar { zend_do_declare_property(&$3, &$5, T_CONST TSRMLS_CC); } - | T_CONST T_STRING '=' static_scalar { zend_do_declare_property(&$2, &$4, T_CONST TSRMLS_CC); } + class_constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } ; echo_expr_list: - | echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); } + echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); } | expr { zend_do_echo(&$1 TSRMLS_CC); } ; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 57fe3fc8bf..f26d032389 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -730,6 +730,10 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_ABSTRACT; } +"final" { + return T_FINAL; +} + "private" { return T_PRIVATE; } @@ -739,7 +743,7 @@ NEWLINE ("\r"|"\n"|"\r\n") } "public" { - return T_VAR; + return T_PUBLIC; } "unset" { -- 2.40.0