Ruby 的 AST 中的 'send' 关键字是什么意思?

What is the meaning of the 'send' keyword in Ruby's AST?

我正在尝试学习 Ruby 词法分析器和解析器 (whitequark parser),以进一步了解从 Ruby 脚本进一步生成机器代码的过程。

在解析以下 Ruby 代码字符串时。

def add(a, b)
    return a + b
end

puts add 1, 2

它导致以下 S 表达式符号。

s(:begin,
    s(:def, :add,
        s(:args,
            s(:arg, :a),
            s(:arg, :b)),
        s(:return,
            s(:send,
                s(:lvar, :a), :+,
                s(:lvar, :b)))),
    s(:send, nil, :puts,
        s(:send, nil, :add,
            s(:int, 1),
            s(:int, 3))))

谁能解释一下结果 S 表达式符号中 :send 关键字的定义?

Ruby 建立在“一切皆对象”范式之上。也就是说,包括数字在内的一切都是对象。

运算符,正如我们在普通 ruby 代码中看到的那样,只不过是一个语法糖,用于各个对象的方法调用:

3.14.+(42)
#⇒ 45.14

以上就是Ruby如何对待3.14 + 42简写法。反过来,它可以使用泛型 Object#send:

编写
3.14.send :+, 42
#⇒ 45.14

后者应理解为:“将带有参数[s] (42) 的消息:+ 发送给接收者3.14。”

Ruby 是一种面向对象的语言。在面向对象的编程中,我们通过让对象向其他对象发送消息来做事。例如,

foo.bar(baz)

表示self向解引用局部变量foo得到的对象发送消息bar,将解引用局部变量baz得到的对象作为争论。 (假设 foobaz 是局部变量。它们也可以是消息发送,因为 Ruby 允许你省略接收者,如果它是 self 和参数列表如果它是空的。请注意,这将在此时被解析器静态知道,但是,因为局部变量是在解析时静态创建的。)

在您的代码中,有几个消息发送:

a + b

将消息 + 发送到变量 a 中的对象,传递变量 b

中的对象
puts add 1, 2

发送消息 addself 将文字整数 12 作为参数传递,然后将消息 puts 发送到 self 将上述消息发送的结果作为参数传递。

请注意,这与 Object#send/Object#public_send没有任何关系。这两个是反射方法,允许您动态指定消息而不是在源代码中静态指定消息。它们通常通过委托给 AST 解释器委托给的相同私有内部运行时例程来在内部实现。 不是相反。解释器调用Object#send(否则,您可以通过猴子修补Object#send自定义Ruby中的方法查找规则,您可以轻松尝试情况并非如此),而是 Object#send 和解释器都调用相同的私有内部实现细节。