This represents a node in the tree. It is the parent class of all of the various node types.
A pointer to the source that this node was created from.
A unique identifier for this node. This is used in a very specific use case where you want to keep around a reference to a node without having to keep around the syntax tree in memory. This unique identifier will be consistent across multiple parses of the same source code.
An bitset of flags for this node. There are certain flags that are common for all nodes, and then some nodes have specific flags.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 242
def self.fields
# This method should only be called on subclasses of Node, not Node
# itself.
raise NoMethodError, "undefined method `fields' for #{inspect}" if self == Node
Reflection.fields_for(self)
end
Returns a list of the fields that exist for this node class. Fields describe the structure of the node. This kind of reflection is useful for things like recursively visiting each node and field in the tree.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 307
def self.type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 258
def accept(visitor)
raise NoMethodError, "undefined method `accept' for #{inspect}"
end
Accepts a visitor and calls back into the specialized visit function.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 228
def breadth_first_search(&block)
queue = [self] #: Array[Prism::node]
while (node = queue.shift)
return node if yield node
queue.concat(node.compact_child_nodes)
end
nil
end
Returns the first node that matches the given block when visited in a depth-first search. This is useful for finding a node that matches a particular condition.
node.breadth_first_search { |node| node.node_id == node_id }
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 115
def cached_end_code_units_column(cache)
location.cached_end_code_units_column(cache)
end
Delegates to the cached_end_code_units_column
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 83
def cached_end_code_units_offset(cache)
location.cached_end_code_units_offset(cache)
end
Delegates to the cached_end_code_units_offset
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 109
def cached_start_code_units_column(cache)
location.cached_start_code_units_column(cache)
end
Delegates to the cached_start_code_units_column
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 77
def cached_start_code_units_offset(cache)
location.cached_start_code_units_offset(cache)
end
Delegates to the cached_start_code_units_offset
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 264
def child_nodes
raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
end
Returns an array of child nodes, including ‘nil`s in the place of optional nodes that were not present.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 278
def comment_targets
raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
end
Returns an array of child nodes and locations that could potentially have comments attached to them.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 130
def comments
location.comments
end
Delegates to the comments of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 272
def compact_child_nodes
raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
end
Returns an array of child nodes, excluding any ‘nil`s in the place of optional nodes that were not present.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 103
def end_character_column
location.end_character_column
end
Delegates to the end_character_column
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 71
def end_character_offset
location.end_character_offset
end
Delegates to the end_character_offset
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 93
def end_column
location.end_column
end
Delegates to the end_column
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 47
def end_line
location.end_line
end
Delegates to the end_line
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 60
def end_offset
location = @location
location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
end
The end offset of the node in the source. This method is effectively a delegate method to the location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 283
def inspect
raise NoMethodError, "undefined method `inspect' for #{inspect}"
end
Returns a string representation of the node.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 120
def leading_comments
location.leading_comments
end
Delegates to the leading_comments
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 30
def location
location = @location
return location if location.is_a?(Location)
@location = Location.new(source, location >> 32, location & 0xFFFFFFFF)
end
A Location
instance that represents the location of this node in the source.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 161
def newline?
flags.anybits?(NodeFlags::NEWLINE)
end
Returns true if the node has the newline flag set.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 172
def pretty_print(q)
q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
q.text(line.chomp)
end
q.current_group.break
end
Similar to inspect, but respects the current level of indentation given by the pretty print object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 24
def save(repository)
repository.enter(node_id, :itself)
end
Save this node using a saved source so that it can be retrieved later.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 37
def save_location(repository)
repository.enter(node_id, :location)
end
Save the location using a saved source so that it can be retrieved later.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 144
def slice
location.slice
end
Slice the location of the node from the source.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 151
def slice_lines
location.slice_lines
end
Slice the location of the node from the source, starting at the beginning of the line that the location starts on, ending at the end of the line that the location ends on.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 135
def source_lines
location.source_lines
end
Returns all of the lines of the source code associated with this node.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 98
def start_character_column
location.start_character_column
end
Delegates to the start_character_column
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 66
def start_character_offset
location.start_character_offset
end
Delegates to the start_character_offset
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 88
def start_column
location.start_column
end
Delegates to the start_column
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 42
def start_line
location.start_line
end
Delegates to the start_line
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 53
def start_offset
location = @location
location.is_a?(Location) ? location.start_offset : location >> 32
end
The start offset of the node in the source. This method is effectively a delegate method to the location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 166
def static_literal?
flags.anybits?(NodeFlags::STATIC_LITERAL)
end
Returns true if the node has the static literal flag set.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 180
def to_dot
# @type self: node
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
end
Convert this node into a graphviz dot graph string.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 125
def trailing_comments
location.trailing_comments
end
Delegates to the trailing_comments
of the associated location object.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 191
def tunnel(line, column)
queue = [self] #: Array[Prism::node]
result = [] #: Array[Prism::node]
while (node = queue.shift)
result << node
node.compact_child_nodes.each do |child_node|
child_location = child_node.location
start_line = child_location.start_line
end_line = child_location.end_line
if start_line == end_line
if line == start_line && column >= child_location.start_column && column < child_location.end_column
queue << child_node
break
end
elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column)
queue << child_node
break
elsif line > start_line && line < end_line
queue << child_node
break
end
end
end
result
end
Returns a list of nodes that are descendants of this node that contain the given line and column. This is useful for locating a node that is selected based on the line and column of the source code.
Important to note is that the column given to this method should be in bytes, as opposed to characters or code units.
# File tmp/rubies/ruby-3.4.1/lib/prism/node.rb, line 299
def type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
Sometimes you want to check an instance of a node against a list of classes to see what kind of behavior to perform. Usually this is done by calling ‘[cls1, cls2].include?(node.class)` or putting the node into a case statement and doing `case node; when cls1; when cls2; end`. Both of these approaches are relatively slow because of the constant lookups, method calls, and/or array allocations.
Instead, you can call type
, which will return to you a symbol that you can use for comparison. This is faster than the other approaches because it uses a single integer comparison, but also because if you’re on CRuby you can take advantage of the fact that case statements with all symbol keys will use a jump table.