]> granicus.if.org Git - php/commitdiff
Port return statement
authorNikita Popov <nikic@php.net>
Mon, 7 Jul 2014 19:06:02 +0000 (21:06 +0200)
committerNikita Popov <nikic@php.net>
Mon, 7 Jul 2014 19:06:02 +0000 (21:06 +0200)
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_language_parser.y

index 2d12ed26bdb76beb4bcb3cb79a3f8c8c3647dfff..b3d696986763c81552119629e8108a743cd7a214 100644 (file)
@@ -37,17 +37,25 @@ enum _zend_ast_kind {
        ZEND_AST_CALL,
        ZEND_AST_METHOD_CALL,
        ZEND_AST_STATIC_CALL,
+       ZEND_AST_PARAMS,
+       ZEND_AST_UNPACK,
+
+       ZEND_AST_CONST,
+       ZEND_AST_CLASS_CONST,
+       ZEND_AST_RESOLVE_CLASS_NAME,
 
        ZEND_AST_ASSIGN,
        ZEND_AST_ASSIGN_REF,
+       ZEND_AST_ASSIGN_OP,
        ZEND_AST_LIST,
-       ZEND_AST_GLOBAL,
-       ZEND_AST_UNSET,
 
-       ZEND_AST_PARAMS,
-       ZEND_AST_UNPACK,
-
-       ZEND_AST_ASSIGN_OP,
+       ZEND_AST_UNARY_PLUS,
+       ZEND_AST_UNARY_MINUS,
+       ZEND_AST_CAST,
+       ZEND_AST_EMPTY,
+       ZEND_AST_ISSET,
+       ZEND_AST_SILENCE,
+       ZEND_AST_SHELL_EXEC,
 
        ZEND_AST_BINARY_OP,
        ZEND_AST_GREATER,
@@ -55,25 +63,15 @@ enum _zend_ast_kind {
        ZEND_AST_AND,
        ZEND_AST_OR,
 
-       ZEND_AST_UNARY_PLUS,
-       ZEND_AST_UNARY_MINUS,
-       ZEND_AST_CAST,
-
        ZEND_AST_CONDITIONAL,
 
-       ZEND_AST_EMPTY,
-       ZEND_AST_ISSET,
-
-       ZEND_AST_SILENCE,
-       ZEND_AST_SHELL_EXEC,
        ZEND_AST_ARRAY,
        ZEND_AST_ARRAY_ELEM,
-
-       ZEND_AST_CONST,
-       ZEND_AST_CLASS_CONST,
-       ZEND_AST_RESOLVE_CLASS_NAME,
-
        ZEND_AST_ENCAPS_LIST,
+
+       ZEND_AST_GLOBAL,
+       ZEND_AST_UNSET,
+       ZEND_AST_RETURN,
 };
 
 typedef unsigned short zend_ast_kind;
@@ -167,6 +165,7 @@ static inline zend_ast *zend_ast_create_assign_op(zend_uint opcode, zend_ast *op
 #define AST_ZVAL(znode) zend_ast_create_zval(&(znode)->u.constant)
 
 #define AC(znode) AST_COMPILE(&znode, znode.u.ast)
+#define AS(znode) AST_COMPILE_STMT(znode.u.ast)
 #define AZ(znode) ((znode).u.ast = AST_ZNODE(&znode))
 
 #endif
index c407a744f843b0a96d85f3da17e41f9a9c0ba5d7..e64ba51320e995d724d0a6d7bec842c8c46f0311 100644 (file)
@@ -6886,7 +6886,6 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) {
        zend_ast *var_ast = ast->child[0];
 
        znode var_node, result;
-       zend_op *opline;
 
        zend_compile_expr(&var_node, var_ast TSRMLS_CC);
        if (var_node.op_type == IS_CONST) {
@@ -6895,7 +6894,7 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) {
                }
        }
 
-       opline = emit_op(&result, ZEND_FETCH_W, &var_node, NULL TSRMLS_CC);
+       emit_op(&result, ZEND_FETCH_W, &var_node, NULL TSRMLS_CC);
 
        // TODO.AST Avoid double fetch
        //opline->extended_value = ZEND_FETCH_GLOBAL_LOCK;
@@ -6936,6 +6935,58 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) {
        }
 }
 
+static void zend_free_foreach_and_switch_variables(TSRMLS_D) {
+       zend_uint opnum_start, opnum_end, i;
+
+       opnum_start = get_next_op_number(CG(active_op_array));
+
+#ifdef ZTS
+       zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC);
+       zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC);
+#else
+       zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr);
+       zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
+#endif
+
+       opnum_end = get_next_op_number(CG(active_op_array));
+
+       for (i = opnum_start; i < opnum_end; ++i) {
+               CG(active_op_array)->opcodes[i].extended_value |= EXT_TYPE_FREE_ON_RETURN;
+       }
+}
+
+void zend_compile_return(zend_ast *ast TSRMLS_DC) {
+       zend_ast *expr_ast = ast->child[0];
+       zend_bool by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+
+       znode expr_node;
+       zend_op *opline;
+
+       if (!expr_ast) {
+               expr_node.op_type = IS_CONST;
+               ZVAL_NULL(&expr_node.u.constant);
+       } else if (by_ref && zend_is_variable(expr_ast) && !zend_is_call(expr_ast)) {
+               zend_compile_var(&expr_node, expr_ast, BP_VAR_REF TSRMLS_CC);
+       } else {
+               zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+       }
+
+       zend_free_foreach_and_switch_variables(TSRMLS_C);
+
+       if (CG(context).in_finally) {
+               emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL TSRMLS_CC);
+       }
+
+       opline = emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN, &expr_node, NULL TSRMLS_CC);
+       if (expr_ast) {
+               if (zend_is_call(expr_ast)) {
+                       opline->extended_value = ZEND_RETURNS_FUNCTION;
+               } else if (!zend_is_variable(expr_ast)) {
+                       opline->extended_value = ZEND_RETURNS_VALUE;
+               }
+       }
+}
+
 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];
@@ -7688,6 +7739,9 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
                case ZEND_AST_UNSET:
                        zend_compile_unset(ast TSRMLS_CC);
                        return;
+               case ZEND_AST_RETURN:
+                       zend_compile_return(ast TSRMLS_CC);
+                       return;
                EMPTY_SWITCH_DEFAULT_CASE()
        }
 }
index 2580c585bcf73661143aef0227a75a8efacf67c6..1ed1510136a1ec53734336e8b2a1fd67f678200c 100644 (file)
@@ -341,9 +341,10 @@ unticked_statement:
        |       T_BREAK expr ';'                { AC($2); zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); }
        |       T_CONTINUE ';'                  { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); }
        |       T_CONTINUE expr ';'             { AC($2); zend_do_brk_cont(ZEND_CONT, &$2 TSRMLS_CC); }
-       |       T_RETURN ';'                                            { zend_do_return(NULL, 0 TSRMLS_CC); }
-       |       T_RETURN expr_without_variable ';'      { AC($2); zend_do_return(&$2, 0 TSRMLS_CC); }
-       |       T_RETURN variable ';'                           { zend_do_return(&$2, 1 TSRMLS_CC); }
+       |       T_RETURN ';'
+                       { $$.u.ast = zend_ast_create_unary(ZEND_AST_RETURN, NULL); AS($$); }
+       |       T_RETURN expr ';'
+                       { $$.u.ast = zend_ast_create_unary(ZEND_AST_RETURN, $2.u.ast); AS($$); }
        |       T_GLOBAL global_var_list ';'
        |       T_STATIC static_var_list ';'
        |       T_ECHO echo_expr_list ';'