Skip to content

Commit

Permalink
Class extension functions
Browse files Browse the repository at this point in the history
  • Loading branch information
rjhdby committed Sep 24, 2018
1 parent 7eb255e commit a54d7d3
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 6 deletions.
5 changes: 5 additions & 0 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,9 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
compiler_globals->static_members_table = NULL;
}
compiler_globals->script_encoding_list = NULL;

compiler_globals->class_extension_functions = (HashTable *) malloc(sizeof(HashTable));
zend_hash_init_ex(compiler_globals->class_extension_functions, 8, NULL, NULL, 1, 1);
}
/* }}} */

Expand All @@ -661,6 +664,8 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
pefree((char*)compiler_globals->script_encoding_list, 1);
}
compiler_globals->last_static_member = 0;

zend_hash_destroy(compiler_globals->class_extension_functions);
}
/* }}} */

Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@ static ZEND_COLD void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int in
case ZEND_AST_FOREACH:
case ZEND_AST_FUNC_DECL:
case ZEND_AST_METHOD:
case ZEND_AST_METHOD_EX:
case ZEND_AST_CLASS:
case ZEND_AST_USE_TRAIT:
case ZEND_AST_NAMESPACE:
Expand Down Expand Up @@ -1315,6 +1316,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_AST_FUNC_DECL:
case ZEND_AST_CLOSURE:
case ZEND_AST_METHOD:
case ZEND_AST_METHOD_EX:
decl = (zend_ast_decl *) ast;
if (decl->flags & ZEND_ACC_PUBLIC) {
smart_str_appends(str, "public ");
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ enum _zend_ast_kind {
ZEND_AST_FUNC_DECL,
ZEND_AST_CLOSURE,
ZEND_AST_METHOD,
ZEND_AST_METHOD_EX,
ZEND_AST_CLASS,

/* list nodes */
Expand Down
39 changes: 34 additions & 5 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,7 @@ static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
{
return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL
|| ast->kind == ZEND_AST_PROP_DECL || ast->kind == ZEND_AST_CLASS_CONST_DECL
|| ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD;
|| ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD || ast->kind == ZEND_AST_METHOD_EX;
}
/* }}} */

Expand Down Expand Up @@ -5634,9 +5634,8 @@ void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
}
/* }}} */

void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
void zend_begin_method_decl_ex(zend_class_entry *ce, zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
{
zend_class_entry *ce = CG(active_class_entry);
zend_bool in_interface = (ce->ce_flags & ZEND_ACC_INTERFACE) != 0;
zend_bool in_trait = (ce->ce_flags & ZEND_ACC_TRAIT) != 0;
zend_bool is_public = (op_array->fn_flags & ZEND_ACC_PUBLIC) != 0;
Expand Down Expand Up @@ -5677,7 +5676,11 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo

if (zend_hash_add_ptr(&ce->function_table, lcname, op_array) == NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::%s()",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
ZSTR_VAL(ce->name), ZSTR_VAL(name));
}

if (ce->type == ZEND_INTERNAL_CLASS) {
zend_hash_add_ptr(CG(class_extension_functions), lcname, ce);
}

if (in_interface) {
Expand Down Expand Up @@ -5810,6 +5813,20 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
}
/* }}} */

void zend_begin_method_decl_ex2(zend_string *class_name, zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
{
zend_class_entry *ce = zend_lookup_class(class_name);
zend_begin_method_decl_ex(ce, op_array, name, has_body);
}
/* }}} */

void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
{
zend_class_entry *ce = CG(active_class_entry);
zend_begin_method_decl_ex(ce, op_array, name, has_body);
}
/* }}} */

static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, zend_bool toplevel) /* {{{ */
{
zend_ast *params_ast = decl->child[0];
Expand Down Expand Up @@ -5876,10 +5893,17 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
{
zend_ast_decl *decl = (zend_ast_decl *) ast;
zend_ast *params_ast = decl->child[0];
zend_ast *uses_ast = decl->child[1];
zend_ast *uses_ast;
zend_ast *stmt_ast = decl->child[2];
zend_ast *return_type_ast = decl->child[3];
zend_bool is_method = decl->kind == ZEND_AST_METHOD;
zend_bool is_ex_method = decl->kind == ZEND_AST_METHOD_EX;

if(is_ex_method){
uses_ast = NULL;
} else {
uses_ast = decl->child[1];
}

zend_op_array *orig_op_array = CG(active_op_array);
zend_op_array *op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
Expand All @@ -5901,6 +5925,10 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
if (is_method) {
zend_bool has_body = stmt_ast != NULL;
zend_begin_method_decl(op_array, decl->name, has_body);
} else if (is_ex_method){
zend_bool has_body = stmt_ast != NULL;
zend_string * class_name = zend_ast_get_str(decl->child[1]);
zend_begin_method_decl_ex2(class_name, op_array, decl->name, has_body);
} else {
zend_begin_func_decl(result, op_array, decl, toplevel);
if (uses_ast) {
Expand Down Expand Up @@ -8122,6 +8150,7 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */
break;
case ZEND_AST_FUNC_DECL:
case ZEND_AST_METHOD:
case ZEND_AST_METHOD_EX:
zend_compile_func_decl(NULL, ast, 0);
break;
case ZEND_AST_PROP_DECL:
Expand Down
7 changes: 7 additions & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ void shutdown_executor(void) /* {{{ */
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
} zend_end_try();

zend_class_entry *temp_ce;

ZEND_HASH_FOREACH_STR_KEY_PTR(CG(class_extension_functions), key, temp_ce) {
zend_hash_del(&temp_ce->function_table, key);
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END();

if (fast_shutdown) {
/* Fast Request Shutdown
* =====================
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct _zend_compiler_globals {
zval **static_members_table;
int last_static_member;
#endif
HashTable * class_extension_functions;
};


Expand Down
10 changes: 9 additions & 1 deletion Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
/* Token used to force a parse error from the lexer */
%token T_ERROR

%type <ast> top_statement namespace_name name statement function_declaration_statement
%type <ast> top_statement namespace_name name statement function_declaration_statement class_extension_function_declaration_statement
%type <ast> class_declaration_statement trait_declaration_statement
%type <ast> interface_declaration_statement interface_extends_list
%type <ast> group_use_declaration inline_use_declarations inline_use_declaration
Expand Down Expand Up @@ -308,6 +308,7 @@ name:
top_statement:
statement { $$ = $1; }
| function_declaration_statement { $$ = $1; }
| class_extension_function_declaration_statement { $$ = $1; }
| class_declaration_statement { $$ = $1; }
| trait_declaration_statement { $$ = $1; }
| interface_declaration_statement { $$ = $1; }
Expand Down Expand Up @@ -489,6 +490,13 @@ function_declaration_statement:
zend_ast_get_str($3), $6, NULL, $11, $8); CG(extra_fn_flags) = $9; }
;

class_extension_function_declaration_statement:
function returns_ref namespace_name T_OBJECT_OPERATOR T_STRING backup_doc_comment '(' parameter_list ')'
return_type backup_fn_flags method_body backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD_EX, $2 | ZEND_ACC_PUBLIC | $13, $1, $6,
zend_ast_get_str($5), $8, $3, $12, $10); CG(extra_fn_flags) = $11; }
;

is_reference:
/* empty */ { $$ = 0; }
| '&' { $$ = ZEND_PARAM_REF; }
Expand Down

0 comments on commit a54d7d3

Please sign in to comment.