From: Nikita Popov Date: Mon, 21 Jul 2014 20:49:31 +0000 (+0200) Subject: Port use statement X-Git-Tag: POST_AST_MERGE^2~99 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=37ac1b96ed1;p=php Port use statement --- diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 784e43adec..c89b4af03c 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -118,6 +118,9 @@ enum _zend_ast_kind { ZEND_AST_METHOD_REFERENCE, ZEND_AST_CLASS, + + ZEND_AST_USE, + ZEND_AST_USE_ELEM, }; typedef unsigned short zend_ast_kind; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 970a0c7e13..dccdf7f380 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -916,6 +916,10 @@ static void ptr_dtor(zval *zv) /* {{{ */ } /* }}} */ +static void str_dtor(zval *zv) { + STR_RELEASE(Z_STR_P(zv)); +} + void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */ { zend_label *dest; @@ -6478,6 +6482,97 @@ void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) { CG(active_class_entry) = NULL; } +void zend_compile_use(zend_ast *ast TSRMLS_DC) { + zend_uint i; + zend_string *current_ns = Z_TYPE(CG(current_namespace)) != IS_UNDEF + ? Z_STR(CG(current_namespace)) : NULL; + + for (i = 0; i < ast->children; ++i) { + zend_ast *use_ast = ast->child[i]; + zend_ast *old_name_ast = use_ast->child[0]; + zend_ast *new_name_ast = use_ast->child[1]; + zend_string *old_name = Z_STR_P(zend_ast_get_zval(old_name_ast)); + zend_string *new_name, *lcname; + zend_class_entry *ce; + + if (new_name_ast) { + new_name = STR_COPY(Z_STR_P(zend_ast_get_zval(new_name_ast))); + } else { + /* The form "use A\B" is eqivalent to "use A\B as B" */ + const char *p = zend_memrchr(old_name->val, '\\', old_name->len); + if (p) { + new_name = STR_INIT(p + 1, old_name->len - (p - old_name->val + 1), 0); + } else { + new_name = STR_COPY(old_name); + + if (!current_ns) { + if (zend_str_equals(new_name, "strict")) { + zend_error_noreturn(E_COMPILE_ERROR, + "You seem to be trying to use a different language..."); + } + + zend_error(E_WARNING, "The use statement with non-compound name '%s' " + "has no effect", new_name->val); + } + } + } + + lcname = STR_ALLOC(new_name->len, 0); + zend_str_tolower_copy(lcname->val, new_name->val, new_name->len); + + if (zend_str_equals(lcname, "self") || zend_str_equals(lcname, "parent")) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' " + "is a special class name", old_name->val, new_name->val, new_name->val); + } + + if (current_ns) { + zend_string *ns_name = STR_ALLOC(current_ns->len + 1 + new_name->len, 0); + zend_str_tolower_copy(ns_name->val, current_ns->val, current_ns->len); + ns_name->val[current_ns->len] = '\\'; + memcpy(ns_name->val + current_ns->len + 1, lcname->val, lcname->len); + + if (zend_hash_exists(CG(class_table), ns_name)) { + char *tmp = zend_str_tolower_dup(old_name->val, old_name->len); + + if (old_name->len != ns_name->len || memcmp(tmp, ns_name->val, ns_name->len)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because the name " + "is already in use", old_name->val, new_name->val); + } + + efree(tmp); + } + + STR_FREE(ns_name); + } else if ((ce = zend_hash_find_ptr(CG(class_table), lcname)) + && ce->type == ZEND_USER_CLASS + && ce->info.user.filename == CG(compiled_filename) + ) { + char *tmp = zend_str_tolower_dup(old_name->val, old_name->len); + + if (old_name->len != lcname->len || memcmp(tmp, lcname->val, lcname->len)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because the name " + "is already in use", old_name->val, new_name->val); + } + + efree(tmp); + } + + if (!CG(current_import)) { + CG(current_import) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_import), 8, NULL, str_dtor, 0); + } + + STR_ADDREF(old_name); + if (!zend_hash_add_ptr(CG(current_import), lcname, old_name)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because the name " + "is already in use", old_name->val, new_name->val); + } + + STR_RELEASE(lcname); + STR_RELEASE(new_name); + } +} + void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) { zend_ast *left_ast = ast->child[0]; zend_ast *right_ast = ast->child[1]; @@ -7388,6 +7483,9 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) { case ZEND_AST_CLASS: zend_compile_class_decl(ast TSRMLS_CC); break; + case ZEND_AST_USE: + zend_compile_use(ast TSRMLS_CC); + break; default: { znode result; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 08972aa55a..f4bfd7b106 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -255,7 +255,7 @@ top_statement: top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } | T_NAMESPACE '{' { zend_do_begin_namespace(NULL, 1 TSRMLS_CC); } top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } - | T_USE use_declarations ';' { zend_verify_namespace(TSRMLS_C); } + | T_USE use_declarations ';' { AS($2); zend_verify_namespace(TSRMLS_C); } | T_USE T_FUNCTION use_function_declarations ';' { zend_verify_namespace(TSRMLS_C); } | T_USE T_CONST use_const_declarations ';' { zend_verify_namespace(TSRMLS_C); } | constant_declaration ';' { zend_verify_namespace(TSRMLS_C); } @@ -263,14 +263,20 @@ top_statement: use_declarations: use_declarations ',' use_declaration + { $$.u.ast = zend_ast_dynamic_add($1.u.ast, $3.u.ast); } | use_declaration + { $$.u.ast = zend_ast_create_dynamic_and_add(ZEND_AST_USE, $1.u.ast); } ; use_declaration: - namespace_name { zend_do_use(&$1, NULL, 0 TSRMLS_CC); } - | namespace_name T_AS T_STRING { zend_do_use(&$1, &$3, 0 TSRMLS_CC); } - | T_NS_SEPARATOR namespace_name { zend_do_use(&$2, NULL, 1 TSRMLS_CC); } - | T_NS_SEPARATOR namespace_name T_AS T_STRING { zend_do_use(&$2, &$4, 1 TSRMLS_CC); } + namespace_name + { $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_ELEM, AST_ZVAL(&$1), NULL); } + | namespace_name T_AS T_STRING + { $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_ELEM, AST_ZVAL(&$1), AST_ZVAL(&$3)); } + | T_NS_SEPARATOR namespace_name + { $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_ELEM, AST_ZVAL(&$2), NULL); } + | T_NS_SEPARATOR namespace_name T_AS T_STRING + { $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_ELEM, AST_ZVAL(&$2), AST_ZVAL(&$4)); } ; use_function_declarations: