模块 RubyVM::AbstractSyntaxTree

AbstractSyntaxTree 提供将 Ruby 代码解析为抽象语法树的方法。树中的节点是 RubyVM::AbstractSyntaxTree::Node 的实例。

此模块是 MRI 特定的,因为它公开了 MRI 抽象语法树的实现细节。

此模块处于实验阶段,其 API 不稳定,因此可能会在未经通知的情况下更改。例如,子节点的顺序没有保证,子节点的数量可能会更改,没有办法按名称访问子节点等。

如果您正在寻找稳定的 API 或在多个 Ruby 实现中工作的 API,请考虑使用 parser gem 或 Ripper。如果您想使 RubyVM::AbstractSyntaxTree 稳定,请加入 bugs.ruby-lang.org/issues/14844 的讨论。

公共类方法

RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(backtrace_location) → integer 点击切换源代码

返回给定回溯位置的节点 ID。

begin
  raise
rescue =>  e
  loc = e.backtrace_locations.first
  RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc)
end # => 0
# File ast.rb, line 111
def self.node_id_for_backtrace_location backtrace_location
  Primitive.node_id_for_backtrace_location backtrace_location
end
RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) → RubyVM::AbstractSyntaxTree::Node 点击切换源代码
RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) → RubyVM::AbstractSyntaxTree::Node

返回给定 procmethod 的 AST 节点。

RubyVM::AbstractSyntaxTree.of(proc {1 + 2})
# => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:35-1:42>

def hello
  puts "hello, world"
end

RubyVM::AbstractSyntaxTree.of(method(:hello))
# => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>

有关关键字参数含义和用法的解释,请参见 ::parse

# File ast.rb, line 96
def self.of body, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
  Primitive.ast_s_of body, keep_script_lines, error_tolerant, keep_tokens
end
RubyVM::AbstractSyntaxTree.parse(string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) → RubyVM::AbstractSyntaxTree::Node 点击切换源代码

将给定的字符串解析为抽象语法树,并返回该树的根节点。

RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
# => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-1:9>

如果提供了keep_script_lines: true选项,则解析后的源代码文本将与节点关联,并可通过Node#script_lines访问。

如果提供了keep_tokens: true选项,则会填充Node#tokens

如果给定的字符串语法无效,则会引发SyntaxError。要覆盖此行为,可以提供error_tolerant: true。在这种情况下,解析器将生成一个树,其中语法错误的表达式将由Node表示,其type=:ERROR

root = RubyVM::AbstractSyntaxTree.parse("x = 1; p(x; y=2")
# <internal:ast>:33:in `parse': syntax error, unexpected ';', expecting ')' (SyntaxError)
# x = 1; p(x; y=2
#           ^

root = RubyVM::AbstractSyntaxTree.parse("x = 1; p(x; y=2", error_tolerant: true)
# (SCOPE@1:0-1:15
#  tbl: [:x, :y]
#  args: nil
#  body: (BLOCK@1:0-1:15 (LASGN@1:0-1:5 :x (LIT@1:4-1:5 1)) (ERROR@1:7-1:11) (LASGN@1:12-1:15 :y (LIT@1:14-1:15 2))))
root.children.last.children
# [(LASGN@1:0-1:5 :x (LIT@1:4-1:5 1)),
#  (ERROR@1:7-1:11),
#  (LASGN@1:12-1:15 :y (LIT@1:14-1:15 2))]

请注意,即使在遇到错误表达式后,解析也会继续进行。

# File ast.rb, line 58
def self.parse string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
  Primitive.ast_s_parse string, keep_script_lines, error_tolerant, keep_tokens
end
RubyVM::AbstractSyntaxTree.parse_file(pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) → RubyVM::AbstractSyntaxTree::Node 点击切换源代码

pathname读取文件,然后像::parse一样解析它,返回抽象语法树的根节点。

如果pathname的内容不是有效的 Ruby 语法,则会引发SyntaxError

RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
# => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>

有关关键字参数含义和用法的解释,请参见 ::parse

# File ast.rb, line 75
def self.parse_file pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
  Primitive.ast_s_parse_file pathname, keep_script_lines, error_tolerant, keep_tokens
end