3 # AbstractSyntaxTree provides methods to parse Ruby code into
4 # abstract syntax trees. The nodes in the tree
5 # are instances of RubyVM::AbstractSyntaxTree::Node.
7 # This module is MRI specific as it exposes implementation details
8 # of the MRI abstract syntax tree.
10 # This module is experimental and its API is not stable, therefore it might
11 # change without notice. As examples, the order of children nodes is not
12 # guaranteed, the number of children nodes might change, there is no way to
13 # access children nodes by name, etc.
15 # If you are looking for a stable API or an API working under multiple Ruby
16 # implementations, consider using the _prism_ gem, which is the official
17 # Ruby API to parse Ruby code.
19 module RubyVM::AbstractSyntaxTree
22 # RubyVM::AbstractSyntaxTree.parse(string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
24 # Parses the given _string_ into an abstract syntax tree,
25 # returning the root node of that tree.
27 # RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
28 # # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-1:9>
30 # If <tt>keep_script_lines: true</tt> option is provided, the text of the parsed
31 # source is associated with nodes and is available via Node#script_lines.
33 # If <tt>keep_tokens: true</tt> option is provided, Node#tokens are populated.
35 # SyntaxError is raised if the given _string_ is invalid syntax. To overwrite this
36 # behavior, <tt>error_tolerant: true</tt> can be provided. In this case, the parser
37 # will produce a tree where expressions with syntax errors would be represented by
38 # Node with <tt>type=:ERROR</tt>.
40 # root = RubyVM::AbstractSyntaxTree.parse("x = 1; p(x; y=2")
41 # # <internal:ast>:33:in `parse': syntax error, unexpected ';', expecting ')' (SyntaxError)
45 # root = RubyVM::AbstractSyntaxTree.parse("x = 1; p(x; y=2", error_tolerant: true)
49 # # 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))))
50 # root.children.last.children
51 # # [(LASGN@1:0-1:5 :x (LIT@1:4-1:5 1)),
53 # # (LASGN@1:12-1:15 :y (LIT@1:14-1:15 2))]
55 # Note that parsing continues even after the errored expression.
57 def self.parse string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
58 Primitive.ast_s_parse string, keep_script_lines, error_tolerant, keep_tokens
62 # RubyVM::AbstractSyntaxTree.parse_file(pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
64 # Reads the file from _pathname_, then parses it like ::parse,
65 # returning the root node of the abstract syntax tree.
67 # SyntaxError is raised if _pathname_'s contents are not
70 # RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
71 # # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
73 # See ::parse for explanation of keyword argument meaning and usage.
74 def self.parse_file pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
75 Primitive.ast_s_parse_file pathname, keep_script_lines, error_tolerant, keep_tokens
79 # RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
80 # RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
82 # Returns AST nodes of the given _proc_ or _method_.
84 # RubyVM::AbstractSyntaxTree.of(proc {1 + 2})
85 # # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:35-1:42>
91 # RubyVM::AbstractSyntaxTree.of(method(:hello))
92 # # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
94 # See ::parse for explanation of keyword argument meaning and usage.
95 def self.of body, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
96 Primitive.ast_s_of body, keep_script_lines, error_tolerant, keep_tokens
100 # RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(backtrace_location) -> integer
102 # Returns the node id for the given backtrace location.
107 # loc = e.backtrace_locations.first
108 # RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(loc)
110 def self.node_id_for_backtrace_location backtrace_location
111 Primitive.node_id_for_backtrace_location backtrace_location
114 # RubyVM::AbstractSyntaxTree::Node instances are created by parse methods in
115 # RubyVM::AbstractSyntaxTree.
117 # This class is MRI specific.
122 # node.type -> symbol
124 # Returns the type of this node as a symbol.
126 # root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
127 # root.type # => :SCOPE
128 # lasgn = root.children[2]
129 # lasgn.type # => :LASGN
130 # call = lasgn.children[1]
131 # call.type # => :OPCALL
133 Primitive.ast_node_type
137 # node.first_lineno -> integer
139 # The line number in the source code where this AST's text began.
141 Primitive.ast_node_first_lineno
145 # node.first_column -> integer
147 # The column number in the source code where this AST's text began.
149 Primitive.ast_node_first_column
153 # node.last_lineno -> integer
155 # The line number in the source code where this AST's text ended.
157 Primitive.ast_node_last_lineno
161 # node.last_column -> integer
163 # The column number in the source code where this AST's text ended.
165 Primitive.ast_node_last_column
169 # node.tokens -> array
171 # Returns tokens corresponding to the location of the node.
172 # Returns +nil+ if +keep_tokens+ is not enabled when #parse method is called.
174 # root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true)
175 # root.tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
176 # root.tokens.map{_1[2]}.join # => "x = 1 + 2"
178 # Token is an array of:
183 # - location [ first_lineno, first_column, last_lineno, last_column ]
185 return nil unless all_tokens
187 all_tokens.each_with_object([]) do |token, a|
189 if ([first_lineno, first_column] <=> [loc[0], loc[1]]) <= 0 &&
190 ([last_lineno, last_column] <=> [loc[2], loc[3]]) >= 0
197 # node.all_tokens -> array
199 # Returns all tokens for the input script regardless the receiver node.
200 # Returns +nil+ if +keep_tokens+ is not enabled when #parse method is called.
202 # root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true)
203 # root.all_tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
204 # root.children[-1].all_tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
206 Primitive.ast_node_all_tokens
210 # node.children -> array
212 # Returns AST nodes under this one. Each kind of node
213 # has different children, depending on what kind of node it is.
215 # The returned array may contain other nodes or <code>nil</code>.
217 Primitive.ast_node_children
221 # node.inspect -> string
223 # Returns debugging information about this node as a string.
225 Primitive.ast_node_inspect
229 # node.node_id -> integer
231 # Returns an internal node_id number.
232 # Note that this is an API for ruby internal use, debugging,
233 # and research. Do not use this for any other purpose.
234 # The compatibility is not guaranteed.
236 Primitive.ast_node_node_id
240 # node.script_lines -> array
242 # Returns the original source code as an array of lines.
244 # Note that this is an API for ruby internal use, debugging,
245 # and research. Do not use this for any other purpose.
246 # The compatibility is not guaranteed.
248 Primitive.ast_node_script_lines
252 # node.source -> string
254 # Returns the code fragment that corresponds to this AST.
256 # Note that this is an API for ruby internal use, debugging,
257 # and research. Do not use this for any other purpose.
258 # The compatibility is not guaranteed.
260 # Also note that this API may return an incomplete code fragment
261 # that does not parse; for example, a here document following
262 # an expression may be dropped.
266 lines = lines[first_lineno - 1 .. last_lineno - 1]
267 lines[-1] = lines[-1].byteslice(0...last_column)
268 lines[0] = lines[0].byteslice(first_column..-1)
276 # node.locations -> array
278 # Returns location objects associated with the AST node.
279 # The returned array contains RubyVM::AbstractSyntaxTree::Location.
281 Primitive.ast_node_locations
285 # RubyVM::AbstractSyntaxTree::Location instances are created by
286 # RubyVM::AbstractSyntaxTree::Node#locations.
288 # This class is MRI specific.
293 # location.first_lineno -> integer
295 # The line number in the source code where this AST's text began.
297 Primitive.ast_location_first_lineno
301 # location.first_column -> integer
303 # The column number in the source code where this AST's text began.
305 Primitive.ast_location_first_column
309 # location.last_lineno -> integer
311 # The line number in the source code where this AST's text ended.
313 Primitive.ast_location_last_lineno
317 # location.last_column -> integer
319 # The column number in the source code where this AST's text ended.
321 Primitive.ast_location_last_column
325 # location.inspect -> string
327 # Returns debugging information about this location as a string.
329 Primitive.ast_location_inspect