MRI 1.8.6的irb里一个小诡异的地方(以为是IronRuby rev183的bug)

元旦前后有好长时间DLR相关的项目都没更新过source drop了。直到这两天IronRuby才从rev181更新到rev183(rubyforge上的SVN仓库的版本号)。
这个revision给了我一个小小的惊喜:ir.exe(IronRuby的console)终于在交互模式支持在全局作用域里用局部变量了。之前拿IronRuby的交互式解释器来玩的时候,方法外的变量全得用$符号修饰成全局变量,总觉得别扭。现在总算好了~指望着什么时候能在IronRuby上直接用irb...

不过今天玩的时候因为手误却发现了一个奇怪的现象。在交互式解释器里玩,写了插入运算符("<<")之后忘了写空格就写了后面的数字,然后按了回车。

先用Ruby 1.8.6 p287来实验:
E:\ironruby\build\debug>irb
irb(main):001:0> a, b = [], 'xyz'
=> []
irb(main):002:0> a <<2 <<3
irb(main):003:0" puts b.succ
irb(main):004:0" 2
xza
=> 2
irb(main):005:0> a
=> [2, 3]

Ruby 1.8.6的irb貌似是把<<2看成heredoc的起始标志了,但是行为却又不像heredoc返回字符串,而是执行了<<2到2之间的代码。不仅如此,<<2和<<3还把2和3插入到a里去了……
拜托有知道这是什么现象的人解释一下……我给弄糊涂了。
顺带一提JRuby 1.1.5的jirb的行为跟Ruby 1.8.6的irb是一样的。

然后用IronRuby rev183来测试这个现象:
E:\ironruby\build\debug>ir
IronRuby 1.0.0.0 on .NET 2.0.50727.3053
Copyright (c) Microsoft Corporation. All rights reserved.

>>> a = []
=> []
>>> a <<2 <<3
=> [2, 3]

可以看到IronRuby的ir.exe认为这就是普通的连续两个插入操作。怪哉怪哉……
(然而测试了一番之后,这个行为就Ruby语言来说却是对的。只是交互式解释器ir.exe与MRI的irb的行为不同而已。看下面)

然后回头来用JRuby看看它是如何理解这样的代码的。打开JRuby 1.1.5的jirb:
irb(main):001:0> src = <<SRCEND
irb(main):002:0" a = []
irb(main):003:0" b = 'xyz'
irb(main):004:0" a <<2 <<3
irb(main):005:0" puts b.succ
irb(main):006:0" 2
irb(main):007:0" a
irb(main):008:0" SRCEND
=> "a = []\nb = 'xyz'\na <<2 <<3\nputs b.succ\n2\na\n"
irb(main):009:0> ast = JRuby.parse src
=> RootNode
  BlockNode
    NewlineNode
      LocalAsgnNode |a| &0 >0
        ZArrayNode
    NewlineNode
      LocalAsgnNode |b| &1 >0
        StrNode =="xyz"
    NewlineNode
      CallOneArgNode |<<|
        CallOneArgNode |<<|
          LocalVarNode |a| &0 >0
          ArrayNode
            FixnumNode ==2
        ArrayNode
          FixnumNode ==3
    NewlineNode
      FCallOneArgNode |puts|
        ArrayNode
          CallNoArgNode |succ|
            LocalVarNode |b| &1 >0
    NewlineNode
      FixnumNode ==2
    NewlineNode
      LocalVarNode |a| &0 >0

可以发现JRuby认为这段代码里没有heredoc,都是普通的语句而已。也就是说跟<<后带有空格时的结果是一样的:
irb(main):001:0> src = <<SRCEND
irb(main):002:0" a = []
irb(main):003:0" b = 'xyz'
irb(main):004:0" a << 2 << 3
irb(main):005:0" puts b.succ
irb(main):006:0" 2
irb(main):007:0" a
irb(main):008:0" SRCEND
=> "a = []\nb = 'xyz'\na << 2 << 3\nputs b.succ\n2\na\n"
irb(main):009:0> ast = JRuby.parse src
=> RootNode
  BlockNode
    NewlineNode
      LocalAsgnNode |a| &0 >0
        ZArrayNode
    NewlineNode
      LocalAsgnNode |b| &1 >0
        StrNode =="xyz"
    NewlineNode
      CallOneArgNode |<<|
        CallOneArgNode |<<|
          LocalVarNode |a| &0 >0
          ArrayNode
            FixnumNode ==2
        ArrayNode
          FixnumNode ==3
    NewlineNode
      FCallOneArgNode |puts|
        ArrayNode
          CallNoArgNode |succ|
            LocalVarNode |b| &1 >0
    NewlineNode
      FixnumNode ==2
    NewlineNode
      LocalVarNode |a| &0 >0


但这是以a是数组为前提条件的。如果a不是数组呢?看看JRuby 1.1.5对这个的反应:
irb(main):001:0> JRuby.parse "a <<2 <<3\nputs 'ok'\n2"
=> RootNode
  NewlineNode
    FCallOneArgNode |a|
      ArrayNode
        CallOneArgNode |<<|
          StrNode =="puts 'ok'\n"
          ArrayNode
            FixnumNode ==3

太可爱了,等于它认为a是一个方法,那么
a <<2 <<3
puts 'ok'
2

就等价于
a("puts 'ok'" << 3)


再用Ruby 1.8.6 p287来看看:
E:\>irb
irb(main):001:0> def a(str)
irb(main):002:1>   str
irb(main):003:1> end
=> nil
irb(main):004:0> a <<2 <<3
irb(main):005:0" puts 'ok'
irb(main):006:0" 2
=> "puts 'ok'\n\003"

看,果然是把数字3给插到字符串"puts 'ok'"里了……

然而这个状况在IronRuby rev183里也是一样的:
E:\ironruby\build\debug>ir
IronRuby 1.0.0.0 on .NET 2.0.50727.3053
Copyright (c) Microsoft Corporation. All rights reserved.

>>> def a(str)
...   str
... end
=> nil
>>> a <<2 <<3
... puts 'ok'
... 2
=> "puts 'ok'\n\003"


嗯整体看来,开头碰到似乎是irb的bug。IronRuby就“忠于Ruby语言”来说做得已经越来越好了,这里应该不算IronRuby的错。
但是一不小心在代码里弄出heredoc真是够囧的。以后我无论如何都得注意在运算符两边加空格……

==========================================================================

说到IronRuby rev183,这次放到SVN的代码他们是没build测试过吧……用VS2008直接打开是build不了的。要在Microsoft.Scripting.csproj把SpecSharp相关的内容都删除掉,并将Microsoft.Scripting.Extensionattribute.csproj里一个版本号不对的System.dll的引用删掉,然后把各个project里的Reference重新设一边才能build得了。虽然不是第一次碰到这种状况了,多少还是会觉得不爽的……||||

你可能感兴趣的:(.net,SVN,Microsoft,Ruby,jruby)