Feature #12543 ยป then_return.patch
compile.c | ||
---|---|---|
ADD_LABEL(ret, end_label);
|
||
}
|
||
static void
|
||
iseq_compile_call(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped, unsigned int flag)
|
||
{
|
||
enum node_type type = nd_type(node);
|
||
int line = (int)nd_line(node);
|
||
/*
|
||
call: obj.method(...)
|
||
fcall: func(...)
|
||
vcall: func
|
||
*/
|
||
DECL_ANCHOR(recv);
|
||
DECL_ANCHOR(args);
|
||
LABEL *lskip = 0;
|
||
ID mid = node->nd_mid;
|
||
VALUE argc;
|
||
struct rb_call_info_kw_arg *keywords = NULL;
|
||
const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
|
||
ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
|
||
INIT_ANCHOR(recv);
|
||
INIT_ANCHOR(args);
|
||
/* receiver */
|
||
if (type == NODE_CALL || type == NODE_QCALL) {
|
||
COMPILE(recv, "recv", node->nd_recv);
|
||
if (type == NODE_QCALL) {
|
||
lskip = NEW_LABEL(line);
|
||
ADD_INSN(recv, line, dup);
|
||
ADD_INSNL(recv, line, branchnil, lskip);
|
||
}
|
||
}
|
||
else if (type == NODE_FCALL || type == NODE_VCALL) {
|
||
ADD_CALL_RECEIVER(recv, line);
|
||
}
|
||
/* args */
|
||
if (nd_type(node) != NODE_VCALL) {
|
||
argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
|
||
}
|
||
else {
|
||
argc = INT2FIX(0);
|
||
}
|
||
ADD_SEQ(ret, recv);
|
||
ADD_SEQ(ret, args);
|
||
debugp_param("call args argc", argc);
|
||
debugp_param("call method", ID2SYM(mid));
|
||
switch (nd_type(node)) {
|
||
case NODE_VCALL:
|
||
flag |= VM_CALL_VCALL;
|
||
/* VCALL is funcall, so fall through */
|
||
case NODE_FCALL:
|
||
flag |= VM_CALL_FCALL;
|
||
}
|
||
ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
|
||
if (lskip) {
|
||
ADD_LABEL(ret, lskip);
|
||
}
|
||
if (poped) {
|
||
ADD_INSN(ret, line, pop);
|
||
}
|
||
}
|
||
/**
|
||
compile each node
|
||
... | ... | |
case NODE_QCALL:
|
||
case NODE_FCALL:
|
||
case NODE_VCALL:{ /* VCALL: variable or call */
|
||
/*
|
||
call: obj.method(...)
|
||
fcall: func(...)
|
||
vcall: func
|
||
*/
|
||
DECL_ANCHOR(recv);
|
||
DECL_ANCHOR(args);
|
||
LABEL *lskip = 0;
|
||
ID mid = node->nd_mid;
|
||
VALUE argc;
|
||
unsigned int flag = 0;
|
||
struct rb_call_info_kw_arg *keywords = NULL;
|
||
const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
|
||
ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
|
||
INIT_ANCHOR(recv);
|
||
INIT_ANCHOR(args);
|
||
#if SUPPORT_JOKE
|
||
if (nd_type(node) == NODE_VCALL) {
|
||
ID id_bitblt;
|
||
ID id_answer;
|
||
CONST_ID(id_bitblt, "bitblt");
|
||
CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
|
||
if (mid == id_bitblt) {
|
||
ADD_INSN(ret, line, bitblt);
|
||
break;
|
||
}
|
||
else if (mid == id_answer) {
|
||
ADD_INSN(ret, line, answer);
|
||
break;
|
||
}
|
||
}
|
||
/* only joke */
|
||
{
|
||
ID goto_id;
|
||
ID label_id;
|
||
CONST_ID(goto_id, "__goto__");
|
||
CONST_ID(label_id, "__label__");
|
||
if (nd_type(node) == NODE_FCALL &&
|
||
(mid == goto_id || mid == label_id)) {
|
||
LABEL *label;
|
||
st_data_t data;
|
||
st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
|
||
ID label_name;
|
||
if (!labels_table) {
|
||
labels_table = st_init_numtable();
|
||
ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
|
||
}
|
||
if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
|
||
SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
|
||
label_name = SYM2ID(node->nd_args->nd_head->nd_lit);
|
||
if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
|
||
label = NEW_LABEL(line);
|
||
label->position = line;
|
||
st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
|
||
}
|
||
else {
|
||
label = (LABEL *)data;
|
||
}
|
||
}
|
||
else {
|
||
COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
|
||
}
|
||
if (mid == goto_id) {
|
||
ADD_INSNL(ret, line, jump, label);
|
||
}
|
||
else {
|
||
ADD_LABEL(ret, label);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
/* receiver */
|
||
if (type == NODE_CALL || type == NODE_QCALL) {
|
||
COMPILE(recv, "recv", node->nd_recv);
|
||
if (type == NODE_QCALL) {
|
||
lskip = NEW_LABEL(line);
|
||
ADD_INSN(recv, line, dup);
|
||
ADD_INSNL(recv, line, branchnil, lskip);
|
||
}
|
||
}
|
||
else if (type == NODE_FCALL || type == NODE_VCALL) {
|
||
ADD_CALL_RECEIVER(recv, line);
|
||
}
|
||
/* args */
|
||
if (nd_type(node) != NODE_VCALL) {
|
||
argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
|
||
}
|
||
else {
|
||
argc = INT2FIX(0);
|
||
}
|
||
ADD_SEQ(ret, recv);
|
||
ADD_SEQ(ret, args);
|
||
debugp_param("call args argc", argc);
|
||
debugp_param("call method", ID2SYM(mid));
|
||
switch (nd_type(node)) {
|
||
case NODE_VCALL:
|
||
flag |= VM_CALL_VCALL;
|
||
/* VCALL is funcall, so fall through */
|
||
case NODE_FCALL:
|
||
flag |= VM_CALL_FCALL;
|
||
}
|
||
ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
|
||
if (lskip) {
|
||
ADD_LABEL(ret, lskip);
|
||
}
|
||
if (poped) {
|
||
ADD_INSN(ret, line, pop);
|
||
}
|
||
iseq_compile_call(iseq, ret, node, poped, 0);
|
||
break;
|
||
}
|
||
case NODE_TAIL:{
|
||
iseq_compile_call(iseq, ret, node->nd_head, poped, VM_CALL_TAILCALL);
|
||
break;
|
||
}
|
||
case NODE_SUPER:
|
defs/keywords | ||
---|---|---|
return, {keyword_return, keyword_return}, EXPR_MID
|
||
self, {keyword_self, keyword_self}, EXPR_END
|
||
super, {keyword_super, keyword_super}, EXPR_ARG
|
||
then, {keyword_then, keyword_then}, EXPR_BEG
|
||
then, {keyword_then, modifier_then}, EXPR_BEG
|
||
true, {keyword_true, keyword_true}, EXPR_END
|
||
undef, {keyword_undef, keyword_undef}, EXPR_FNAME|EXPR_FITEM
|
||
unless, {keyword_unless, modifier_unless}, EXPR_VALUE
|
defs/lex.c.src | ||
---|---|---|
return, {keyword_return, keyword_return}, EXPR_MID
|
||
self, {keyword_self, keyword_self}, EXPR_END
|
||
super, {keyword_super, keyword_super}, EXPR_ARG
|
||
then, {keyword_then, keyword_then}, EXPR_BEG
|
||
then, {keyword_then, modifier_then}, EXPR_BEG
|
||
true, {keyword_true, keyword_true}, EXPR_END
|
||
undef, {keyword_undef, keyword_undef}, EXPR_FNAME|EXPR_FITEM
|
||
unless, {keyword_unless, modifier_unless}, EXPR_VALUE
|
lex.c.blt | ||
---|---|---|
#line 27 "defs/keywords"
|
||
{(int)offsetof(struct stringpool_t, stringpool_str12), {keyword_end, keyword_end}, EXPR_END},
|
||
#line 44 "defs/keywords"
|
||
{(int)offsetof(struct stringpool_t, stringpool_str13), {keyword_then, keyword_then}, EXPR_BEG},
|
||
{(int)offsetof(struct stringpool_t, stringpool_str13), {keyword_then, modifier_then}, EXPR_BEG},
|
||
#line 36 "defs/keywords"
|
||
{(int)offsetof(struct stringpool_t, stringpool_str14), {keyword_not, keyword_not}, EXPR_ARG},
|
||
#line 29 "defs/keywords"
|
node.h | ||
---|---|---|
#define NODE_VCALL NODE_VCALL
|
||
NODE_QCALL,
|
||
#define NODE_QCALL NODE_QCALL
|
||
NODE_TAIL,
|
||
#define NODE_TAIL NODE_TAIL
|
||
NODE_SUPER,
|
||
#define NODE_SUPER NODE_SUPER
|
||
NODE_ZSUPER,
|
||
... | ... | |
#define NEW_CALL(r,m,a) NEW_NODE(NODE_CALL,r,m,a)
|
||
#define NEW_FCALL(m,a) NEW_NODE(NODE_FCALL,0,m,a)
|
||
#define NEW_VCALL(m) NEW_NODE(NODE_VCALL,0,m,0)
|
||
#define NEW_TAIL(m) NEW_NODE(NODE_TAIL,m,0,0)
|
||
#define NEW_SUPER(a) NEW_NODE(NODE_SUPER,0,0,a)
|
||
#define NEW_ZSUPER() NEW_NODE(NODE_ZSUPER,0,0,0)
|
||
#define NEW_ARGS_AUX(r,b) NEW_NODE(NODE_ARGS_AUX,r,b,0)
|
parse.y | ||
---|---|---|
modifier_while
|
||
modifier_until
|
||
modifier_rescue
|
||
modifier_then
|
||
keyword_alias
|
||
keyword_defined
|
||
keyword_BEGIN
|
||
... | ... | |
%nonassoc tLOWEST
|
||
%nonassoc tLBRACE_ARG
|
||
%nonassoc modifier_if modifier_unless modifier_while modifier_until
|
||
%nonassoc modifier_if modifier_unless modifier_while modifier_until modifier_then
|
||
%left keyword_or keyword_and
|
||
%right keyword_not
|
||
%nonassoc keyword_defined
|
||
... | ... | |
$$ = dispatch1(undef, $2);
|
||
%*/
|
||
}
|
||
| expr modifier_then keyword_return
|
||
{
|
||
/*%%%*/
|
||
$$ = NEW_TAIL($1);
|
||
/*%
|
||
$$ = dispatch1(tail, $1);
|
||
%*/
|
||
}
|
||
| stmt modifier_if expr_value
|
||
{
|
||
/*%%%*/
|
||
... | ... | |
/*%c
|
||
{ $$ = Qnil; }
|
||
%*/
|
||
| modifier_then
|
||
| keyword_then
|
||
| term modifier_then
|
||
/*%c%*/
|
||
/*%c
|
||
{ $$ = $2; }
|
||
%*/
|
||
| term keyword_then
|
||
/*%c%*/
|
||
/*%c
|
||
... | ... | |
{modifier_while, "while"},
|
||
{modifier_until, "until"},
|
||
{modifier_rescue, "rescue"},
|
||
{modifier_then, "then"},
|
||
{keyword_alias, "alias"},
|
||
{keyword_defined, "defined?"},
|
||
{keyword_BEGIN, "BEGIN"},
|