Port use statement

This commit is contained in:
Nikita Popov 2014-07-21 22:49:31 +02:00
parent c60cd3e8ef
commit 37ac1b96ed
3 changed files with 112 additions and 5 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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: