]> granicus.if.org Git - php/commitdiff
Port use statement
authorNikita Popov <nikic@php.net>
Mon, 21 Jul 2014 20:49:31 +0000 (22:49 +0200)
committerNikita Popov <nikic@php.net>
Mon, 21 Jul 2014 20:49:31 +0000 (22:49 +0200)
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_language_parser.y

index 784e43adecb88024108783afae70c7fabe794daa..c89b4af03c584497544fd1e5bb3d7206d4ab2b8e 100644 (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;
index 970a0c7e138f5b7f0b8ea96df541f8bd4c06c491..dccdf7f380078c0ee531a6cb53ce5f179d676495 100644 (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;
index 08972aa55aa804fcfa1a696f20a8a859e79121f9..f4bfd7b1069911fafcaf2b4f344d8ff69a023194 100644 (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: