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) {
}
}
- 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;
}
}
+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];
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()
}
}
| 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 ';'