]> granicus.if.org Git - php/commitdiff
Port break/continue
authorNikita Popov <nikic@php.net>
Wed, 9 Jul 2014 21:05:21 +0000 (23:05 +0200)
committerNikita Popov <nikic@php.net>
Wed, 9 Jul 2014 21:05:21 +0000 (23:05 +0200)
Zend/zend_compile.c
Zend/zend_language_parser.y

index aefd99bbd345e5eb4d516d7e84b6589265e2aced..f198e429ab120093fd3e53059013981131f69cc6 100644 (file)
@@ -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()
        }
 }
index 1e3153121d9c77857854a90e263560344e717ff6..1e15c04b3911c37069d635982dad65a90bd7d8bf 100644 (file)
@@ -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 ';'