diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-08-14 23:55:34 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-08-14 23:55:34 +0000 |
commit | 582b7057dc92fcf23b01a4fb699ebe008fd92240 (patch) | |
tree | e4a47fc630528fe8b4456af7e288be22c10f7885 /compile.c | |
parent | 12693e245ff8ec149dfc73eb25458035e9211637 (diff) | |
download | ruby-582b7057dc92fcf23b01a4fb699ebe008fd92240.tar.gz |
compile.c: compile_break
* compile.c (compile_break): extract from iseq_compile_each.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59593 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 132 |
1 files changed, 70 insertions, 62 deletions
@@ -4362,6 +4362,71 @@ compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped, co return COMPILE_OK; } +static int +compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped) +{ + const int line = nd_line(node); + unsigned long level = 0; + + if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) { + /* while/until */ + LABEL *splabel = NEW_LABEL(0); + ADD_LABEL(ret, splabel); + ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label); + CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts, + ISEQ_COMPILE_DATA(iseq)->loopval_popped)); + add_ensure_iseq(ret, iseq, 0); + ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label); + ADD_ADJUST_RESTORE(ret, splabel); + + if (!popped) { + ADD_INSN(ret, line, putnil); + } + } + else if (iseq->body->type == ISEQ_TYPE_BLOCK) { + break_by_insn: + /* escape from block */ + CHECK(COMPILE(ret, "break val (block)", node->nd_stts)); + ADD_INSN1(ret, line, throw, INT2FIX(level | TAG_BREAK)); + if (popped) { + ADD_INSN(ret, line, pop); + } + } + else if (iseq->body->type == ISEQ_TYPE_EVAL) { + break_in_eval: + COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break"); + return COMPILE_NG; + } + else { + const rb_iseq_t *ip = iseq->body->parent_iseq; + + while (ip) { + if (!ISEQ_COMPILE_DATA(ip)) { + ip = 0; + break; + } + + level++; + if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) { + level = VM_THROW_NO_ESCAPE_FLAG; + goto break_by_insn; + } + else if (ip->body->type == ISEQ_TYPE_BLOCK) { + level <<= VM_THROW_LEVEL_SHIFT; + goto break_by_insn; + } + else if (ip->body->type == ISEQ_TYPE_EVAL) { + goto break_in_eval; + } + + ip = ip->body->parent_iseq; + } + COMPILE_ERROR(ERROR_ARGS "Invalid break"); + return COMPILE_NG; + } + return COMPILE_OK; +} + static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped); /** compile each node @@ -4527,69 +4592,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp break; } - case NODE_BREAK:{ - unsigned long level = 0; - - if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) { - /* while/until */ - LABEL *splabel = NEW_LABEL(0); - ADD_LABEL(ret, splabel); - ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label); - CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts, - ISEQ_COMPILE_DATA(iseq)->loopval_popped)); - add_ensure_iseq(ret, iseq, 0); - ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label); - ADD_ADJUST_RESTORE(ret, splabel); - - if (!popped) { - ADD_INSN(ret, line, putnil); - } - } - else if (iseq->body->type == ISEQ_TYPE_BLOCK) { - break_by_insn: - /* escape from block */ - CHECK(COMPILE(ret, "break val (block)", node->nd_stts)); - ADD_INSN1(ret, line, throw, INT2FIX(level | TAG_BREAK)); - if (popped) { - ADD_INSN(ret, line, pop); - } - } - else if (iseq->body->type == ISEQ_TYPE_EVAL) { - break_in_eval: - COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break"); - ng: - debug_node_end(); - return COMPILE_NG; - } - else { - const rb_iseq_t *ip = iseq->body->parent_iseq; - - while (ip) { - if (!ISEQ_COMPILE_DATA(ip)) { - ip = 0; - break; - } - - level++; - if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) { - level = VM_THROW_NO_ESCAPE_FLAG; - goto break_by_insn; - } - else if (ip->body->type == ISEQ_TYPE_BLOCK) { - level <<= VM_THROW_LEVEL_SHIFT; - goto break_by_insn; - } - else if (ip->body->type == ISEQ_TYPE_EVAL) { - goto break_in_eval; - } - - ip = ip->body->parent_iseq; - } - COMPILE_ERROR(ERROR_ARGS "Invalid break"); - goto ng; - } + case NODE_BREAK: + CHECK(compile_break(iseq, ret, node, popped)); break; - } case NODE_NEXT:{ unsigned long level = 0; @@ -6501,6 +6506,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp } default: UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG); + ng: + debug_node_end(); + return COMPILE_NG; } /* check & remove redundant trace(line) */ |