Ruby 3.2 アドベントカレンダーの21日目の記事です。
RubyVM::AbstractSyntaxTree
RubyVM::AbstractSyntaxTree.parse に error_tolerant
オプション追加
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))))
不完全な状態をパースするようなツールとかにはいいのかもしれない。しらんけど。
RubyVM::AbstractSyntaxTree.parse に keep_tokens
オプション追加
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