💎
Ruby 3.2 - RubyVM::AbstractSyntaxTree
Ruby 3.2 アドベントカレンダーの21日目の記事です。
RubyVM::AbstractSyntaxTree
error_tolerant
オプション追加
RubyVM::AbstractSyntaxTree.parse に Feature #19013: Error Tolerant Parser - Ruby master - Ruby Issue Tracking System
RubyVM::AbstractSyntaxTree.parse
とかに構文エラーがあるような文字列を食わせるとエラーになる。
s = <<EOS
def hoge
p 1,
end
EOS
RubyVM::AbstractSyntaxTree.parse(s)
#=> SyntaxSuggest: Could not find filename from "syntax error, unexpected `end' (SyntaxError)"
# <internal:ast>:33:in `parse': syntax error, unexpected `end' (SyntaxError)
# from a.rb:6:in `<main>'
Ruby 3.2 では error_tolerant
オプションに真を指定して、エラーにせずにエラーを含んだオブジェクトが返せるようになった。
s = <<EOS
def hoge
p 1,
end
EOS
RubyVM::AbstractSyntaxTree.parse(s, error_tolerant: true)
#=> (SCOPE@1:0-3:3
# tbl: []
# args: nil
# body:
# (DEFN@1:0-3:3
# mid: :hoge
# body:
# (SCOPE@1:0-3:3
# tbl: []
# args:
# (ARGS@1:8-1:8
# pre_num: 0
# pre_init: nil
# opt: nil
# first_post: nil
# post_num: 0
# post_init: nil
# rest: nil
# kw: nil
# kwrest: nil
# block: nil)
# body: (ERROR@2:2-3:3))))
不完全な状態をパースするようなツールとかにはいいのかもしれない。しらんけど。
keep_tokens
オプション追加
RubyVM::AbstractSyntaxTree.parse に
keep_tokens
に真を指定すると #tokens
でトークンを得ることができるようになった。
s = <<EOS
def hoge
p 1,2,3
end
EOS
ast = RubyVM::AbstractSyntaxTree.parse(s, keep_tokens: true)
pp ast.tokens
# [[0, :keyword_def, "def", [1, 0, 1, 3]],
# [1, :tSP, " ", [1, 3, 1, 4]],
# [2, :tIDENTIFIER, "hoge", [1, 4, 1, 8]],
# [3, :nl, "\n", [1, 8, 1, 9]],
# [4, :tSP, " ", [2, 0, 2, 2]],
# [5, :tIDENTIFIER, "p", [2, 2, 2, 3]],
# [6, :tSP, " ", [2, 3, 2, 4]],
# [7, :tINTEGER, "1", [2, 4, 2, 5]],
# [8, :",", ",", [2, 5, 2, 6]],
# [9, :tINTEGER, "2", [2, 6, 2, 7]],
# [10, :",", ",", [2, 7, 2, 8]],
# [11, :tINTEGER, "3", [2, 8, 2, 9]],
# [12, :nl, "\n", [2, 9, 2, 10]],
# [13, :keyword_end, "end", [3, 0, 3, 3]]]
puts ast.tokens.map{_1[2]}.join
# def hoge
# p 1,2,3
# end
Discussion