From: Nikita Popov Date: Wed, 9 Jul 2014 21:05:21 +0000 (+0200) Subject: Port break/continue X-Git-Tag: POST_AST_MERGE^2~167 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cc8a6fa91e1bde6fbaf0be397b634405551e9bdc;p=php Port break/continue --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index aefd99bbd3..f198e429ab 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6995,6 +6995,36 @@ void zend_compile_throw(zend_ast *ast TSRMLS_DC) { emit_op(NULL, ZEND_THROW, &expr_node, NULL TSRMLS_CC); } +void zend_compile_break_continue(zend_ast *ast TSRMLS_DC) { + zend_ast *depth_ast = ast->child[0]; + zend_uint opcode = ast->kind; + + znode depth_node; + zend_op *opline; + + ZEND_ASSERT(opcode == ZEND_BRK || opcode == ZEND_CONT); + + if (depth_ast) { + if (depth_ast->kind != ZEND_AST_ZVAL) { + zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-constant operand " + "is no longer supported", opcode == ZEND_BRK ? "break" : "continue"); + } + + zend_compile_expr(&depth_node, depth_ast TSRMLS_CC); + + if (Z_TYPE(depth_node.u.constant) != IS_LONG || Z_LVAL(depth_node.u.constant) < 1) { + zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive numbers", + opcode == ZEND_BRK ? "break" : "continue"); + } + } else { + depth_node.op_type = IS_CONST; + ZVAL_LONG(&depth_node.u.constant, 1); + } + + opline = emit_op(NULL, opcode, NULL, &depth_node TSRMLS_CC); + opline->op1.opline_num = CG(context).current_brk_cont; +} + 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]; @@ -7756,6 +7786,10 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) { case ZEND_THROW: zend_compile_throw(ast TSRMLS_CC); return; + case ZEND_BRK: + case ZEND_CONT: + zend_compile_break_continue(ast TSRMLS_CC); + return; EMPTY_SWITCH_DEFAULT_CASE() } } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1e3153121d..1e15c04b39 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -337,10 +337,10 @@ unticked_statement: ')' { zend_do_free(&$9 TSRMLS_CC); zend_do_for_before_statement(&$4, &$7 TSRMLS_CC); } for_statement { zend_do_for_end(&$7 TSRMLS_CC); } | T_SWITCH parenthesis_expr { AC($2); zend_do_switch_cond(&$2 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$4 TSRMLS_CC); } - | T_BREAK ';' { zend_do_brk_cont(ZEND_BRK, NULL TSRMLS_CC); } - | 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_BREAK ';' { $$.u.ast = zend_ast_create_unary(ZEND_BRK, NULL); AS($$); } + | T_BREAK expr ';' { $$.u.ast = zend_ast_create_unary(ZEND_BRK, $2.u.ast); AS($$); } + | T_CONTINUE ';' { $$.u.ast = zend_ast_create_unary(ZEND_CONT, NULL); AS($$); } + | T_CONTINUE expr ';' { $$.u.ast = zend_ast_create_unary(ZEND_CONT, $2.u.ast); AS($$); } | T_RETURN ';' { $$.u.ast = zend_ast_create_unary(ZEND_AST_RETURN, NULL); AS($$); } | T_RETURN expr ';'