From: Stanislav Malyshev Date: Sun, 16 Feb 2003 11:12:43 +0000 (+0000) Subject: Namespace patch. Big changes: X-Git-Tag: RELEASE_0_5~986 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a4c3b2ce807dec309812cfe72c91a597c8476113;p=php Namespace patch. Big changes: 1. Nested classes are gone. 2. New syntax for namespaces: namespace foo { class X { ... } function bar { ... } var x = 1; const ZZ = 2; } 3. Namespaced symbol access: $x = new foo::X; - etc. For now, namespaces are case insensitive, just like classes. Also, there can be no global class and namespace with the same name (to avoid ambiguities in :: resolution). --- diff --git a/Zend/zend.c b/Zend/zend.c index c45cc63d1d..e3b538a3e2 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -29,9 +29,9 @@ #include "zend_ini.h" #ifdef ZTS -# define GLOBAL_FUNCTION_TABLE &global_main_class.function_table -# define GLOBAL_CLASS_TABLE &global_main_class.class_table -# define GLOBAL_CONSTANTS_TABLE &global_main_class.constants_table +# define GLOBAL_FUNCTION_TABLE &global_namespace.function_table +# define GLOBAL_CLASS_TABLE &global_namespace.class_table +# define GLOBAL_CONSTANTS_TABLE &global_namespace.constants_table # define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table #else # define GLOBAL_FUNCTION_TABLE CG(function_table) @@ -92,6 +92,7 @@ ZEND_API int compiler_globals_id; ZEND_API int executor_globals_id; ZEND_API int alloc_globals_id; zend_class_entry global_main_class; +zend_namespace global_namespace; HashTable *global_auto_globals_table; #endif @@ -401,11 +402,11 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals TSRMLS compiler_globals->compiled_filename = NULL; - compiler_globals->function_table = &compiler_globals->main_class.function_table; + compiler_globals->function_table = &compiler_globals->global_namespace.function_table; zend_hash_init_ex(compiler_globals->function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_hash_copy(compiler_globals->function_table, GLOBAL_FUNCTION_TABLE, NULL, &tmp_func, sizeof(zend_function)); - compiler_globals->class_table = &compiler_globals->main_class.class_table; + compiler_globals->class_table = &compiler_globals->global_namespace.class_table; zend_hash_init_ex(compiler_globals->class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); zend_hash_copy(compiler_globals->class_table, GLOBAL_CLASS_TABLE, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry *)); @@ -551,8 +552,9 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO)-1; #ifndef ZTS - GLOBAL_FUNCTION_TABLE = &compiler_globals.main_class.function_table; - GLOBAL_CLASS_TABLE = &compiler_globals.main_class.class_table; + GLOBAL_FUNCTION_TABLE = &compiler_globals.global_namespace.function_table; + GLOBAL_CLASS_TABLE = &compiler_globals.global_namespace.class_table; + compiler_globals.global_namespace.static_members = NULL; #endif GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); diff --git a/Zend/zend.h b/Zend/zend.h index ac86552e0a..c031bce103 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -262,7 +262,18 @@ struct _zval_struct { zend_uchar is_ref; }; +struct _zend_op_array; +/* typedef struct _zend_namespace { + char *name; + zend_uint name_length; + HashTable function_table; + HashTable class_table; + HashTable constants_table; + HashTable *global_variables; + struct _zend_op_array *op_array; +} zend_namespace; +*/ typedef struct _zend_function_entry { char *fname; @@ -308,6 +319,7 @@ struct _zend_class_entry { HashTable *static_members; HashTable constants_table; zend_function_entry *builtin_functions; + struct _zend_class_entry *namespace; union _zend_function *constructor; union _zend_function *destructor; @@ -316,6 +328,7 @@ struct _zend_class_entry { union _zend_function *__set; union _zend_function *__call; + /* handlers */ zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC); @@ -327,6 +340,7 @@ struct _zend_class_entry { #endif }; +typedef struct _zend_class_entry zend_namespace; /* namespace is the same as class */ typedef struct _zend_utility_functions { void (*error_function)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e1eaafdbea..c103be1cc3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -74,7 +74,7 @@ void zend_init_compiler_data_structures(TSRMLS_D) zend_stack_init(&CG(object_stack)); zend_stack_init(&CG(declare_stack)); CG(active_class_entry) = NULL; - CG(active_ce_parent_class_name).value.str.val = NULL; + CG(active_namespace) = &CG(global_namespace); zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0); zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0); zend_stack_init(&CG(list_stack)); @@ -937,6 +937,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n op_array.fn_flags = fn_flags; op_array.scope = CG(active_class_entry); + op_array.namespace = CG(active_namespace); if (is_method) { char *short_class_name = CG(active_class_entry)->name; @@ -1150,7 +1151,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC) } -void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_DC) +void do_fetch_class(znode *result, znode *namespace_name, znode *class_name TSRMLS_DC) { long fetch_class_op_number; zend_op *opline; @@ -1159,8 +1160,9 @@ void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CLASS; - if (class_entry) { - opline->op1 = *class_entry; + if (namespace_name) { + zend_str_tolower(namespace_name->u.constant.value.str.val, namespace_name->u.constant.value.str.len); + opline->op1 = *namespace_name; } else { SET_UNUSED(opline->op1); CG(catch_begin) = fetch_class_op_number; @@ -1675,6 +1677,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze zend_initialize_class_data(new_class_entry, 1); zend_str_tolower(new_class_entry->name, new_class_entry->name_length); + if (zend_hash_update(class_table, new_class_entry->name, name_length+1, &new_class_entry, sizeof(zend_class_entry *), NULL) == FAILURE) { zend_error(E_COMPILE_ERROR, "Can't create class. Fatal error, please report!"); } @@ -1715,7 +1718,7 @@ static int create_nested_class(HashTable *class_table, char *path, zend_class_en new_ce->refcount++; if (zend_hash_add(&ce->class_table, last, strlen(last)+1, &new_ce, sizeof(zend_class_entry *), NULL) == FAILURE) { new_ce->refcount--; - zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", last); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class '%s' - class or namespace with this name already exist.", last); return FAILURE; } return SUCCESS; @@ -1726,7 +1729,7 @@ ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTa zend_function *function; if (opline->opcode != ZEND_DECLARE_FUNCTION) { - zend_error(E_ERROR, "Internal compiler error. Please report!"); + zend_error(E_COMPILE_ERROR, "Internal compiler error. Please report!"); } zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function); @@ -1758,7 +1761,7 @@ ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable zend_class_entry *ce, **pce; if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { - zend_error(E_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); return FAILURE; } else { ce = *pce; @@ -1769,7 +1772,7 @@ ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable ce->refcount++; if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { ce->refcount--; - zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); return FAILURE; } else { return SUCCESS; @@ -1784,7 +1787,7 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table, found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce); if (found_ce == FAILURE) { - zend_error(E_ERROR, "Cannot redeclare class %s", (*pce)->name); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name); return FAILURE; } else { ce = *pce; @@ -1800,7 +1803,7 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table, /* Register the derived class */ if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { - zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); ce->refcount--; zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->default_properties); @@ -2114,7 +2117,6 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod int doing_inheritance = 0; zend_class_entry *new_class_entry = emalloc(sizeof(zend_class_entry)); - class_token->u.previously_active_class_entry = CG(active_class_entry); if (!(strcmp(class_name->u.constant.value.str.val, "main") && strcmp(class_name->u.constant.value.str.val, "self") && strcmp(class_name->u.constant.value.str.val, "parent"))) { zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val); @@ -2148,7 +2150,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod opline->op2.op_type = IS_CONST; opline->op2.u.constant.type = IS_STRING; opline->op2.u.constant.refcount = 1; - + if (doing_inheritance) { opline->extended_value = parent_class_name->u.var; opline->opcode = ZEND_DECLARE_INHERITED_CLASS; @@ -2158,7 +2160,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod opline->op2.u.constant.value.str.val = estrndup(new_class_entry->name, new_class_entry->name_length); opline->op2.u.constant.value.str.len = new_class_entry->name_length; - + zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL); CG(active_class_entry) = new_class_entry; } @@ -2167,11 +2169,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod void zend_do_end_class_declaration(znode *class_token TSRMLS_DC) { do_inherit_parent_constructor(CG(active_class_entry)); - CG(active_class_entry) = class_token->u.previously_active_class_entry; - if (CG(active_ce_parent_class_name).value.str.val) { - efree(CG(active_ce_parent_class_name).value.str.val); - CG(active_ce_parent_class_name).value.str.val = NULL; - } + CG(active_class_entry) = NULL; } void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length) @@ -3180,6 +3178,116 @@ void zend_destroy_property_info(zend_property_info *property_info) efree(property_info->name); } +void zend_init_namespace(zend_namespace *ns TSRMLS_DC) +{ + zend_hash_init(&ns->function_table, 10, NULL, ZEND_FUNCTION_DTOR, 0); + zend_hash_init(&ns->class_table, 10, NULL, ZEND_CLASS_DTOR, 0); + zend_hash_init(&ns->constants_table, 10, NULL, ZVAL_PTR_DTOR, 0); + ALLOC_HASHTABLE(ns->static_members); + zend_hash_init(ns->static_members, 0, NULL, ZVAL_PTR_DTOR, 0); + ns->constructor = NULL; + ns->type = ZEND_NAMESPACE; +} + +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC) +{ + zend_namespace *ns = emalloc(sizeof(zend_namespace)); + zend_op *opline; + + zend_str_tolower(ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len); + ns->name = ns_name->u.constant.value.str.val; + ns->name_length = ns_name->u.constant.value.str.len; + + if(zend_hash_add(&CG(global_namespace).class_table, ns->name, ns->name_length+1, (void **)&ns, sizeof(zend_namespace *), NULL) != SUCCESS) { + efree(ns); + zend_error(E_COMPILE_ERROR, "Cannot redefine namespace '%s' - class or namespace with this name already defined", ns->name); + } + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_DECLARE_NAMESPACE; + opline->op1.op_type = IS_CONST; + opline->op1.u.constant.type = IS_STRING; + opline->op1.u.constant.value.str.val = estrndup(ns->name, ns->name_length); + opline->op1.u.constant.value.str.len = ns->name_length; + opline->op1.u.constant.refcount = 1; + SET_UNUSED(opline->op2); + + zend_init_namespace(ns TSRMLS_CC); + + ns->constructor = emalloc(sizeof(zend_op_array)); + init_op_array((zend_op_array *)ns->constructor, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); + ns->constructor->op_array.namespace = CG(active_namespace); + + ns_token->u.op_array = CG(active_op_array); + + CG(active_op_array) = &ns->constructor->op_array; + CG(active_namespace) = ns; + + /* new symbol tables */ + CG(class_table) = &ns->class_table; + CG(function_table) = &ns->function_table; + + fprintf(stderr, "Start namespace '%s'\n", ns->name); +} + +void zend_do_end_namespace(znode *ns_token TSRMLS_DC) +{ + zend_namespace *ns = CG(active_op_array)->namespace; + int handle = CG(handle_op_arrays); + + + zend_do_return(NULL, 0 TSRMLS_CC); + CG(handle_op_arrays) = 0; + pass_two(CG(active_op_array) TSRMLS_CC); + CG(handle_op_arrays) = handle; + + CG(active_op_array)->namespace = CG(active_namespace); + + CG(active_namespace) = ns; + CG(active_op_array) = ns_token->u.op_array; + /* restore symbol tables */ + CG(class_table) = &CG(active_namespace)->class_table; + CG(function_table) = &CG(active_namespace)->function_table; + + fprintf(stderr, "End namespace\n"); +} + +void zend_do_declare_namespace_var(znode *var_name, znode *value TSRMLS_DC) +{ + zval *var; + + ALLOC_ZVAL(var); + + if (value) { + *var = value->u.constant; + } else { + INIT_PZVAL(var); + var->type = IS_NULL; + } + + zend_hash_update(CG(active_namespace)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &var, sizeof(zval *), NULL); + + FREE_PNODE(var_name); +} + +void zend_do_declare_namespace_constant(znode *var_name, znode *value TSRMLS_DC) +{ + zval *var; + + ALLOC_ZVAL(var); + + if (value) { + *var = value->u.constant; + } else { + INIT_PZVAL(var); + var->type = IS_NULL; + } + + zend_hash_update(&CG(active_namespace)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &var, sizeof(zval *), NULL); + + FREE_PNODE(var_name); +} void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers) { @@ -3211,6 +3319,8 @@ void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers ce->__call = NULL; ce->create_object = NULL; } + + ce->namespace = CG(active_namespace); } /* diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index ec82fe727a..a43501ad36 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -53,7 +53,6 @@ typedef struct _znode { zend_uint var; zend_uint opline_num; /* Needs to be signed */ zend_op_array *op_array; - zend_class_entry *previously_active_class_entry; /* Used at compile-time */ zend_op *jmp_addr; struct { zend_uint var; /* dummy */ @@ -119,6 +118,7 @@ struct _zend_op_array { char *function_name; /* MUST be the third element of this struct! */ zend_class_entry *scope; /* MUST be the fourth element of this struct! */ zend_uint fn_flags; /* MUST be the fifth element of this struct! */ + zend_namespace *namespace; zend_uint *refcount; @@ -154,6 +154,7 @@ typedef struct _zend_internal_function { char *function_name; /* MUST be the third element of this struct! */ zend_class_entry *scope; /* MUST be the fourth element of this struct! */ zend_uint fn_flags; /* MUST be the fifth element of this struct! */ + zend_namespace *namespace; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); } zend_internal_function; @@ -169,6 +170,7 @@ typedef union _zend_function { char *function_name; zend_class_entry *scope; zend_uint fn_flags; + zend_namespace *namespace; } common; zend_op_array op_array; @@ -322,7 +324,7 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia int zend_do_begin_function_call(znode *function_name TSRMLS_DC); void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC); -void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_DC); +void do_fetch_class(znode *result, znode *namespace_name, znode *class_name TSRMLS_DC); void do_fetch_class_name(znode *result, znode *class_entry, znode *class_name, zend_bool case_sensitive TSRMLS_DC); void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name TSRMLS_DC); void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC); @@ -445,12 +447,19 @@ ZEND_API void destroy_zend_function(zend_function *function); ZEND_API void destroy_zend_class(zend_class_entry **pce); void zend_class_add_ref(zend_class_entry **ce); +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC); +void zend_do_end_namespace(znode *ns_token TSRMLS_DC); +void zend_init_namespace(zend_namespace *ns TSRMLS_DC); +void zend_do_declare_namespace_var(znode *name, znode *value TSRMLS_DC); +void zend_do_declare_namespace_constant(znode *name, znode *value TSRMLS_DC); +ZEND_API void destroy_zend_namespace(zend_namespace **pns); void zend_duplicate_property_info(zend_property_info *property_info); void zend_destroy_property_info(zend_property_info *property_info); #define ZEND_FUNCTION_DTOR (void (*)(void *)) destroy_zend_function #define ZEND_CLASS_DTOR (void (*)(void *)) destroy_zend_class +#define ZEND_NAMESPACE_DTOR (void (*)(void *)) destroy_zend_namespace zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC); void init_op(zend_op *op TSRMLS_DC); @@ -648,6 +657,8 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_RAISE_ABSTRACT_ERROR 142 +#define ZEND_DECLARE_NAMESPACE 143 + /* end of block */ @@ -664,6 +675,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_FETCH_CLASS_SELF 1 #define ZEND_FETCH_CLASS_PARENT 2 #define ZEND_FETCH_CLASS_MAIN 3 +#define ZEND_FETCH_CLASS_GLOBAL 4 /* variable parsing type (compile-time) */ @@ -694,6 +706,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_INTERNAL_CLASS 1 #define ZEND_USER_CLASS 2 +#define ZEND_NAMESPACE 3 #define ZEND_EVAL (1<<0) #define ZEND_INCLUDE (1<<1) diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 956dfa53a1..826e6071fa 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -80,7 +80,7 @@ void clean_module_constants(int module_number TSRMLS_DC) int zend_startup_constants(TSRMLS_D) { - EG(zend_constants) = &CG(main_class).constants_table; + EG(zend_constants) = &CG(global_namespace).constants_table; if (zend_hash_init(EG(zend_constants), 20, NULL, ZEND_CONSTANT_DTOR, 1)==FAILURE) { return FAILURE; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index cdb7fa6844..4caed9cb1c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1208,7 +1208,10 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) */ EX(function_state).function_symbol_table = NULL; #endif - + if(EG(active_namespace) != op_array->namespace) { + zend_switch_namespace(op_array->namespace TSRMLS_CC); + } + while (1) { #ifdef ZEND_WIN32 if (EG(timed_out)) { @@ -2299,7 +2302,7 @@ int zend_fetch_class_handler(ZEND_OPCODE_HANDLER_ARGS) zval tmp; int retval; - if (EX(opline)->op1.op_type == IS_UNUSED) { + if (EX(opline)->op2.op_type == IS_UNUSED) { if (EX(opline)->extended_value == ZEND_FETCH_CLASS_SELF) { if (!EG(scope)) { zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); @@ -2307,7 +2310,7 @@ int zend_fetch_class_handler(ZEND_OPCODE_HANDLER_ARGS) EX_T(EX(opline)->result.u.var).EA.class_entry = EG(scope); NEXT_OPCODE(); } else if (EX(opline)->extended_value == ZEND_FETCH_CLASS_MAIN) { - EX_T(EX(opline)->result.u.var).EA.class_entry = EG(main_class_ptr); + EX_T(EX(opline)->result.u.var).EA.class_entry = EG(global_namespace_ptr); NEXT_OPCODE(); } else if (EX(opline)->extended_value == ZEND_FETCH_CLASS_PARENT) { if (!EG(scope)) { @@ -2318,7 +2321,7 @@ int zend_fetch_class_handler(ZEND_OPCODE_HANDLER_ARGS) } EX_T(EX(opline)->result.u.var).EA.class_entry = EG(scope)->parent; NEXT_OPCODE(); - } + } } is_const = (EX(opline)->op2.op_type == IS_CONST); @@ -2338,10 +2341,28 @@ int zend_fetch_class_handler(ZEND_OPCODE_HANDLER_ARGS) class_name_strlen = tmp.value.str.len; } - if (EX(opline)->op1.op_type == IS_UNUSED) { + if (EX(opline)->op1.op_type == IS_UNUSED && EX(opline)->extended_value != ZEND_FETCH_CLASS_GLOBAL) { retval = zend_lookup_class(class_name_strval, class_name_strlen, &pce TSRMLS_CC); + + if(retval == FAILURE) { + /* try namespace */ + if(zend_hash_find(&EG(global_namespace_ptr)->class_table, class_name_strval, class_name_strlen+1, (void **)&pce) == SUCCESS && (*pce)->type == ZEND_NAMESPACE) { + retval = SUCCESS; + } + } + } else { - retval = zend_hash_find(&EX_T(EX(opline)->op1.u.var).EA.class_entry->class_table, class_name_strval, class_name_strlen+1, (void **)&pce); + zend_namespace *ns; + /* Looking for namespace */ + if(EX(opline)->extended_value == ZEND_FETCH_CLASS_GLOBAL) { + ns = EG(global_namespace_ptr); + } else { + if (zend_hash_find(&EG(global_namespace_ptr)->class_table, EX(opline)->op1.u.constant.value.str.val, EX(opline)->op1.u.constant.value.str.len+1, (void **)&pce) == FAILURE || (*pce)->type != ZEND_NAMESPACE) { + zend_error(E_ERROR, "Namespace '%s' not found", EX(opline)->op1.u.constant.value.str.val); + } + ns = *pce; + } + retval = zend_hash_find(&ns->class_table, class_name_strval, class_name_strlen+1, (void **)&pce); } if (retval == FAILURE) { @@ -2535,7 +2556,10 @@ int zend_init_fcall_by_name_handler(ZEND_OPCODE_HANDLER_ARGS) } */ if (zend_hash_find(EG(function_table), function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) { - zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval); + /* try global space also */ + if(zend_hash_find(&EG(global_namespace_ptr)->function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) { + zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval); + } } EX(calling_scope) = function->common.scope; EX(object) = NULL; @@ -2557,7 +2581,8 @@ int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *current_scope; zval *current_this; int return_value_used = RETURN_VALUE_USED(EX(opline)); - + zend_namespace *active_namespace = EG(active_namespace); + zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *) EX(opline)->extended_value, NULL); EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr; @@ -2647,6 +2672,9 @@ int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS) } zend_ptr_stack_n_pop(&EG(arg_types_stack), 3, &EX(calling_scope), &EX(object), &EX(fbc)); + if(EG(active_namespace) != active_namespace) { + zend_switch_namespace(active_namespace TSRMLS_CC); + } EX(function_state).function = (zend_function *) op_array; EG(function_state_ptr) = &EX(function_state); zend_ptr_stack_clear_multiple(TSRMLS_C); @@ -3105,7 +3133,7 @@ int zend_clone_handler(ZEND_OPCODE_HANDLER_ARGS) int zend_fetch_constant_handler(ZEND_OPCODE_HANDLER_ARGS) { - zend_class_entry *ce; + zend_class_entry *ce = NULL; zval **value; if (EX(opline)->op1.op_type == IS_UNUSED) { @@ -3118,6 +3146,16 @@ int zend_fetch_constant_handler(ZEND_OPCODE_HANDLER_ARGS) NEXT_OPCODE(); } } + if(EG(active_namespace) != EG(global_namespace_ptr)) { + /* if we are not global, go find in local constant table */ + if (zend_hash_find(&EG(active_namespace)->constants_table, EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + zval_update_constant(value, (void *) 1 TSRMLS_CC); + EX_T(EX(opline)->result.u.var).tmp_var = **value; + zval_copy_ctor(&EX_T(EX(opline)->result.u.var).tmp_var); + NEXT_OPCODE(); + } + } + if (!zend_get_constant(EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len, &EX_T(EX(opline)->result.u.var).tmp_var TSRMLS_CC)) { zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", EX(opline)->op2.u.constant.value.str.val, @@ -3130,7 +3168,7 @@ int zend_fetch_constant_handler(ZEND_OPCODE_HANDLER_ARGS) ce = EX_T(EX(opline)->op1.u.var).EA.class_entry; - if (&ce->constants_table == &EG(main_class_ptr)->constants_table) { + if (&ce->constants_table == &EG(global_namespace_ptr)->constants_table) { if (!zend_get_constant(EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len, &EX_T(EX(opline)->result.u.var).tmp_var TSRMLS_CC)) { zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", EX(opline)->op2.u.constant.value.str.val, @@ -3308,6 +3346,7 @@ int zend_include_or_eval_handler(ZEND_OPCODE_HANDLER_ARGS) } if (zend_hash_add(&EG(included_files), opened_path, strlen(opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) { + CG(active_namespace) = EG(active_namespace); new_op_array = zend_compile_file(&file_handle, (EX(opline)->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC); zend_destroy_file_handle(&file_handle TSRMLS_CC); opened_path = NULL; /* zend_destroy_file_handle() already frees it */ @@ -3330,11 +3369,13 @@ int zend_include_or_eval_handler(ZEND_OPCODE_HANDLER_ARGS) break; case ZEND_INCLUDE: case ZEND_REQUIRE: + CG(active_namespace) = EG(active_namespace); new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); break; case ZEND_EVAL: { char *eval_desc = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC); + CG(active_namespace) = EG(active_namespace); new_op_array = compile_string(inc_filename, eval_desc TSRMLS_CC); efree(eval_desc); } @@ -3349,7 +3390,7 @@ int zend_include_or_eval_handler(ZEND_OPCODE_HANDLER_ARGS) if (new_op_array) { zval *saved_object; zend_function *saved_function; - + zend_namespace *active_namespace = EG(active_namespace); EG(return_value_ptr_ptr) = EX_T(EX(opline)->result.u.var).var.ptr_ptr; EG(active_op_array) = new_op_array; @@ -3363,6 +3404,9 @@ int zend_include_or_eval_handler(ZEND_OPCODE_HANDLER_ARGS) zend_execute(new_op_array TSRMLS_CC); + if(EG(active_namespace) != active_namespace) { + zend_switch_namespace(active_namespace TSRMLS_CC); + } EX(function_state).function = saved_function; EX(object) = saved_object; @@ -3876,6 +3920,57 @@ int zend_nop_handler(ZEND_OPCODE_HANDLER_ARGS) NEXT_OPCODE(); } +int zend_declare_namespace_handler(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op_array *new_op_array=NULL; + zval **original_return_value = EG(return_value_ptr_ptr); + zval *namespace_name = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R); + zend_namespace **pns; + zval *saved_object; + zend_function *saved_function; + zend_namespace *active_namespace = EG(active_namespace); + + if (Z_TYPE_P(namespace_name) != IS_STRING) { + zend_error(E_ERROR, "Internal error: Invalid type in namespace definition - %d", Z_TYPE_P(namespace_name)); + } + + if(zend_hash_find(&EG(global_namespace_ptr)->class_table, Z_STRVAL_P(namespace_name), Z_STRLEN_P(namespace_name)+1, (void **)&pns) != SUCCESS || (*pns)->type != ZEND_NAMESPACE) { + zend_error(E_ERROR, "Internal error: Cannot locate namespace '%s'", Z_STRVAL_P(namespace_name)); + } + + new_op_array = (*pns)->constructor; + + FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); + EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr; + + EG(return_value_ptr_ptr) = EX_T(EX(opline)->result.u.var).var.ptr_ptr; + EG(active_op_array) = new_op_array; + EX_T(EX(opline)->result.u.var).var.ptr = NULL; + + saved_object = EX(object); + saved_function = EX(function_state).function; + + EX(function_state).function = (zend_function *) new_op_array; + EX(object) = NULL; + + zend_execute(new_op_array TSRMLS_CC); + + if(EG(active_namespace) != active_namespace) { + zend_switch_namespace(active_namespace TSRMLS_CC); + } + EX(function_state).function = saved_function; + EX(object) = saved_object; + + if (EX_T(EX(opline)->result.u.var).var.ptr) { + zval_ptr_dtor(&EX_T(EX(opline)->result.u.var).var.ptr); + } + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = op_array; + EG(function_state_ptr) = &EX(function_state); + EG(return_value_ptr_ptr) = original_return_value; + NEXT_OPCODE(); +} void zend_init_opcodes_handlers() { @@ -4051,6 +4146,7 @@ void zend_init_opcodes_handlers() zend_opcode_handlers[ZEND_DECLARE_FUNCTION] = zend_declare_function_handler; zend_opcode_handlers[ZEND_RAISE_ABSTRACT_ERROR] = zend_raise_abstract_error_handler; + zend_opcode_handlers[ZEND_DECLARE_NAMESPACE] = zend_declare_namespace_handler; } /* diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 4168c2db92..252ea0c97b 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -69,6 +69,7 @@ static inline void safe_free_zval_ptr(zval *p) } ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC); ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); +void zend_switch_namespace(zend_namespace *ns TSRMLS_DC); static inline int i_zend_is_true(zval *op) { diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 275278e29d..77d43788e2 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -177,9 +177,10 @@ void init_executor(TSRMLS_D) EG(exception) = NULL; EG(scope) = NULL; + EG(active_namespace) = &CG(global_namespace); - EG(main_class_ptr) = &CG(main_class); - CG(main_class).static_members = &EG(symbol_table); + EG(global_namespace_ptr) = &CG(global_namespace); + CG(global_namespace).static_members = &EG(symbol_table); EG(current_execute_data) = NULL; @@ -191,6 +192,11 @@ void init_executor(TSRMLS_D) void shutdown_executor(TSRMLS_D) { + /* return to global namespace here */ + if(EG(active_namespace) != EG(global_namespace_ptr)) { + zend_switch_namespace(EG(global_namespace_ptr)); + } + zend_try { zend_ptr_stack_destroy(&EG(arg_types_stack)); @@ -531,7 +537,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun zend_class_entry *current_scope; zend_class_entry *calling_scope = NULL; zval *current_this; - + zend_namespace *current_namespace = EG(active_namespace); zend_execute_data execute_data; /* Initialize execute_data */ @@ -708,6 +714,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun } zend_ptr_stack_clear_multiple(TSRMLS_C); EG(function_state_ptr) = original_function_state_ptr; + EG(active_namespace) = current_namespace; if (EG(This)) { zval_ptr_dtor(&EG(This)); @@ -727,11 +734,6 @@ ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry *** zval *retval_ptr; int retval; - if (EG(scope)) { - if (zend_hash_find(&EG(scope)->class_table, name, name_length+1, (void **) ce) == SUCCESS) { - return SUCCESS; - } - } if (zend_hash_find(EG(class_table), name, name_length+1, (void **) ce) == SUCCESS) { return SUCCESS; } @@ -1037,6 +1039,17 @@ void zend_unset_timeout(TSRMLS_D) #endif } +void zend_switch_namespace(zend_namespace *ns TSRMLS_DC) +{ + if(NULL == ns) { + return; + } + EG(active_namespace) = ns; + EG(function_table) = &ns->function_table; + EG(class_table) = &ns->class_table; +/* EG(zend_constants) = &ns->constants_table; */ +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 0508757c41..e5c6520787 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -70,7 +70,7 @@ struct _zend_compiler_globals { zend_stack declare_stack; zend_class_entry *active_class_entry; - zval active_ce_parent_class_name; + zend_namespace *active_namespace; /* variables for list() compilation */ zend_llist list_llist; @@ -88,9 +88,11 @@ struct _zend_compiler_globals { zend_op_array *active_op_array; - zend_class_entry main_class; + zend_namespace global_namespace; + HashTable *function_table; /* function symbol table */ HashTable *class_table; /* class table */ + HashTable namespace_table; /* namespaces */ HashTable filenames_table; @@ -167,7 +169,8 @@ struct _zend_executor_globals { HashTable *zend_constants; /* constants table */ zend_class_entry *scope; - zend_class_entry *main_class_ptr; + zend_namespace *global_namespace_ptr; + zend_namespace *active_namespace; zval *This; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 4dc5ba8b68..3d2ebd601f 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -139,6 +139,8 @@ %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM %token T_IMPORT T_FROM +%token T_NAMESPACE_NAME +%token T_NAMESPACE %% /* Rules */ @@ -156,6 +158,7 @@ top_statement: statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement + | namespace_declaration_statement ; @@ -211,10 +214,10 @@ unticked_statement: | T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); } | ';' /* empty statement */ | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' - T_CATCH '(' catch_or_import_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } + T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } additional_catches | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } - | T_IMPORT { zend_do_begin_import(TSRMLS_C); } import_rule T_FROM catch_or_import_class_entry { zend_do_end_import(&$5 TSRMLS_CC); } ';' + | T_IMPORT { zend_do_begin_import(TSRMLS_C); } import_rule T_FROM import_namespace { zend_do_end_import(&$5 TSRMLS_CC); } ';' ; @@ -243,8 +246,8 @@ additional_catches: ; non_empty_additional_catches: - non_empty_additional_catches T_CATCH '(' catch_or_import_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); } - | T_CATCH '(' catch_or_import_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } + non_empty_additional_catches T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); } + | T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } ; @@ -287,13 +290,45 @@ unticked_class_declaration_statement: T_CLASS declaration_class_name extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); } ; +namespace_declaration_statement: + T_NAMESPACE T_STRING '{' { zend_do_begin_namespace(&$1, &$2 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); } +; + +namespace_statement_list: + namespace_statement_list namespace_statement + | /* empty */ +; + +namespace_statement: + T_VAR namespace_var_declaration_list ';' + | namespace_const_declaration ';' + | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } + | class_declaration_statement + | namespace_declaration_statement +; + +namespace_var_declaration_list: + namespace_var_declaration_list ',' namespace_var_declaration + | namespace_var_declaration +; + +namespace_var_declaration: + T_VARIABLE { zend_do_declare_namespace_var(&$1, NULL TSRMLS_CC); } + | T_VARIABLE '=' static_scalar { zend_do_declare_namespace_var(&$1, &$3 TSRMLS_CC); } +; + +namespace_const_declaration: + namespace_const_declaration ',' T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar { zend_do_declare_namespace_constant(&$2, &$4 TSRMLS_CC); } +; + extends_from: - /* empty */ { $$.op_type = IS_UNUSED; } - | T_EXTENDS catch_or_import_class_entry { $$ = $2; } + /* empty */ { $$.op_type = IS_UNUSED; } + | T_EXTENDS catch_class_entry { $$ = $2; } ; declaration_class_name: - | parse_class_name_entry T_STRING { do_fetch_class_name(&$$, &$1, &$2, 0 TSRMLS_CC); } + | namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class_name(&$$, &$1, &$3, 0 TSRMLS_CC); } | T_STRING { $$ = $1; zend_str_tolower($$.u.constant.value.str.val, $$.u.constant.value.str.len); } ; @@ -421,7 +456,7 @@ global_var_list: global_var: T_VARIABLE { $$ = $1; } - | '$' r_variable { $$ = $2; } + | '$' r_variable { $$ = $2; } | '$' '{' expr '}' { $$ = $3; } ; @@ -446,7 +481,6 @@ class_statement: | class_constant_declaration ';' | 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 ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 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); } ; @@ -589,32 +623,37 @@ function_call: ; parse_class_entry: - parse_class_entry T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); } + T_NAMESPACE_NAME T_PAAMAYIM_NEKUDOTAYIM T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); } | T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } ; -parse_class_name_entry: - parse_class_name_entry T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class_name(&$$, &$1, &$2, 0 TSRMLS_CC); } - | T_STRING T_PAAMAYIM_NEKUDOTAYIM { $$ = $1; zend_str_tolower($$.u.constant.value.str.val, $$.u.constant.value.str.len); } -; +catch_class_entry: + namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); } + | T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } + ; -catch_or_import_class_entry: - parse_class_entry T_STRING { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); } +import_namespace: + T_NAMESPACE_NAME { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } | T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } ; new_class_entry: - parse_class_entry static_or_variable_string { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); } + namespace_prefix T_PAAMAYIM_NEKUDOTAYIM static_or_variable_string { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); } | static_or_variable_string { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } ; +namespace_prefix: + T_NAMESPACE_NAME { $$ = $1; } + | T_STRING { $$ = $1; } +; + static_or_variable_string: T_STRING { $$ = $1; } | r_variable_without_static_member { $$ = $1; } ; instanceof_expr: - parse_class_entry T_STRING { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); } + namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); } | T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } ; @@ -648,7 +687,7 @@ static_scalar: /* compile-time evaluated scalars */ | '+' static_scalar { $$ = $2; } | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; } - | parse_class_name_entry T_STRING { zend_do_fetch_constant(&$$, &$1, &$2, ZEND_CT TSRMLS_CC); } + | namespace_prefix T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT TSRMLS_CC); } ; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 4139f1d862..6908e15318 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -292,6 +292,7 @@ ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSR init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); CG(in_compilation) = 1; CG(active_op_array) = op_array; + op_array->namespace = CG(active_namespace); compiler_result = zendparse(TSRMLS_C); zend_do_return(&retval_znode, 0 TSRMLS_CC); CG(in_compilation) = original_in_compilation; @@ -405,6 +406,7 @@ zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC) } else { init_op_array(op_array, ZEND_EVAL_CODE, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); CG(active_op_array) = op_array; + op_array->namespace = CG(active_namespace); BEGIN(ST_IN_SCRIPTING); compiler_result = zendparse(TSRMLS_C); @@ -481,6 +483,7 @@ ENCAPSED_TOKENS [\[\]{}$] ESCAPED_AND_WHITESPACE [\n\t\r #'.:;,()|^&+-/*=%!~<>?@]+ ANY_CHAR (.|[\n]) NEWLINE ("\r"|"\n"|"\r\n") +NAMESPACE_NAME ({LABEL}":")+{LABEL} %option noyylineno %option noyywrap @@ -618,6 +621,10 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_EXTENDS; } +"namespace" { + return T_NAMESPACE; +} + "->" { yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC); return T_OBJECT_OPERATOR; @@ -1094,6 +1101,21 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_STRING; } +{NAMESPACE_NAME} { + int i; + + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + + /* Nuke this code */ + for (i=0; ivalue.str.val[i] == ':') { + zendlval->value.str.val[i] = '_'; + } + } + return T_NAMESPACE_NAME; +} {ENCAPSED_STRING} { zendlval->value.str.val = (char *)estrndup(yytext, yyleng); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 619c79168e..32bc402269 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -78,6 +78,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->arg_types = NULL; op_array->scope = NULL; + op_array->namespace = NULL; op_array->brk_cont_array = NULL; op_array->last_brk_cont = 0; @@ -166,9 +167,25 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) zend_hash_destroy(&ce->class_table); free(ce); break; + case ZEND_NAMESPACE: + destroy_zend_namespace(pce); + break; } } +ZEND_API void destroy_zend_namespace(zend_namespace **pns) +{ + zend_namespace *ns = *pns; + zend_hash_destroy(&ns->function_table); + zend_hash_destroy(&ns->class_table); + zend_hash_destroy(&ns->constants_table); + zend_hash_destroy(ns->static_members); + FREE_HASHTABLE(ns->static_members); + destroy_op_array(ns->constructor); + efree(ns->constructor); + efree(ns->name); + efree(ns); +} void zend_class_add_ref(zend_class_entry **ce) {