为什么ruby和jruby的begin-next-end的行为有所不同?

比较以下场景(它们是相同的,但结果是不同的):

首先,我会在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

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

为什么这不会像在cruby上那样在jruby上失败?这是一个犹豫不决的虫子吗?

最佳答案 我把它归档为
Bug #13064.

我在各种版本的YARV以及JRuby,MRuby和Rubinius的最新版本中测试了您的代码:

> YARV 2.2.0(使用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(JRuby声称此版本兼容)

# 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(截至昨天的当前SVN中继):

# 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(最新版本)

# 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(由matz自己编写的最低ISO兼容Ruby实现)

# 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

最有趣的是,MRuby,JRuby和Rubinius实际上都同意这种行为,但与YARV不同. YARV或其他所有都是错的.不过,我不能说出哪些.

点赞