diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend.c php-5.1.0b2/Zend/zend.c --- php-5.1.0b2-bak/Zend/zend.c 2005-06-15 15:05:55.000000000 -0400 +++ php-5.1.0b2/Zend/zend.c 2005-07-09 00:44:41.000000000 -0400 @@ -34,10 +34,12 @@ # define GLOBAL_CLASS_TABLE global_class_table # define GLOBAL_CONSTANTS_TABLE global_constants_table # define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table +# define GLOBAL_IMPORT_CLASS_TABLE global_import_class_table #else # define GLOBAL_FUNCTION_TABLE CG(function_table) # define GLOBAL_CLASS_TABLE CG(class_table) # define GLOBAL_AUTO_GLOBALS_TABLE CG(auto_globals) +# define GLOBAL_IMPORT_CLASS_TABLE CG(import_class_table) #endif #if defined(ZEND_WIN32) && ZEND_DEBUG @@ -88,6 +90,7 @@ HashTable *global_class_table; HashTable *global_constants_table; HashTable *global_auto_globals_table; +HashTable *global_import_class_table; #endif ZEND_API zend_utility_values zend_uv; @@ -430,6 +433,7 @@ { zend_function tmp_func; zend_class_entry *tmp_class; + zval tmp_zval; compiler_globals->compiled_filename = NULL; @@ -443,6 +447,16 @@ zend_set_default_compile_time_values(TSRMLS_C); + /* initialize namespace variables */ + compiler_globals->namespace_prefix = NULL; + compiler_globals->namespace_prefix_lc = NULL; + compiler_globals->namespace_prefix_len = 0; + + /* initialize the import table */ + compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable)); + zend_hash_init_ex(compiler_globals->import_class_table, 10, NULL, ZVAL_DESTRUCTOR, 1, 0); + zend_hash_copy(compiler_globals->import_class_table, global_import_class_table, NULL, &tmp_zval, sizeof(zval)); + CG(interactive) = 0; compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); @@ -465,6 +479,10 @@ zend_hash_destroy(compiler_globals->auto_globals); free(compiler_globals->auto_globals); } + if (compiler_globals->import_class_table != GLOBAL_IMPORT_CLASS_TABLE) { + zend_hash_destroy(compiler_globals->import_class_table); + free(compiler_globals->import_class_table); + } } @@ -588,11 +606,13 @@ GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable)); GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_IMPORT_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); #ifdef ZTS GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable)); #endif zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_hash_init_ex(GLOBAL_CLASS_TABLE, 10, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_IMPORT_CLASS_TABLE, 10, NULL, ZVAL_DESTRUCTOR, 1, 0); zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0); zend_init_rsrc_list_dtors(); @@ -618,10 +638,12 @@ compiler_globals->in_compilation = 0; compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable)); *compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE; *compiler_globals->class_table = *GLOBAL_CLASS_TABLE; compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; + *compiler_globals->import_class_table = *GLOBAL_IMPORT_CLASS_TABLE; zend_hash_destroy(executor_globals->zend_constants); *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; @@ -676,9 +698,11 @@ *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + *GLOBAL_IMPORT_CLASS_TABLE = *compiler_globals->import_class_table; zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); free(compiler_globals->function_table); free(compiler_globals->class_table); + free(compiler_globals->import_class_table); compiler_globals_ctor(compiler_globals, tsrm_ls); free(EG(zend_constants)); executor_globals_ctor(executor_globals, tsrm_ls); @@ -699,6 +723,7 @@ zend_hash_destroy(GLOBAL_FUNCTION_TABLE); zend_hash_destroy(GLOBAL_CLASS_TABLE); + zend_hash_destroy(GLOBAL_IMPORT_CLASS_TABLE); zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); free(GLOBAL_AUTO_GLOBALS_TABLE); @@ -709,6 +734,7 @@ zend_shutdown_constants(TSRMLS_C); free(GLOBAL_FUNCTION_TABLE); free(GLOBAL_CLASS_TABLE); + free(GLOBAL_IMPORT_CLASS_TABLE); #ifdef ZTS zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); zend_hash_destroy(GLOBAL_CONSTANTS_TABLE); @@ -716,6 +742,7 @@ GLOBAL_FUNCTION_TABLE = NULL; GLOBAL_CLASS_TABLE = NULL; GLOBAL_AUTO_GLOBALS_TABLE = NULL; + GLOBAL_IMPORT_CLASS_TABLE = NULL; #endif zend_destroy_rsrc_list_dtors(); } diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_compile.c php-5.1.0b2/Zend/zend_compile.c --- php-5.1.0b2-bak/Zend/zend_compile.c 2005-06-22 04:32:57.000000000 -0400 +++ php-5.1.0b2/Zend/zend_compile.c 2005-07-09 00:44:41.000000000 -0400 @@ -1385,10 +1384,12 @@ zval_dtor(&class_name->u.constant); break; default: + zend_resolve_class_name_node(class_name TSRMLS_CC); opline->op2 = *class_name; break; } } else { + zend_resolve_class_name_node(class_name TSRMLS_CC); opline->op2 = *class_name; } opline->result.u.var = get_temporary_variable(CG(active_op_array)); @@ -2615,6 +2616,11 @@ zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val); } + /* fully prefix the class name */ + efree(lcname); + zend_prefix_class_name_node(class_name TSRMLS_CC); + lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = class_name->u.constant.value.str.val; new_class_entry->name_length = class_name->u.constant.value.str.len; @@ -2659,8 +2665,151 @@ CG(doc_comment) = NULL; CG(doc_comment_len) = 0; } + +} + +/***************************** + * BEGIN NAMESPACE FUNCTIONS * + *****************************/ + +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC) +{ + /* allocate space for the namespace prefix */ + CG(namespace_prefix) = emalloc(ns_name->u.constant.value.str.len + 2); + *CG(namespace_prefix) = '\0'; + + /* get the namespace prefix */ + strcat(CG(namespace_prefix), ns_name->u.constant.value.str.val); + strcat(CG(namespace_prefix), ":"); + + /* get the lowercased namespace prefix */ + CG(namespace_prefix_lc) = zend_str_tolower_dup(CG(namespace_prefix), ns_name->u.constant.value.str.len + 1); + + /* save the prefix length */ + CG(namespace_prefix_len) = ns_name->u.constant.value.str.len + 1; +} + +void zend_do_end_namespace(znode *ns_token TSRMLS_DC) +{ + /* free the string memory */ + efree(CG(namespace_prefix)); + efree(CG(namespace_prefix_lc)); + CG(namespace_prefix_len) = 0; + + /* set the prefixes to null */ + CG(namespace_prefix) = NULL; + CG(namespace_prefix_lc) = NULL; +} + +void zend_do_import(znode *class_name, znode *alias_name TSRMLS_DC) +{ + char *alias_name_lc = NULL; + zend_uint alias_name_len = 0; + zval alias_val; + /* 'colon_pos' is the position of the last colon in the full class name */ + char *colon_pos = strrchr(class_name->u.constant.value.str.val, ':'); + /* 'last_pos' is the position of the null terminator in the full class name */ + char *last_pos = class_name->u.constant.value.str.val + class_name->u.constant.value.str.len; + + if (colon_pos == NULL) { + zend_error(E_COMPILE_ERROR, "Cannot import non-namespace class: %s!", class_name->u.constant.value.str.val); + return; + } + + if (alias_name == NULL) { + /* advance to the first character of the class name */ + ++colon_pos; + + /* get the lowercased class name as the alias */ + alias_name_len = last_pos - colon_pos; + alias_name_lc = zend_str_tolower_dup(colon_pos, alias_name_len); + } else /* alias_name != NULL */ { + alias_name_lc = zend_str_tolower_dup(alias_name->u.constant.value.str.val, alias_name->u.constant.value.str.len); + alias_name_len = alias_name->u.constant.value.str.len; + } + + /* make sure this import alias is not the same as a class name */ + if (zend_hash_exists(CG(class_table), alias_name_lc, alias_name_len + 1)) { + zend_error(E_COMPILE_ERROR, "Could not import %s as %s: a class exists with the name %s", class_name->u.constant.value.str.val, alias_name_lc, alias_name_lc); + return; + } + + /* make sure this import alias has not been used before */ + if (zend_hash_exists(CG(import_class_table), alias_name_lc, alias_name_len + 1)) { + zend_error(E_COMPILE_ERROR, "An import was already done with the %s alias", alias_name_lc); + return; + } + + /* initialize the full class name zval */ + INIT_ZVAL(alias_val); + alias_val.value.str.val = estrdup(class_name->u.constant.value.str.val); + alias_val.value.str.len = class_name->u.constant.value.str.len; + + /* add the alias */ + if (zend_hash_add(CG(import_class_table), alias_name_lc, alias_name_len + 1, &alias_val, sizeof(alias_val), NULL) == FAILURE) { + zend_error(E_COMPILE_ERROR, "Could not import %s as %s!", class_name->u.constant.value.str.val, alias_name_lc); + return; + } + + efree(alias_name_lc); +} + +void zend_do_namespace_import(znode *ns_name TSRMLS_DC) +{ +} + +void zend_do_unimport_all(TSRMLS_D) +{ + zend_hash_clean(CG(import_class_table)); +} + +void zend_prefix_class_name_node(znode *class_name TSRMLS_DC) +{ + zend_uint new_length = 0; + char *org_class_name = NULL; + + if (CG(namespace_prefix) != NULL) { + new_length = CG(namespace_prefix_len) + class_name->u.constant.value.str.len; + org_class_name = estrdup(class_name->u.constant.value.str.val); + + STR_REALLOC(class_name->u.constant.value.str.val, new_length + 1); + + /* prepare for strcat */ + *class_name->u.constant.value.str.val = '\0'; + + /* get the full class name */ + strcat(class_name->u.constant.value.str.val, CG(namespace_prefix)); + strcat(class_name->u.constant.value.str.val, org_class_name); + + /* get the new string length */ + class_name->u.constant.value.str.len = new_length; + + efree(org_class_name); + } +} + +void zend_resolve_class_name_node(znode *class_name TSRMLS_DC) +{ + zval* mapped_class_name = NULL; + char *org_class_name = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + zend_uint org_class_name_len = class_name->u.constant.value.str.len; + + /* check to see if this class name is actually an import alias */ + if (zend_hash_find(CG(import_class_table), org_class_name, org_class_name_len + 1, (void **)&mapped_class_name) == SUCCESS) { + /* free the class name string */ + STR_FREE(class_name->u.constant.value.str.val); + + /* set the class node to contain the full class name */ + class_name->u.constant.value.str.val = estrdup(mapped_class_name->value.str.val); + class_name->u.constant.value.str.len = mapped_class_name->value.str.len; + } + + efree(org_class_name); } +/*************************** + * END NAMESPACE FUNCTIONS * + ***************************/ static void do_verify_abstract_class(TSRMLS_D) { diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_compile.h php-5.1.0b2/Zend/zend_compile.h --- php-5.1.0b2-bak/Zend/zend_compile.h 2005-06-22 04:32:57.000000000 -0400 +++ php-5.1.0b2/Zend/zend_compile.h 2005-07-09 00:44:41.000000000 -0400 @@ -438,6 +438,14 @@ void zend_do_declare_implicit_property(TSRMLS_D); void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC); +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_do_import(znode *class_name, znode *alias_name TSRMLS_DC); +void zend_do_namespace_import(znode *ns_name TSRMLS_DC); +void zend_do_unimport_all(TSRMLS_D); +void zend_prefix_class_name_node(znode *class_name TSRMLS_DC); +void zend_resolve_class_name_node(znode *class_name TSRMLS_DC); + void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC); diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_globals.h php-5.1.0b2/Zend/zend_globals.h --- php-5.1.0b2-bak/Zend/zend_globals.h 2004-11-03 18:13:32.000000000 -0500 +++ php-5.1.0b2/Zend/zend_globals.h 2005-07-09 00:44:41.000000000 -0400 @@ -143,6 +143,13 @@ zend_encoding_converter encoding_converter; zend_encoding_oddlen encoding_oddlen; #endif /* ZEND_MULTIBYTE */ + + /* namespace variables */ + char *namespace_prefix; + char *namespace_prefix_lc; + zend_uint namespace_prefix_len; + + HashTable *import_class_table; }; diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_language_parser.y php-5.1.0b2/Zend/zend_language_parser.y --- php-5.1.0b2-bak/Zend/zend_language_parser.y 2005-06-08 02:49:00.000000000 -0400 +++ php-5.1.0b2/Zend/zend_language_parser.y 2005-07-09 02:20:28.000000000 -0400 @@ -145,11 +145,13 @@ %token T_DOLLAR_OPEN_CURLY_BRACES %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM - +%token T_IMPORT +%token T_NAMESPACE_NAME +%token T_NAMESPACE %% /* Rules */ start: - top_statement_list + top_statement_list { zend_do_unimport_all(TSRMLS_C); } ; top_statement_list: @@ -162,6 +164,7 @@ statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } + | namespace_declaration_statement | T_HALT_COMPILER '(' ')' ';' { REGISTER_MAIN_LONG_CONSTANT("__COMPILER_HALT_OFFSET__", zend_get_scanned_file_offset(TSRMLS_C), CONST_CS); YYACCEPT; } ; @@ -231,6 +234,10 @@ '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); } | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE_NAME ';' { zend_do_import(&$2, NULL TSRMLS_CC); } + | T_IMPORT T_NAMESPACE_NAME T_AS T_STRING ';' { zend_do_import(&$2, &$4 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE T_NAMESPACE_NAME ';' { zend_do_namespace_import(&$3 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE T_STRING ';' { zend_do_namespace_import(&$3 TSRMLS_CC); } ; @@ -307,6 +314,19 @@ | T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; } ; +namespace_declaration_statement: + T_NAMESPACE namespace_name '{' { 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: + class_declaration_statement { zend_do_early_binding(TSRMLS_C); } +; + extends_from: /* empty */ { $$.op_type = IS_UNUSED; } | T_EXTENDS fully_qualified_class_name { $$ = $2; } @@ -639,10 +659,12 @@ fully_qualified_class_name: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; class_name_reference: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; @@ -654,6 +676,10 @@ | base_variable { $$ = $1; } ; +namespace_name: + T_NAMESPACE_NAME { $$ = $1; } + | T_STRING { $$ = $1; } +; dynamic_class_name_variable_properties: dynamic_class_name_variable_properties dynamic_class_name_variable_property Only in php-5.1.0b2/Zend/: zend_language_parser.y~ diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_language_scanner.l php-5.1.0b2/Zend/zend_language_scanner.l --- php-5.1.0b2-bak/Zend/zend_language_scanner.l 2005-06-16 09:31:21.000000000 -0400 +++ php-5.1.0b2/Zend/zend_language_scanner.l 2005-07-09 00:44:41.000000000 -0400 @@ -790,6 +790,7 @@ ESCAPED_AND_WHITESPACE [\n\t\r #'.:;,()|^&+-/*=%!~<>?@]+ ANY_CHAR (.|[\n]) NEWLINE ("\r"|"\n"|"\r\n") +NAMESPACE_NAME ({LABEL}":")*{LABEL} %option noyylineno %option noyywrap @@ -923,6 +924,14 @@ return T_CLASS; } +"namespace" { + return T_NAMESPACE; +} + +"import" { + return T_IMPORT; +} + "interface" { return T_INTERFACE; } @@ -1433,6 +1442,13 @@ return T_STRING; } +{NAMESPACE_NAME} { + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + return T_NAMESPACE_NAME; +} + {LABEL} { zend_copy_value(zendlval, yytext, yyleng); zendlval->type = IS_STRING;