123456789_123456789_123456789_123456789_123456789_

Class: Prism::Node

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
AliasGlobalVariableNode, AliasMethodNode, AlternationPatternNode, AndNode, ArgumentsNode, ArrayNode, ArrayPatternNode, AssocNode, AssocSplatNode, BackReferenceReadNode, BeginNode, BlockArgumentNode, BlockLocalVariableNode, BlockNode, BlockParameterNode, BlockParametersNode, BreakNode, CallAndWriteNode, CallNode, CallOperatorWriteNode, CallOrWriteNode, CallTargetNode, CapturePatternNode, CaseMatchNode, CaseNode, ClassNode, ClassVariableAndWriteNode, ClassVariableOperatorWriteNode, ClassVariableOrWriteNode, ClassVariableReadNode, ClassVariableTargetNode, ClassVariableWriteNode, ConstantAndWriteNode, ConstantOperatorWriteNode, ConstantOrWriteNode, ConstantPathAndWriteNode, ConstantPathNode, ConstantPathOperatorWriteNode, ConstantPathOrWriteNode, ConstantPathTargetNode, ConstantPathWriteNode, ConstantReadNode, ConstantTargetNode, ConstantWriteNode, DefNode, DefinedNode, ElseNode, EmbeddedStatementsNode, EmbeddedVariableNode, EnsureNode, FalseNode, FindPatternNode, FlipFlopNode, FloatNode, ForNode, ForwardingArgumentsNode, ForwardingParameterNode, ForwardingSuperNode, GlobalVariableAndWriteNode, GlobalVariableOperatorWriteNode, GlobalVariableOrWriteNode, GlobalVariableReadNode, GlobalVariableTargetNode, GlobalVariableWriteNode, HashNode, HashPatternNode, IfNode, ImaginaryNode, ImplicitNode, ImplicitRestNode, InNode, IndexAndWriteNode, IndexOperatorWriteNode, IndexOrWriteNode, IndexTargetNode, InstanceVariableAndWriteNode, InstanceVariableOperatorWriteNode, InstanceVariableOrWriteNode, InstanceVariableReadNode, InstanceVariableTargetNode, InstanceVariableWriteNode, IntegerNode, InterpolatedMatchLastLineNode, InterpolatedRegularExpressionNode, InterpolatedStringNode, InterpolatedSymbolNode, InterpolatedXStringNode, ItLocalVariableReadNode, ItParametersNode, KeywordHashNode, KeywordRestParameterNode, LambdaNode, LocalVariableAndWriteNode, LocalVariableOperatorWriteNode, LocalVariableOrWriteNode, LocalVariableReadNode, LocalVariableTargetNode, LocalVariableWriteNode, MatchLastLineNode, MatchPredicateNode, MatchRequiredNode, MatchWriteNode, MissingNode, ModuleNode, MultiTargetNode, MultiWriteNode, NextNode, NilNode, NoKeywordsParameterNode, NumberedParametersNode, NumberedReferenceReadNode, OptionalKeywordParameterNode, OptionalParameterNode, OrNode, ParametersNode, ParenthesesNode, PinnedExpressionNode, PinnedVariableNode, PostExecutionNode, PreExecutionNode, ProgramNode, RangeNode, RationalNode, RedoNode, RegularExpressionNode, RequiredKeywordParameterNode, RequiredParameterNode, RescueModifierNode, RescueNode, RestParameterNode, RetryNode, ReturnNode, SelfNode, ShareableConstantNode, SingletonClassNode, SourceEncodingNode, SourceFileNode, SourceLineNode, SplatNode, StatementsNode, StringNode, SuperNode, SymbolNode, TrueNode, UndefNode, UnlessNode, UntilNode, WhenNode, WhileNode, XStringNode, YieldNode
Inherits: Object
Defined in: lib/prism/node.rb,
lib/prism/node_ext.rb,
lib/prism/parse_result/newlines.rb,
prism/extension.c

Overview

This represents a node in the tree. It is the parent class of all of the various node types.

Class Method Summary

  • .fields

    Returns a list of the fields that exist for this node class.

  • .type

    Similar to #type, this method returns a symbol that you can use for splitting on the type of the node without having to do a long === chain.

Instance Attribute Summary

Instance Method Summary

Class Method Details

.fields

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.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 234

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

.type

Similar to #type, this method returns a symbol that you can use for splitting on the type of the node without having to do a long === chain. Note that like #type, it will still be slower than using == for a single class, but should be faster in a case statement or an array comparison.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 306

def self.type
  raise NoMethodError, "undefined method `type' for #{inspect}"
end

Instance Attribute Details

#flags (readonly, protected)

An bitset of flags for this node. There are certain flags that are common for all nodes, and then some nodes have specific flags.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 160

attr_reader :flags

#newline?Boolean (readonly)

Returns true if the node has the newline flag set.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 164

def newline?
  flags.anybits?(NodeFlags::NEWLINE)
end

#newline_flag?Boolean (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 66

def newline_flag? # :nodoc:
  !!defined?(@newline_flag)
end

#node_id (readonly)

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.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 24

attr_reader :node_id

#source (readonly, private)

A pointer to the source that this node was created from.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 17

attr_reader :source

#static_literal?Boolean (readonly)

Returns true if the node has the static literal flag set.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 169

def static_literal?
  flags.anybits?(NodeFlags::STATIC_LITERAL)
end

Instance Method Details

#accept(visitor)

Accepts a visitor and calls back into the specialized visit function.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 250

def accept(visitor)
  raise NoMethodError, "undefined method `accept' for #{inspect}"
end

#breadth_first_search(&block)

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 }
[ GitHub ]

  
# File 'lib/prism/node.rb', line 220

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

#cached_end_code_units_column(cache)

Delegates to the cached_end_code_units_column of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 118

def cached_end_code_units_column(cache)
  location.cached_end_code_units_column(cache)
end

#cached_end_code_units_offset(cache)

Delegates to the cached_end_code_units_offset of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 86

def cached_end_code_units_offset(cache)
  location.cached_end_code_units_offset(cache)
end

#cached_start_code_units_column(cache)

Delegates to the cached_start_code_units_column of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 112

def cached_start_code_units_column(cache)
  location.cached_start_code_units_column(cache)
end

#cached_start_code_units_offset(cache)

Delegates to the cached_start_code_units_offset of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 80

def cached_start_code_units_offset(cache)
  location.cached_start_code_units_offset(cache)
end

#child_nodes Also known as: #deconstruct

Returns an array of child nodes, including nils in the place of optional nodes that were not present.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 256

def child_nodes
  raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
end

#comment_targets

Returns an array of child nodes and locations that could potentially have comments attached to them.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 277

def comment_targets
  raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
end

#comments

Delegates to the comments of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 133

def comments
  location.comments
end

#compact_child_nodes

Returns an array of child nodes, excluding any nils in the place of optional nodes that were not present.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 271

def compact_child_nodes
  raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
end

#deconstruct

Alias for #child_nodes.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 260

alias deconstruct child_nodes

#deprecated(*replacements)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/node_ext.rb', line 10

def deprecated(*replacements) # :nodoc:
  location = caller_locations(1, 1)
  location = location[0].label if location
  suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }

  warn(<<~MSG, uplevel: 1, category: :deprecated)
    [deprecation]: #{self.class}##{location} is deprecated and will be \
    removed in the next major version. Use #{suggest.join("/")} instead.
    #{(caller(1, 3) || []).join("\n")}
  MSG
end

#each_child_node

With a block given, yields each child node. Without a block, returns an enumerator that contains each child node. Excludes any nils in the place of optional nodes that were not present.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 265

def each_child_node
  raise NoMethodError, "undefined method `each_child_node' for #{inspect}"
end

#end_character_column

Delegates to the end_character_column of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 106

def end_character_column
  location.end_character_column
end

#end_character_offset

Delegates to the end_character_offset of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 74

def end_character_offset
  location.end_character_offset
end

#end_column

Delegates to the end_column of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 96

def end_column
  location.end_column
end

#end_line

Delegates to the end_line of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 50

def end_line
  location.end_line
end

#end_offset

The end offset of the node in the source. This method is effectively a delegate method to the location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 63

def end_offset
  location = @location
  location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
end

#inspect

Returns a string representation of the node.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 282

def inspect
  raise NoMethodError, "undefined method `inspect' for #{inspect}"
end

#leading_comments

Delegates to the leading_comments of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 123

def leading_comments
  location.leading_comments
end

#location

A Location instance that represents the location of this node in the source.

[ GitHub ]

  
# File '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

#newline_flag!(lines)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/prism/parse_result/newlines.rb', line 70

def newline_flag!(lines) # :nodoc:
  line = location.start_line
  unless lines[line]
    lines[line] = true
    @newline_flag = true
  end
end

#pretty_print(q)

Similar to inspect, but respects the current level of indentation given by the pretty print object.

[ GitHub ]

  
# File '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

#save(repository)

Save this node using a saved source so that it can be retrieved later.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 27

def save(repository)
  repository.enter(node_id, :itself)
end

#save_location(repository)

Save the location using a saved source so that it can be retrieved later.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 40

def save_location(repository)
  repository.enter(node_id, :location)
end

#script_lines

Alias for #source_lines.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 144

alias script_lines source_lines

#slice

Slice the location of the node from the source.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 147

def slice
  location.slice
end

#slice_lines

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.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 154

def slice_lines
  location.slice_lines
end

#source_lines Also known as: #script_lines

Returns all of the lines of the source code associated with this node.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 138

def source_lines
  location.source_lines
end

#start_character_column

Delegates to the start_character_column of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 101

def start_character_column
  location.start_character_column
end

#start_character_offset

Delegates to the start_character_offset of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 69

def start_character_offset
  location.start_character_offset
end

#start_column

Delegates to the start_column of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 91

def start_column
  location.start_column
end

#start_line

Delegates to the start_line of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 45

def start_line
  location.start_line
end

#start_offset

The start offset of the node in the source. This method is effectively a delegate method to the location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 56

def start_offset
  location = @location
  location.is_a?(Location) ? location.start_offset : location >> 32
end

#to_dot

Convert this node into a graphviz dot graph string.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 183

def to_dot
  # @type self: node
  DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
end

#trailing_comments

Delegates to the trailing_comments of the associated location object.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 128

def trailing_comments
  location.trailing_comments
end

#tunnel(line, column)

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.

[ GitHub ]

  
# File 'lib/prism/node.rb', line 194

def tunnel(line, column)
  queue = [self] #: Array[Prism::node]
  result = [] #: Array[Prism::node]

  search_offset = source.line_to_byte_offset(line) + column

  while (node = queue.shift)
    result << node

    node.each_child_node do |child_node|
      if child_node.start_offset <= search_offset && search_offset < child_node.end_offset
        queue << child_node
        break
      end
    end
  end

  result
end

#type

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.

Raises:

  • (NoMethodError)
[ GitHub ]

  
# File 'lib/prism/node.rb', line 298

def type
  raise NoMethodError, "undefined method `type' for #{inspect}"
end