From e068554f151ab6a083846d63852532e079bbb4f8 Mon Sep 17 00:00:00 2001 From: Masataka Pocke Kuwabara Date: Sat, 20 Jun 2020 19:51:17 +0900 Subject: [PATCH 1/4] Add RubyVM::AbstractSyntaxTree --- refm/api/src/_builtin.rd | 2 + .../src/_builtin/RubyVM__AbstractSyntaxTree | 96 +++++++++++++++++++ .../_builtin/RubyVM__AbstractSyntaxTree__Node | 76 +++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 refm/api/src/_builtin/RubyVM__AbstractSyntaxTree create mode 100644 refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node diff --git a/refm/api/src/_builtin.rd b/refm/api/src/_builtin.rd index bd4fcff121..468fdd7150 100644 --- a/refm/api/src/_builtin.rd +++ b/refm/api/src/_builtin.rd @@ -102,6 +102,8 @@ require を書かなくても使うことができます。 #@include(_builtin/RubyVM__InstructionSequence) #@since 2.6.0 #@include(_builtin/RubyVM__MJIT) +#@include(_builtin/RubyVM__AbstractSyntaxTree) +#@include(_builtin/RubyVM__AbstractSyntaxTree__Node) #@end #@include(_builtin/RuntimeError) #@include(_builtin/ScriptError) diff --git a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree new file mode 100644 index 0000000000..d8341128f6 --- /dev/null +++ b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree @@ -0,0 +1,96 @@ += module RubyVM::AbstractSyntaxTree + +Ruby のコードをパースして得られる抽象構文木を扱うモジュールです。 + +抽象構文木は[[c:RubyVM::AbstractSyntaxTree::Node]]クラスのインスタンスとして表されます。 + + +このモジュールはMRIの抽象構文木の実装の詳細を表します。 + +このモジュールは実験的であり、安定したAPIではないため、 +予告なしに変更される可能性があります。 +例えば、子要素の順序は保証されておらず、 +子要素の数は変更される可能性があります。 +また子要素に名前でアクセスする方法は提供されていません。 + +もし安定したAPIやMRI以外の実装で抽象構文木を扱いたい場合、 +parser gem ([[url:https://github.com/whitequark/parser]])や +[[c:Ripper]]の使用を検討してください。 +もし RubyVM::AbstractSyntaxTree のAPIを安定にしたい場合、[[feature:14844]] での議論に参加してください。 + +== Singleton Methods + +--- of(proc) -> RubyVM::AbstractSyntaxTree::Node + +引数 proc に渡したProcやメソッドオブジェクトの抽象構文木を返します。 + +@param proc Procもしくはメソッドオブジェクトを指定します。 + +#@samplecode +pp RubyVM::AbstractSyntaxTree.of(proc {1 + 2}) +# => (SCOPE@2:38-2:45 +# tbl: [] +# args: nil +# body: +# (OPCALL@2:39-2:44 (LIT@2:39-2:40 1) :+ +# (LIST@2:43-2:44 (LIT@2:43-2:44 2) nil))) + +def hello + puts "hello, world" +end + +pp RubyVM::AbstractSyntaxTree.of(method(:hello)) +# => (SCOPE@5:0-7:3 +# tbl: [] +# args: +# (ARGS@5:9-5:9 +# 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: +# (FCALL@6:2-6:21 :puts (LIST@6:7-6:21 (STR@6:7-6:21 "hello, world") nil))) +#@end + + +--- parse(string) -> RubyVM::AbstractSyntaxTree::Node + +文字列を抽象構文木にパースし、その木の根ノードを返します。 + +@param string パースする対象の Ruby のコードを文字列で指定します。 +@raise SyntaxError string が Ruby のコードとして正しくない場合に発生します。 + +#@samplecode +pp RubyVM::AbstractSyntaxTree.parse("x = 1 + 2") +# => (SCOPE@1:0-1:9 +# tbl: [:x] +# args: nil +# body: +# (LASGN@1:0-1:9 :x +# (OPCALL@1:4-1:9 (LIT@1:4-1:5 1) :+ (LIST@1:8-1:9 (LIT@1:8-1:9 2) nil)))) +#@end + +--- parse_file(pathname) -> RubyVM::AbstractSyntaxTree::Node + +pathname のファイルを読み込み、その内容を抽象構文木にパースし、その木の根ノードを返します。 + +@param pathname パースする対象のファイルパスを指定します +@raise SyntaxError string が Ruby のコードとして正しくない場合に発生します。 + +#@samplecode +# => (SCOPE@1:0-1:50 +# tbl: [] +# args: nil +# body: +# (FCALL@1:0-1:50 :pp +# (LIST@1:3-1:50 +# (CALL@1:3-1:50 +# (COLON2@1:3-1:29 (CONST@1:3-1:9 :RubyVM) :AbstractSyntaxTree) +# :parse_file (LIST@1:41-1:49 (STR@1:41-1:49 "") nil)) nil))) +#@end diff --git a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node new file mode 100644 index 0000000000..ddf31553f8 --- /dev/null +++ b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node @@ -0,0 +1,76 @@ += class RubyVM::AbstractSyntaxTree::Node + +[[m:RubyVM::AbstractSyntaxTree.parse]] によって作られる抽象構文木を表すクラスです。 + +このクラスは MRI の実装の詳細を表します。 + +== Instance Methods + +--- children -> Array + +self の子ノードを配列で返します。 + +どのような子ノードが返ってくるかは、そのノードの type によって異なります。 + +戻り値は、ほかの RubyVM::AbstractSyntaxTree::Node のインスタンスや nil を含みます。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 2') +p node.children +# => [[], nil, #] +#@end + +--- first_column -> Integer + +ソースコード中で、self を表すテキストが最初に現れる列番号を返します。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 2') +p node.first_column # => 0 +#@end + +--- first_lineno -> Integer + +ソースコード中で、self を表すテキストが最初に現れる行番号を返します。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 2') +p node.first_lineno # => 1 +#@end + +--- inspect -> String + +self のデバッグ用の情報を含んだ文字列を返します。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 1') +puts node.inspect +# => # +#@end + +--- last_column -> Integer + +ソースコード中で、self を表すテキストが最後に現れる列番号を返します。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 1') +p node.last_column # => 5 +#@end + +--- last_lineno -> Integer + +ソースコード中で、self を表すテキストが最後に現れる行番号を返します。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 1') +p node.last_lineno # => 1 +#@end + +--- type -> Symbol + +self の種類を Symbol で返します。 + +#@samplecode +node = RubyVM::AbstractSyntaxTree.parse('1 + 1') +p node.type # => :SCOPE +#@end From 7411d4f4f208ef2c939d2eba1c3b7f99a857056b Mon Sep 17 00:00:00 2001 From: Masataka Pocke Kuwabara Date: Tue, 14 Jul 2020 20:34:26 +0900 Subject: [PATCH 2/4] Mention IRB from AST#of --- refm/api/src/_builtin/RubyVM__AbstractSyntaxTree | 3 +++ 1 file changed, 3 insertions(+) diff --git a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree index d8341128f6..cc3e396b21 100644 --- a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree +++ b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree @@ -24,6 +24,9 @@ parser gem ([[url:https://github.com/whitequark/parser]])や 引数 proc に渡したProcやメソッドオブジェクトの抽象構文木を返します。 +このメソッドはProcやメソッドが定義されたファイルを読み込む必要があるため、 +irbのようなファイルを介さない対話的環境では動作しません。 + @param proc Procもしくはメソッドオブジェクトを指定します。 #@samplecode From 0dfb3dbc281248e261be6f27262d70846f75bc77 Mon Sep 17 00:00:00 2001 From: Masataka Pocke Kuwabara Date: Tue, 14 Jul 2020 20:36:02 +0900 Subject: [PATCH 3/4] Fix samplecode for AST#parse_file --- refm/api/src/_builtin/RubyVM__AbstractSyntaxTree | 1 + 1 file changed, 1 insertion(+) diff --git a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree index cc3e396b21..83ea95c71a 100644 --- a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree +++ b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree @@ -87,6 +87,7 @@ pathname のファイルを読み込み、その内容を抽象構文木にパ @raise SyntaxError string が Ruby のコードとして正しくない場合に発生します。 #@samplecode +pp RubyVM::AbstractSyntaxTree.parse_file(__FILE__) # => (SCOPE@1:0-1:50 # tbl: [] # args: nil From 93073aead89f5de757070cb52a25755389d1f97f Mon Sep 17 00:00:00 2001 From: Masataka Pocke Kuwabara Date: Tue, 14 Jul 2020 20:37:24 +0900 Subject: [PATCH 4/4] Mention origin in AST::Node doc --- refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node index ddf31553f8..5a122616c3 100644 --- a/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node +++ b/refm/api/src/_builtin/RubyVM__AbstractSyntaxTree__Node @@ -24,6 +24,8 @@ p node.children ソースコード中で、self を表すテキストが最初に現れる列番号を返します。 +列番号は0-originで、バイト単位で表されます。 + #@samplecode node = RubyVM::AbstractSyntaxTree.parse('1 + 2') p node.first_column # => 0 @@ -33,6 +35,8 @@ p node.first_column # => 0 ソースコード中で、self を表すテキストが最初に現れる行番号を返します。 +行番号は1-originです。 + #@samplecode node = RubyVM::AbstractSyntaxTree.parse('1 + 2') p node.first_lineno # => 1 @@ -52,6 +56,8 @@ puts node.inspect ソースコード中で、self を表すテキストが最後に現れる列番号を返します。 +列番号は0-originで、バイト単位で表されます。 + #@samplecode node = RubyVM::AbstractSyntaxTree.parse('1 + 1') p node.last_column # => 5 @@ -61,6 +67,8 @@ p node.last_column # => 5 ソースコード中で、self を表すテキストが最後に現れる行番号を返します。 +行番号は1-originです。 + #@samplecode node = RubyVM::AbstractSyntaxTree.parse('1 + 1') p node.last_lineno # => 1