This represents a node in the tree. It is the parent class of all of the various node types.
An bitset of flags for this node. There are certain flags that are common for all nodes, and then some nodes have specific flags.
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.
A pointer to the source that this node was created from.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 245
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-4.0.0/lib/prism/node.rb, line 310
def self.type
raise NoMethodError, "undefined method `type' for #{inspect}"
end
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 261
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-4.0.0/lib/prism/node.rb, line 231
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-4.0.0/lib/prism/node.rb, line 118
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-4.0.0/lib/prism/node.rb, line 86
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-4.0.0/lib/prism/node.rb, line 112
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-4.0.0/lib/prism/node.rb, line 80
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-4.0.0/lib/prism/node.rb, line 267
def child_nodes
raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
end
Returns an array of child nodes, including nils in the place of optional nodes that were not present.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 133
def comments
location.comments
end
Delegates to the comments of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 281
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-4.0.0/lib/prism/node.rb, line 275
def compact_child_nodes
raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
end
Returns an array of child nodes, excluding any nils in the place of optional nodes that were not present.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 106
def end_character_column
location.end_character_column
end
Delegates to the end_character_column of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 74
def end_character_offset
location.end_character_offset
end
Delegates to the end_character_offset of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 96
def end_column
location.end_column
end
Delegates to the end_column of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 50
def end_line
location.end_line
end
Delegates to the end_line of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 63
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-4.0.0/lib/prism/node.rb, line 286
def inspect
raise NoMethodError, "undefined method `inspect' for #{inspect}"
end
Returns a string representation of the node.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 123
def leading_comments
location.leading_comments
end
Delegates to the leading_comments of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 33
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-4.0.0/lib/prism/node.rb, line 164
def newline?
flags.anybits?(NodeFlags::NEWLINE)
end
Returns true if the node has the newline flag set.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 175
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-4.0.0/lib/prism/node.rb, line 27
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-4.0.0/lib/prism/node.rb, line 40
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-4.0.0/lib/prism/node.rb, line 147
def slice
location.slice
end
Slice the location of the node from the source.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 154
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-4.0.0/lib/prism/node.rb, line 138
def source_lines
location.source_lines
end
Returns all of the lines of the source code associated with this node.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 101
def start_character_column
location.start_character_column
end
Delegates to the start_character_column of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 69
def start_character_offset
location.start_character_offset
end
Delegates to the start_character_offset of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 91
def start_column
location.start_column
end
Delegates to the start_column of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 45
def start_line
location.start_line
end
Delegates to the start_line of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 56
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-4.0.0/lib/prism/node.rb, line 169
def static_literal?
flags.anybits?(NodeFlags::STATIC_LITERAL)
end
Returns true if the node has the static literal flag set.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 183
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-4.0.0/lib/prism/node.rb, line 128
def trailing_comments
location.trailing_comments
end
Delegates to the trailing_comments of the associated location object.
# File tmp/rubies/ruby-4.0.0/lib/prism/node.rb, line 194
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-4.0.0/lib/prism/node.rb, line 302
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.