mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* compile.c (iseq_compile_each): add break catch point.
* insns.def (throw): support correct "break" and "return". this commit achieve that "make test" passes all tests. * vm.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12703 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a74dbca686
commit
0bb4c2b3db
4 changed files with 125 additions and 51 deletions
|
@ -1,3 +1,12 @@
|
|||
Thu Jul 5 18:42:01 2007 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* compile.c (iseq_compile_each): add break catch point.
|
||||
|
||||
* insns.def (throw): support correct "break" and "return".
|
||||
this commit achieve that "make test" passes all tests.
|
||||
|
||||
* vm.c: ditto.
|
||||
|
||||
Thu Jul 5 18:44:12 2007 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* parse.y (mlhs_basic): use mlhs_post after tSTAR.
|
||||
|
|
51
compile.c
51
compile.c
|
@ -2839,38 +2839,41 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
}
|
||||
case NODE_ITER:
|
||||
case NODE_FOR:{
|
||||
VALUE prevblock = iseq->compile_data->current_block;
|
||||
LABEL *retry_label = NEW_LABEL(nd_line(node));
|
||||
LABEL *retry_end_l = NEW_LABEL(nd_line(node));
|
||||
ID mid = 0;
|
||||
VALUE prevblock = iseq->compile_data->current_block;
|
||||
LABEL *retry_label = NEW_LABEL(nd_line(node));
|
||||
LABEL *retry_end_l = NEW_LABEL(nd_line(node));
|
||||
ID mid = 0;
|
||||
|
||||
ADD_LABEL(ret, retry_label);
|
||||
if (nd_type(node) == NODE_FOR) {
|
||||
COMPILE(ret, "iter caller (for)", node->nd_iter);
|
||||
ADD_LABEL(ret, retry_label);
|
||||
if (nd_type(node) == NODE_FOR) {
|
||||
COMPILE(ret, "iter caller (for)", node->nd_iter);
|
||||
|
||||
iseq->compile_data->current_block =
|
||||
iseq->compile_data->current_block =
|
||||
NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
|
||||
ISEQ_TYPE_BLOCK);
|
||||
|
||||
mid = idEach;
|
||||
ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
|
||||
iseq->compile_data->current_block, INT2FIX(0));
|
||||
if (poped) {
|
||||
ADD_INSN(ret, nd_line(node), pop);
|
||||
}
|
||||
}
|
||||
else {
|
||||
iseq->compile_data->current_block =
|
||||
mid = idEach;
|
||||
ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
|
||||
iseq->compile_data->current_block, INT2FIX(0));
|
||||
}
|
||||
else {
|
||||
iseq->compile_data->current_block =
|
||||
NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
|
||||
ISEQ_TYPE_BLOCK);
|
||||
COMPILE_(ret, "iter caller", node->nd_iter, poped);
|
||||
}
|
||||
ADD_LABEL(ret, retry_end_l);
|
||||
iseq->compile_data->current_block = prevblock;
|
||||
COMPILE(ret, "iter caller", node->nd_iter);
|
||||
}
|
||||
ADD_LABEL(ret, retry_end_l);
|
||||
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, retry_label, retry_end_l, 0,
|
||||
retry_label);
|
||||
break;
|
||||
if (poped) {
|
||||
ADD_INSN(ret, nd_line(node), pop);
|
||||
}
|
||||
|
||||
iseq->compile_data->current_block = prevblock;
|
||||
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, retry_label, retry_end_l, 0, retry_label);
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
|
||||
|
||||
break;
|
||||
}
|
||||
case NODE_BREAK:{
|
||||
unsigned long level = 0;
|
||||
|
|
94
insns.def
94
insns.def
|
@ -1386,7 +1386,70 @@ throw
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (state == TAG_BREAK || state == TAG_RETRY) {
|
||||
if (state == TAG_BREAK) {
|
||||
rb_control_frame_t *cfp = GET_CFP();
|
||||
VALUE *dfp = GET_DFP();
|
||||
int is_orphan = 1;
|
||||
rb_iseq_t *base_iseq = GET_ISEQ();
|
||||
|
||||
INSN_LABEL(search_parent):
|
||||
if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
|
||||
dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
|
||||
base_iseq = base_iseq->parent_iseq;
|
||||
|
||||
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
||||
if (cfp->dfp == dfp) {
|
||||
goto INSN_LABEL(search_parent);
|
||||
}
|
||||
cfp++;
|
||||
}
|
||||
rb_bug("VM (throw): can't find break base.");
|
||||
}
|
||||
|
||||
if (cfp->magic == FRAME_MAGIC_LAMBDA) {
|
||||
/* lambda{... break ...} */
|
||||
is_orphan = 0;
|
||||
pt = dfp;
|
||||
}
|
||||
else {
|
||||
dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
|
||||
|
||||
while ((VALUE *)cfp < th->stack + th->stack_size) {
|
||||
if (cfp->dfp == dfp) {
|
||||
VALUE epc = epc = cfp->pc - cfp->iseq->iseq_encoded;
|
||||
rb_iseq_t *iseq = cfp->iseq;
|
||||
int i;
|
||||
|
||||
for (i=0; i<iseq->catch_table_size; i++) {
|
||||
struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
|
||||
|
||||
if (entry->type == CATCH_TYPE_BREAK &&
|
||||
entry->start < epc && entry->end >= epc) {
|
||||
if (entry->cont == epc) {
|
||||
goto INSN_LABEL(found);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
INSN_LABEL(found):
|
||||
|
||||
pt = dfp;
|
||||
is_orphan = 0;
|
||||
break;
|
||||
}
|
||||
cfp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_orphan) {
|
||||
vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
|
||||
}
|
||||
}
|
||||
else if (state == TAG_RETRY) {
|
||||
pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP());
|
||||
for (i = 0; i < level; i++) {
|
||||
pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
|
||||
|
@ -1394,31 +1457,32 @@ throw
|
|||
}
|
||||
else if (state == TAG_RETURN) {
|
||||
rb_control_frame_t *cfp = GET_CFP();
|
||||
int is_orphan = 1;
|
||||
VALUE *dfp = GET_DFP();
|
||||
int is_orphan = 1;
|
||||
|
||||
/* check orphan */
|
||||
/**
|
||||
* check orphan:
|
||||
*/
|
||||
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
||||
if (GET_LFP() == cfp->lfp) {
|
||||
is_orphan = 0;
|
||||
break;
|
||||
}
|
||||
else if (dfp == cfp->dfp) {
|
||||
/* return from lambda{} */
|
||||
if (GET_DFP() == dfp) {
|
||||
if (cfp->magic == FRAME_MAGIC_LAMBDA) {
|
||||
/* in lambda */
|
||||
is_orphan = 0;
|
||||
break;
|
||||
}
|
||||
dfp = GC_GUARDED_PTR_REF(*cfp->dfp);
|
||||
}
|
||||
cfp++;
|
||||
}
|
||||
if (is_orphan) {
|
||||
vm_localjump_error("unexpected return", throwobj,
|
||||
TAG_RETURN);
|
||||
if (GET_LFP() == cfp->lfp &&
|
||||
cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
||||
is_orphan = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_orphan) {
|
||||
vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
|
||||
}
|
||||
|
||||
/* set current lfp */
|
||||
pt = GET_LFP();
|
||||
}
|
||||
else {
|
||||
|
|
20
vm.c
20
vm.c
|
@ -606,12 +606,15 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc,
|
|||
TH_PUSH_TAG(th);
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
th->safe_level = proc->safe_level;
|
||||
|
||||
val = invoke_block(th, &proc->block, self, argc, argv);
|
||||
}
|
||||
else {
|
||||
if (state == TAG_BREAK ||
|
||||
(state == TAG_RETURN && proc->is_lambda)) {
|
||||
TH_POP_TAG();
|
||||
|
||||
th->safe_level = stored_safe;
|
||||
lfp_set_special_cref(proc->block.lfp, (NODE*)stored_special_cref_stack);
|
||||
|
||||
if (state) {
|
||||
if (state == TAG_RETURN && proc->is_lambda) {
|
||||
VALUE err = th->errinfo;
|
||||
VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
|
||||
VALUE *cdfp = proc->block.dfp;
|
||||
|
@ -624,10 +627,6 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc,
|
|||
}
|
||||
}
|
||||
}
|
||||
TH_POP_TAG();
|
||||
|
||||
th->safe_level = stored_safe;
|
||||
lfp_set_special_cref(proc->block.lfp, (NODE*)stored_special_cref_stack);
|
||||
|
||||
if (state) {
|
||||
JUMP_TAG(state);
|
||||
|
@ -873,9 +872,8 @@ vm_get_cbase(rb_thread_t *th)
|
|||
static VALUE
|
||||
make_localjump_error(const char *mesg, VALUE value, int reason)
|
||||
{
|
||||
VALUE exc =
|
||||
rb_exc_new2(rb_const_get(rb_cObject, rb_intern("LocalJumpError")),
|
||||
mesg);
|
||||
extern VALUE rb_eLocalJumpError;
|
||||
VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
|
||||
ID id;
|
||||
|
||||
switch (reason) {
|
||||
|
|
Loading…
Reference in a new issue