Reputation: 1039
Compare the following scenarios (they are the same, but the outcome is different):
First I'll do it on ruby (cruby)
~> irb
irb(main):001:0> begin
irb(main):002:1* begin
irb(main):003:2* puts 1
irb(main):004:2> next
irb(main):005:2> end
irb(main):006:1> puts 2
irb(main):007:1> end
SyntaxError: (irb):4: Can't escape from eval with next
Now same thing on jruby:
~> jirb
irb(main):001:0> begin
irb(main):002:1* begin
irb(main):003:2* puts 1
irb(main):004:2> next
irb(main):005:2> end
irb(main):006:1> puts 2
irb(main):007:1> end
1
=> nil
Why doesn't this fail on jruby like it does on cruby? Is this a jruby bug?
Upvotes: 4
Views: 193
Reputation: 1426
Around the Ruby 1.9 timeframe, MRI started to detect some of these illegal jump cases at parse time rather than raising LocalJumpError. JRuby, MRuby, and Rubinius likely still leave the jump in place and let it fail later on when invoked rather than raising a Syntax error right away.
It might be worth filing a bug with JRuby. Our parser is basically a port of MRIs so we should be able to raise the same error. Barring that, we can perform this analysis at compile time and raise the error then.
Upvotes: 1
Reputation: 369468
I filed this as Bug #13064.
I tested your code in a variety of versions of YARV, as well as on the latest versions of JRuby, MRuby, and Rubinius:
YARV 2.2.0 (the build shipping with macOS)
# ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end'
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]
-e:1: warning: statement not reached
-e:1: Invalid next
-e: compile error (SyntaxError)
# irb -f -d -w -W
irb(main):001:0> p RUBY_VERSION
"2.0.0"
=> "2.0.0"
irb(main):002:0> p RUBY_ENGINE
"ruby"
=> "ruby"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
(irb):9: warning: statement not reached
Exception `SyntaxError' at /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86 - (irb):7: Can't escape from eval with next
Exception `SyntaxError' at /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86 - (irb):7: Can't escape from eval with next
SyntaxError: (irb):7: Can't escape from eval with next
from (irb)
irb(main):011:0>
irb(main):012:0* exit
YARV 2.3.1 (the version JRuby claims to be compatible with at the moment)
# ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end'
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]
-e:1: warning: statement not reached
-e: -e:1: Invalid next (SyntaxError)
# irb -f -d -w -W
irb(main):001:0> p RUBY_VERSION
"2.3.1"
=> "2.3.1"
irb(main):002:0> p RUBY_ENGINE
"ruby"
=> "ruby"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
(irb):9: warning: statement not reached
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
SyntaxError: (irb):7: Can't escape from eval with next
from (irb)
irb(main):011:0>
irb(main):012:0* exit
YARV 2.3.3
# ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end'
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]
-e:1: warning: statement not reached
-e: -e:1: Invalid next (SyntaxError)
# irb -f -d -w -W
irb(main):001:0> p RUBY_VERSION
"2.3.3"
=> "2.3.3"
irb(main):002:0> p RUBY_ENGINE
"ruby"
=> "ruby"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
(irb):9: warning: statement not reached
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.3/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.3/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.3/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
SyntaxError: (irb):7: Can't escape from eval with next
from (irb)
irb(main):011:0>
irb(main):012:0* exit
YARV 2.4.0-preview3:
# ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end'
ruby 2.4.0preview3 (2016-11-07 trunk 56661) [x86_64-darwin16]
-e:1: warning: statement not reached
-e: -e:1: Invalid next (SyntaxError)
# irb -f -d -w -W
irb(main):001:0> p RUBY_VERSION
"2.4.0"
=> "2.4.0"
irb(main):002:0> p RUBY_ENGINE
"ruby"
=> "ruby"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
(irb):9: warning: statement not reached
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.4.0-preview3/lib/ruby/2.4.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
SyntaxError: (irb):7: Can't escape from eval with next
from (irb)
irb(main):011:0>
irb(main):012:0* exit
YARV 2.4.0-dev (current SVN trunk as of yesterday):
# ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end'
ruby 2.4.0dev (2016-12-22 trunk 57151) [x86_64-darwin16]
-e:1: warning: statement not reached
-e: -e:1: Invalid next (SyntaxError)
# irb -f -d -w -W
irb(main):001:0> p RUBY_VERSION
"2.4.0"
=> "2.4.0"
irb(main):002:0> p RUBY_ENGINE
"ruby"
=> "ruby"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
(irb):9: warning: statement not reached
Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.4.0-dev/lib/ruby/2.4.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next
SyntaxError: (irb):7: Can't escape from eval with next
from (irb)
irb(main):011:0>
irb(main):012:0* exit
Rubinius 3.69
# rbx -v -W -e 'begin; begin puts 1; next end; puts 2 end'
rubinius 3.69 (2.3.1 a57071c6 2016-11-17 3.8.1) [x86_64-darwin15.6.0]
1
main # Rubinius::Loader at core/loader.rb:860
evals # Rubinius::Loader at core/loader.rb:646
eval # Kernel(Rubinius::Loader) at core/kernel.rb:1130
call_on_instance # Rubinius::BlockEnvironment at core/block_environment.rb:147
{ } in __script__ # Object at -e:1
jump_error . Rubinius at core/rubinius.rb:279
invalid context for 'next' (LocalJumpError)
An exception occurred evaluating command line code
# irb
irb(main):001:0> p RUBY_VERSION
"2.3.1"
=> "2.3.1"
irb(main):002:0> p RUBY_ENGINE
"rbx"
=> "rbx"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
1
LocalJumpError: invalid context for 'next'
from core/rubinius.rb:279:in `jump_error'
from (irb):7
from core/block_environment.rb:147:in `call_on_instance'
from core/kernel.rb:1130:in `eval'
from core/kernel.rb:585:in `loop'
from core/proc.rb:20:in `call'
from core/kernel.rb:1067:in `catch'
from core/throw_catch.rb:8:in `register'
from core/kernel.rb:1066:in `catch'
from core/proc.rb:20:in `call'
from core/kernel.rb:1067:in `catch'
from core/throw_catch.rb:8:in `register'
from core/kernel.rb:1066:in `catch'
from core/code_loader.rb:505:in `load_script'
from core/code_loader.rb:590:in `load_script'
from core/loader.rb:679:in `script'
from core/loader.rb:861:in `main'irb(main):011:0>
irb(main):012:0* exit
JRuby 9.1.6.0 (the latest release)
# jruby -v -W -e 'begin; begin puts 1; next end; puts 2 end'
jruby 9.1.6.0 (2.3.1) 2016-11-09 0150a76 Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64]
1
LocalJumpError: unexpected next
<main> at -e:1
# irb -f -d -w -W
irb(main):001:0> p RUBY_VERSION
"2.3.1"
=> "2.3.1"
irb(main):002:0> p RUBY_ENGINE
"jruby"
=> "jruby"
irb(main):003:0>
irb(main):004:0* begin
irb(main):005:1* begin
irb(main):006:2* puts 1
irb(main):007:2> next
irb(main):008:2> end
irb(main):009:1> puts 2
irb(main):010:1> end
1
=> nil
irb(main):011:0>
irb(main):012:0* exit
MRuby 1.2.0 (the minimal ISO compliant Ruby implementation written by matz himself)
# mruby -v -e 'begin; begin puts 1; next end; puts 2 end'
mruby 1.2.0 (2015-11-17)
00001 NODE_SCOPE:
00001 NODE_BEGIN:
00001 NODE_BEGIN:
00001 NODE_BEGIN:
00001 NODE_CALL:
00001 NODE_SELF
00001 method='puts' (383)
00001 args:
00001 NODE_INT 1 base 10
00001 NODE_NEXT:
00001 NODE_CALL:
00001 NODE_SELF
00001 method='puts' (383)
00001 args:
00001 NODE_INT 2 base 10
irep 0x7fe0e3c1b630 nregs=4 nlocals=1 pools=1 syms=1 reps=0
file: -e
1 000 OP_LOADSELF R1
1 001 OP_LOADI R2 1
1 002 OP_SEND R1 :puts 1
1 003 OP_ERR "unexpected next"
1 004 OP_LOADSELF R1
1 005 OP_LOADI R2 2
1 006 OP_SEND R1 :puts 1
1 007 OP_STOP
1
trace:
[0] -e:1
LocalJumpError: unexpected next
# irb -v
mruby 1.2.0 (2015-11-17)
mirb - Embeddable Interactive Ruby Shell
> p RUBY_VERSION
00001 NODE_SCOPE:
00001 NODE_BEGIN:
00001 NODE_CALL:
00001 NODE_SELF
00001 method='p' (384)
00001 args:
00001 NODE_CONST RUBY_VERSION
irep 0x7fceeac05220 nregs=4 nlocals=1 pools=0 syms=2 reps=0
file: (mirb)
1 000 OP_LOADSELF R1
1 001 OP_GETCONST R2 :RUBY_VERSION
1 002 OP_SEND R1 :p 1
1 003 OP_STOP
"1.9"
=> "1.9"
> p RUBY_ENGINE
00002 NODE_SCOPE:
00002 NODE_BEGIN:
00002 NODE_CALL:
00002 NODE_SELF
00002 method='p' (384)
00002 args:
00002 NODE_CONST RUBY_ENGINE
irep 0x7fceeae05cf0 nregs=4 nlocals=1 pools=0 syms=2 reps=0
file: (mirb)
2 000 OP_LOADSELF R1
2 001 OP_GETCONST R2 :RUBY_ENGINE
2 002 OP_SEND R1 :p 1
2 003 OP_STOP
"mruby"
=> "mruby"
>
00004 NODE_SCOPE:
00004 NODE_BEGIN:
irep 0x7fceeac06a50 nregs=2 nlocals=1 pools=0 syms=0 reps=0
file: (mirb)
4 000 OP_LOADNIL R1
4 001 OP_STOP
=> nil
> begin
00005 NODE_NIL
* begin
00007 NODE_NIL
* puts 1
00009 NODE_NIL
* next
00011 NODE_NIL
* end
00013 NODE_NIL
* puts 2
00015 NODE_NIL
* end
00012 NODE_SCOPE:
00012 NODE_BEGIN:
00012 NODE_BEGIN:
00012 NODE_BEGIN:
00012 NODE_CALL:
00012 NODE_SELF
00012 method='puts' (383)
00012 args:
00012 NODE_INT 1 base 10
00013 NODE_NEXT:
00015 NODE_CALL:
00015 NODE_SELF
00015 method='puts' (383)
00015 args:
00015 NODE_INT 2 base 10
irep 0x7fceeae01130 nregs=4 nlocals=1 pools=1 syms=1 reps=0
file: (mirb)
12 000 OP_LOADSELF R1
12 001 OP_LOADI R2 1
12 002 OP_SEND R1 :puts 1
13 003 OP_ERR "unexpected next"
15 004 OP_LOADSELF R1
15 005 OP_LOADI R2 2
15 006 OP_SEND R1 :puts 1
15 007 OP_STOP
1
LocalJumpError: unexpected next
>
00012 NODE_SCOPE:
00012 NODE_BEGIN:
irep 0x7fceeae078f0 nregs=2 nlocals=1 pools=0 syms=0 reps=0
file: (mirb)
12 000 OP_LOADNIL R1
12 001 OP_STOP
=> nil
> exit
What is most interesting is that MRuby, JRuby and Rubinius actually agree on the behavior, but differ from YARV. Either YARV or all the other ones are wrong. I cannot say which ones, though.
Upvotes: 1