]> granicus.if.org Git - php/commitdiff
Partial port of class declarations
authorNikita Popov <nikic@php.net>
Mon, 21 Jul 2014 14:34:45 +0000 (16:34 +0200)
committerNikita Popov <nikic@php.net>
Mon, 21 Jul 2014 14:34:45 +0000 (16:34 +0200)
Zend/zend_ast.c
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_language_parser.y

index b62bae9c853f2a939af244734ca1921f2354fc3c..aea1c817400a3469f205790532dcc07bb535d143 100644 (file)
@@ -350,6 +350,7 @@ ZEND_API void zend_ast_destroy(zend_ast *ast)
                case ZEND_AST_FUNC_DECL:
                case ZEND_AST_CLOSURE:
                case ZEND_AST_METHOD:
+               case ZEND_AST_CLASS:
                {
                        zend_ast_decl *decl = (zend_ast_decl *) ast;
                        STR_RELEASE(decl->name);
index 32316afa3c58b02b8187c6ef07e4708ac7023b97..784e43adecb88024108783afae70c7fabe794daa 100644 (file)
@@ -116,6 +116,8 @@ enum _zend_ast_kind {
        ZEND_AST_TRAIT_PRECEDENCE,
        ZEND_AST_TRAIT_ALIAS,
        ZEND_AST_METHOD_REFERENCE,
+
+       ZEND_AST_CLASS,
 };
 
 typedef unsigned short zend_ast_kind;
index d21dde7732d89277b2e13bc420ac2e031c9855c2..f15044c2655b914e538ab587bff281d19546e892 100644 (file)
@@ -6574,6 +6574,115 @@ void zend_compile_use_trait(zend_ast *ast TSRMLS_DC) {
        }
 }
 
+void zend_compile_class_decl(zend_ast *ast TSRMLS_DC) {
+       zend_ast_decl *decl = (zend_ast_decl *) ast;
+       zend_ast *extends_ast = decl->child[0];
+       zend_ast *implements_ast = decl->child[1];
+       zend_ast *stmt_ast = decl->child[2];
+
+       zend_string *name = decl->name, *lcname, *import_name = NULL;
+       zend_class_entry *ce = emalloc(sizeof(zend_class_entry));
+       zend_op *opline;
+       znode extends_node;
+
+       if (CG(active_class_entry)) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
+               return;
+       }
+
+       if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name->val, name->len)) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved",
+                       name->val);
+       }
+
+       lcname = STR_ALLOC(name->len, 0);
+       zend_str_tolower_copy(lcname->val, name->val, name->len);
+
+       if (CG(current_import)) {
+               import_name = zend_hash_find_ptr(CG(current_import), lcname);
+       }
+
+       if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) {
+               name = zend_concat_names(Z_STRVAL(CG(current_namespace)), Z_STRLEN(CG(current_namespace)),
+                       name->val, name->len);
+
+               STR_RELEASE(lcname);
+               lcname = STR_ALLOC(name->len, 0);
+               zend_str_tolower_copy(lcname->val, name->val, name->len);
+       } else {
+               STR_ADDREF(name);
+       }
+
+       if (import_name) {
+               char *import_name_lc = zend_str_tolower_dup(import_name->val, import_name->len);
+               if (lcname->len != import_name->len
+                       || memcmp(import_name_lc, lcname->val, lcname->len)
+               ) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare class %s "
+                               "because the name is already in use", name->val);
+               }
+               efree(import_name_lc);
+       }
+
+       ce->type = ZEND_USER_CLASS;
+       ce->name = zend_new_interned_string(name TSRMLS_CC);
+       zend_initialize_class_data(ce, 1 TSRMLS_CC);
+
+       ce->ce_flags |= decl->flags;
+       ce->info.user.filename = zend_get_compiled_filename(TSRMLS_C);
+       ce->info.user.line_start = decl->start_lineno;
+       ce->info.user.line_end = decl->end_lineno;
+       if (decl->doc_comment) {
+               ce->info.user.doc_comment = STR_COPY(decl->doc_comment);
+       }
+
+       if (extends_ast) {
+               if (ce->ce_flags & ZEND_ACC_TRAIT) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. "
+                               "Traits can only be composed from other traits with the 'use' keyword. Error",
+                               name->val);
+               }
+
+               if (!zend_is_const_default_class_ref(extends_ast)) {
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "Cannot use '%s' as class name as it is reserved", name->val);
+               }
+
+               zend_compile_class_ref(&extends_node, extends_ast TSRMLS_CC);
+       }
+
+
+       opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+       opline->result.var = get_temporary_variable(CG(active_op_array));
+       opline->result_type = IS_VAR;
+       opline->op2_type = IS_CONST;
+       LITERAL_STR(opline->op2, lcname);
+
+       if (extends_ast) {
+               opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
+               opline->extended_value = extends_node.u.op.var;
+       } else {
+               opline->opcode = ZEND_DECLARE_CLASS;
+       }
+
+       {
+               zval key;
+               build_runtime_defined_function_key(&key, lcname, decl->lex_pos TSRMLS_CC);
+               opline->op1_type = IS_CONST;
+               opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
+
+               zend_hash_update_ptr(CG(class_table), Z_STR(key), ce);
+       }
+
+       CG(active_class_entry) = ce;
+
+       zend_compile_stmt(stmt_ast TSRMLS_CC);
+
+       // TODO.AST traits, interfaces, extends, etc
+
+       CG(active_class_entry) = NULL;
+}
+
 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];
@@ -7423,6 +7532,9 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
                case ZEND_AST_USE_TRAIT:
                        zend_compile_use_trait(ast TSRMLS_CC);
                        break;
+               case ZEND_AST_CLASS:
+                       zend_compile_class_decl(ast TSRMLS_CC);
+                       break;
                default:
                {
                        znode result;
index 77c4ef614c0e809421a2e119b11847777e23d57b..67d0504cd4baaa37fd6e82a71f786320769d0a8c 100644 (file)
@@ -409,18 +409,18 @@ is_variadic:
 ;
 
 unticked_class_declaration_statement:
-               class_entry_type T_STRING extends_from
-                       { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
-                       implements_list
-                       '{'
-                               class_statement_list
-                       '}' { zend_do_end_class_declaration(&$1, &$3 TSRMLS_CC); }
-       |       interface_entry T_STRING
+               class_entry_type T_STRING extends_from implements_list
+                       { $$.u.op.ptr = CG(doc_comment); CG(doc_comment) = NULL; }      
+               '{' class_statement_list '}'
+                       { $$.u.ast = zend_ast_create_decl(ZEND_AST_CLASS, $1.EA, $1.u.op.opline_num,
+                             CG(zend_lineno), LANG_SCNG(yy_text), $5.u.op.ptr,
+                                 Z_STR($2.u.constant), $3.u.ast, $4.u.ast, $7.u.ast); AS($$); }
+       /*|     interface_entry T_STRING
                        { zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
                        interface_extends_list
                        '{'
                                class_statement_list
-                       '}' { zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); }
+                       '}' { AS($6); zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); }*/
 ;
 
 
@@ -432,27 +432,22 @@ class_entry_type:
 ;
 
 extends_from:
-               /* empty */                                     { $$.op_type = IS_UNUSED; }
-       |       T_EXTENDS fully_qualified_class_name    { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); }
+               /* empty */             { $$.u.ast = NULL; }
+       |       T_EXTENDS name  { $$.u.ast = $2.u.ast; }
 ;
 
 interface_entry:
        T_INTERFACE             { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; }
 ;
 
-interface_extends_list:
-               /* empty */
+/*interface_extends_list:
+               /* empty /
        |       T_EXTENDS interface_list
-;
+;*/
 
 implements_list:
-               /* empty */
-       |       T_IMPLEMENTS interface_list
-;
-
-interface_list:
-               fully_qualified_class_name                      { zend_do_implements_interface(&$1 TSRMLS_CC); }
-       |       interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); }
+               /* empty */                             { $$.u.ast = NULL; }
+       |       T_IMPLEMENTS name_list  { $$.u.ast = $2.u.ast; }
 ;
 
 foreach_variable:
@@ -621,23 +616,24 @@ static_var:
 
 class_statement_list:
                class_statement_list class_statement
+                       { $$.u.ast = zend_ast_dynamic_add($1.u.ast, $2.u.ast); }
        |       /* empty */
+                       { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_STMT_LIST); }
 ;
 
 
 class_statement:
                variable_modifiers property_list ';'
-                       { $$.u.ast = $2.u.ast; $$.u.ast->attr = Z_LVAL($1.u.constant); AS($$); }
+                       { $$.u.ast = $2.u.ast; $$.u.ast->attr = Z_LVAL($1.u.constant); }
        |       class_const_list ';'
                        { $$.u.ast = $1.u.ast;
-                         if (CG(doc_comment)) { STR_RELEASE(CG(doc_comment)); CG(doc_comment) = NULL; }
-                         AS($$); }
+                         if (CG(doc_comment)) { STR_RELEASE(CG(doc_comment)); CG(doc_comment) = NULL; } }
        |       T_USE name_list trait_adaptations
-                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_TRAIT, $2.u.ast, $3.u.ast); AS($$); }
+                       { $$.u.ast = zend_ast_create_binary(ZEND_AST_USE_TRAIT, $2.u.ast, $3.u.ast); }
        |       method_modifiers function returns_ref T_STRING '(' parameter_list ')' method_body
                        { $$.u.ast = zend_ast_create_decl(ZEND_AST_METHOD, $3.EA | Z_LVAL($1.u.constant),
                              $2.EA, CG(zend_lineno), LANG_SCNG(yy_text), $2.u.op.ptr,
-                                 Z_STR($4.u.constant), $6.u.ast, NULL, $8.u.ast); AS($$); }
+                                 Z_STR($4.u.constant), $6.u.ast, NULL, $8.u.ast); }
 ;
 
 name_list: