RubyVM::AST [Experimental]
Ruby 2.6では RubyVM::AST モジュールが導入されました。
このモジュールには、文字列をパースしてAST(抽象構文木)のNodeを返すparseメソッド、ファイルをパースするparse_fileメソッドが実装されています。 RubyVM::AST::Node も導入されました。このクラスのインスタンスから位置情報や子ノードを取得することができます。この機能はexperimentalであり、互換性は保証されていません。
https://www.ruby-lang.org/ja/news/2018/05/31/ruby-2-6-0-preview2-released/
API
RubyVM::AST
= RubyVM::AST
(from ruby core)
------------------------------------------------------------------------
= Class methods:
parse, parse_file
RubyVM::AST::Node
= RubyVM::AST::Node < Object
(from ruby core)
------------------------------------------------------------------------
= Instance methods:
children, first_column, first_lineno, inspect, last_column,
last_lineno, type
RubyVM::AST.parse
Rubyのコードの文字列を渡すと、文字列をパースしてASTを返す。とりあえず無をparseしてみる。
root = RubyVM::AST.parse('')
# => #<RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 2:0): >
root.type
# => "NODE_SCOPE"
[root.first_lineno, root.first_column, root.last_lineno, root.last_column]
# => [1, 0, 2, 0]
root.children
# => [nil, #<RubyVM::AST::Node(NODE_BEGIN(16) 2:0, 2:0): >]
root.children.class
# => Array
root.children.last.type
# => "NODE_BEGIN
root.children.last.children
# => [nil]
パースできない文字列を渡すとどうなるか
エラーが出て実行がとまる
RubyVM::AST.parse('^^')
# no file name:1: syntax error, unexpected '^'
rescue
できない
begin
RubyVM::AST.parse('^^')
rescue Exception
puts "捕まえた〜!"
p $!
end
# no file name:1: syntax error, unexpected '^'
RubyVM::AST::Node
#type
この辺で定義されてるenum node_type
を文字列で返す。
https://github.com/ruby/ruby/blob/v2_6_0_preview2/node.h#L22-L225
#children
抽象構文木の葉を返す。末端までたどって表示させてみると節点に演算子(NODE_OPCALL
)が来ているのがわかる。
def walk(node, level = 0)
print " " * (level * 2)
p node
return unless node&.children&.empty?&.!
walk(node.children.first, level + 1)
walk(node.children.last, level + 1)
end
walk(RubyVM::AST.parse('1 + 1'))
# #<RubyVM::AST::Node(NODE_SCOPE(0) 1:0, 1:5): >
# nil
# #<RubyVM::AST::Node(NODE_OPCALL(36) 1:0, 1:5): >
# #<RubyVM::AST::Node(NODE_LIT(59) 1:0, 1:1): >
# #<RubyVM::AST::Node(NODE_ARRAY(42) 1:4, 1:5): >
# #<RubyVM::AST::Node(NODE_LIT(59) 1:4, 1:5): >
# nil
RubyVM::AST::Nodeをnewできるか
new
できない
RubyVM::AST::Node.new
Traceback (most recent call last):
2: from /home/sei/local/bin/irb:11:in `<main>'
1: from (irb):1
NoMethodError (undefined method `new' for RubyVM::AST::Node:Class)
自分でASTを組み立ててYARVのInstructionSequenceにコンパイルして実行できるか
YARVのInstructionSequenceに変換するAPIは公開されていないので出来なさそう。