ruby-changes:45059
From: nobu <ko1@a...>
Date: Wed, 21 Dec 2016 10:58:36 +0900 (JST)
Subject: [ruby-changes:45059] nobu:r57132 (trunk): compile.c: toplevel return
nobu 2016-12-21 10:58:32 +0900 (Wed, 21 Dec 2016) New Revision: 57132 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=57132 Log: compile.c: toplevel return * compile.c (iseq_compile_each): stop execution of the current source by toplevel return. [ruby-core:36785] [Feature #4840] Modified files: trunk/NEWS trunk/compile.c trunk/test/ruby/test_syntax.rb Index: NEWS =================================================================== --- NEWS (revision 57131) +++ NEWS (revision 57132) @@ -25,6 +25,8 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L25 * Rescue modifier now applicable to method arguments. [Feature #12686] +* Toplevel return is now allowed. [Feature #4840] + === Core classes updates (outstanding ones only) * Array Index: test/ruby/test_syntax.rb =================================================================== --- test/ruby/test_syntax.rb (revision 57131) +++ test/ruby/test_syntax.rb (revision 57132) @@ -926,6 +926,29 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L926 assert_equal(:ok, result) end + def test_return_toplevel + feature4840 = '[ruby-core:36785] [Feature #4840]' + code = "#{<<~"begin;"}\n#{<<~"end;"}" + begin; + return; raise + begin return; rescue SystemExit; exit false; end + begin return; ensure exit false; end + begin ensure return; end + begin raise; ensure; return; end + begin raise; rescue; return; end + return false; raise + return 1; raise + end; + all_assertions(feature4840) do |a| + code.each_line do |s| + s.chomp! + a.for(s) do + assert_ruby_status([], s, proc {RubyVM::InstructionSequence.compile(s).disasm}) + end + end + end + end + private def not_label(x) @result = x; @not_label ||= nil end Index: compile.c =================================================================== --- compile.c (revision 57131) +++ compile.c (revision 57132) @@ -4635,12 +4635,18 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4635 LABEL *lstart = NEW_LABEL(line); LABEL *lend = NEW_LABEL(line); LABEL *lcont = NEW_LABEL(line); + LINK_ELEMENT *last; + int last_leave = 0; struct ensure_range er; struct iseq_compile_data_ensure_node_stack enl; struct ensure_range *erange; INIT_ANCHOR(ensr); COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr); + last = ensr->last; + last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave); + if (!popped && last_leave) + popped = 1; er.begin = lstart; er.end = lend; @@ -4657,12 +4663,15 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4663 ADD_SEQ(ret, ensr); } ADD_LABEL(ret, lcont); + if (last_leave) ADD_INSN(ret, line, pop); erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange; - while (erange) { - ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, - ensure, lcont); - erange = erange->next; + if (lstart->link.next != &lend->link) { + while (erange) { + ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, + ensure, lcont); + erange = erange->next; + } } ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev; @@ -5463,13 +5472,20 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L5472 rb_iseq_t *is = iseq; if (is) { - if (is->body->type == ISEQ_TYPE_TOP) { - COMPILE_ERROR(ERROR_ARGS "Invalid return"); + enum iseq_type type = is->body->type; + const rb_iseq_t *parent_iseq = is->body->parent_iseq; + enum iseq_type parent_type = parent_iseq ? parent_iseq->body->type : type; + + if (type == ISEQ_TYPE_TOP || type == ISEQ_TYPE_MAIN || + ((type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE) && + (parent_type == ISEQ_TYPE_TOP || parent_type == ISEQ_TYPE_MAIN))) { + ADD_INSN(ret, line, putnil); + ADD_INSN(ret, line, leave); } else { LABEL *splabel = 0; - if (is->body->type == ISEQ_TYPE_METHOD) { + if (type == ISEQ_TYPE_METHOD) { splabel = NEW_LABEL(0); ADD_LABEL(ret, splabel); ADD_ADJUST(ret, line, 0); @@ -5477,7 +5493,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L5493 COMPILE(ret, "return nd_stts (return val)", node->nd_stts); - if (is->body->type == ISEQ_TYPE_METHOD) { + if (type == ISEQ_TYPE_METHOD) { add_ensure_iseq(ret, iseq, 1); ADD_TRACE(ret, line, RUBY_EVENT_RETURN); ADD_INSN(ret, line, leave); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/