From: Nikita Popov Date: Fri, 18 Jul 2014 10:30:39 +0000 (+0200) Subject: Port closure use X-Git-Tag: POST_AST_MERGE^2~137 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=abfc8bd89417519f875d3cb9a881d339e3b9f6e0;p=php Port closure use --- diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 864503db72..7f885ab029 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -100,6 +100,8 @@ enum _zend_ast_kind { ZEND_AST_TYPE, ZEND_AST_FUNC_DECL, + + ZEND_AST_CLOSURE_USES, }; typedef unsigned short zend_ast_kind; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 145f98981a..7daa618803 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6200,26 +6200,13 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) { efree(fetch_ast); } -void zend_compile_static_var(zend_ast *ast TSRMLS_DC) { - zend_ast *var_ast = ast->child[0]; - zend_ast *value_ast = ast->child[1]; - +static void zend_compile_static_var_common( + zend_ast *var_ast, zval *value, zend_bool by_ref TSRMLS_DC +) { znode var_node, result; - zval value_zv; zend_op *opline; zend_compile_expr(&var_node, var_ast TSRMLS_CC); - if (var_node.op_type == IS_CONST) { - if (Z_TYPE(var_node.u.constant) != IS_STRING) { - convert_to_string(&var_node.u.constant); - } - } - - if (value_ast) { - _tmp_compile_const_expr(&value_zv, value_ast TSRMLS_CC); - } else { - ZVAL_NULL(&value_zv); - } if (!CG(active_op_array)->static_variables) { if (CG(active_op_array)->scope) { @@ -6229,15 +6216,40 @@ void zend_compile_static_var(zend_ast *ast TSRMLS_DC) { zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0); } - zend_hash_update(CG(active_op_array)->static_variables, - Z_STR(var_node.u.constant), &value_zv); + zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value); - opline = emit_op(&result, ZEND_FETCH_W, &var_node, NULL TSRMLS_CC); + opline = emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL TSRMLS_CC); opline->extended_value = ZEND_FETCH_STATIC; - zend_ast *fetch_ast = zend_ast_create_unary(ZEND_AST_VAR, var_ast); - zend_compile_assign_ref_common(NULL, fetch_ast, &result TSRMLS_CC); - efree(fetch_ast); + if (by_ref) { + zend_ast *fetch_ast = zend_ast_create_unary(ZEND_AST_VAR, var_ast); + zend_compile_assign_ref_common(NULL, fetch_ast, &result TSRMLS_CC); + efree(fetch_ast); + } else { + zend_ast *fetch_ast = zend_ast_create_unary(ZEND_AST_VAR, var_ast); + zend_ast *znode_ast = zend_ast_create_znode(&result); + zend_ast *assign_ast = zend_ast_create_binary(ZEND_AST_ASSIGN, fetch_ast, znode_ast); + znode dummy_node; + zend_compile_expr(&dummy_node, assign_ast TSRMLS_CC); + zend_do_free(&dummy_node TSRMLS_CC); + efree(znode_ast); + efree(assign_ast); + efree(fetch_ast); + } +} + +void zend_compile_static_var(zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + zend_ast *value_ast = ast->child[1]; + zval value_zv; + + if (value_ast) { + _tmp_compile_const_expr(&value_zv, value_ast TSRMLS_CC); + } else { + ZVAL_NULL(&value_zv); + } + + zend_compile_static_var_common(var_ast, &value_zv, 1 TSRMLS_CC); } void zend_compile_unset(zend_ast *ast TSRMLS_DC) { @@ -6968,6 +6980,30 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) { op_array->arg_info = arg_infos; } +void zend_compile_closure_uses(zend_ast *ast TSRMLS_DC) { + zend_uint i; + + if (!ast) { + return; + } + + for (i = 0; i < ast->children; ++i) { + zend_ast *var_ast = ast->child[i]; + zend_string *name = Z_STR_P(zend_ast_get_zval(var_ast)); + zend_bool by_ref = var_ast->attr; + zval zv; + + if (name->len == sizeof("this") - 1 && !memcmp(name->val, "this", sizeof("this") - 1)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable"); + } + + ZVAL_NULL(&zv); + Z_CONST_FLAGS(zv) = by_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR; + + zend_compile_static_var_common(var_ast, &zv, by_ref TSRMLS_CC); + } +} + void zend_compile_func_decl(zend_ast *ast TSRMLS_DC) { zend_ast *name_ast = ast->child[0]; zend_ast *params_ast = ast->child[1]; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index f48cd3285a..50263eed8a 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -870,11 +870,11 @@ expr_without_variable: | T_YIELD expr T_DOUBLE_ARROW expr { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $4.u.ast, $2.u.ast); } | function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); } - '(' parameter_list ')' { zend_compile_params($5.u.ast TSRMLS_CC); zend_ast_destroy($5.u.ast); } lexical_vars - '{' inner_statement_list '}' { AS($10); zend_do_end_function_declaration(&$1 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$3); } + '(' parameter_list ')' { zend_compile_params($5.u.ast TSRMLS_CC); zend_ast_destroy($5.u.ast); } lexical_vars { zend_compile_closure_uses($8.u.ast TSRMLS_CC); if ($8.u.ast) zend_ast_destroy($8.u.ast); } + '{' inner_statement_list '}' { AS($11); zend_do_end_function_declaration(&$1 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$3); } | T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); } - '(' parameter_list ')' { zend_compile_params($6.u.ast TSRMLS_CC); zend_ast_destroy($6.u.ast); } lexical_vars - '{' inner_statement_list '}' { AS($11); zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); } + '(' parameter_list ')' { zend_compile_params($6.u.ast TSRMLS_CC); zend_ast_destroy($6.u.ast); } lexical_vars { zend_compile_closure_uses($9.u.ast TSRMLS_CC); if ($9.u.ast) zend_ast_destroy($9.u.ast); } + '{' inner_statement_list '}' { AS($12); zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); } ; function: @@ -882,15 +882,18 @@ function: ; lexical_vars: - /* empty */ - | T_USE '(' lexical_var_list ')' + /* empty */ { $$.u.ast = NULL; } + | T_USE '(' lexical_var_list ')' { $$.u.ast = $3.u.ast; } ; lexical_var_list: - lexical_var_list ',' T_VARIABLE { zend_do_fetch_lexical_variable(&$3, 0 TSRMLS_CC); } - | lexical_var_list ',' '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$4, 1 TSRMLS_CC); } - | T_VARIABLE { zend_do_fetch_lexical_variable(&$1, 0 TSRMLS_CC); } - | '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$2, 1 TSRMLS_CC); } + lexical_var_list ',' lexical_var { $$.u.ast = zend_ast_dynamic_add($1.u.ast, $3.u.ast); } + | lexical_var { $$.u.ast = zend_ast_create_dynamic_and_add(ZEND_AST_CLOSURE_USES, $1.u.ast); } +; + +lexical_var: + T_VARIABLE { $$.u.ast = AST_ZVAL(&$1); } + | '&' T_VARIABLE { $$.u.ast = zend_ast_create_zval_ex(&$2.u.constant, 1); } ; function_call: