123456789_123456789_123456789_123456789_123456789_

Class: SyntaxSuggest::Visitor

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Prism::Visitor
Instance Chain:
self, Prism::Visitor
Inherits: Prism::Visitor
  • Object
Defined in: lib/syntax_suggest/visitor.rb

Overview

Walks the Prism AST to extract structural info that cannot be reliably determined from tokens alone.

Such as the location of lines that must be logically joined so the search algorithm will treat them as one. Example:

source = <<~RUBY
User                        # 1
  .where(name: "Earlopain") # 2
  .first                    # 3
RUBY
ast, _tokens = Prism.parse_lex(source).value
visitor = Visitor.new
visitor.visit(ast)
visitor.consecutive_lines # => Set[2, 1]

This output means that line 1 and line 2 need to be joined with their next line.

And determining the location of "endless" method definitions. For example:

source = <<~RUBY
def cube(x)
  x * x * x
end
def square(x) = x * x # 1
RUBY

ast, _tokens = Prism.parse_lex(source).value
visitor = Visitor.new
visitor.visit(ast)
visitor.endless_def_keyword_offsets # => Set[28]

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.newVisitor

[ GitHub ]

  
# File 'lib/syntax_suggest/visitor.rb', line 38

def initialize
  @endless_def_keyword_offsets = Set.new
  @consecutive_lines = Set.new
end

Instance Attribute Details

#consecutive_lines (readonly)

[ GitHub ]

  
# File 'lib/syntax_suggest/visitor.rb', line 36

attr_reader :endless_def_keyword_offsets, :consecutive_lines

#endless_def_keyword_offsets (readonly)

[ GitHub ]

  
# File 'lib/syntax_suggest/visitor.rb', line 36

attr_reader :endless_def_keyword_offsets, :consecutive_lines

Instance Method Details

#visit_call_node(node)

Called by Prism::Visitor for every method-call node in the AST (e.g. foo.bar, foo.bar.baz).

[ GitHub ]

  
# File 'lib/syntax_suggest/visitor.rb', line 45

def visit_call_node(node)
  receiver_loc = node.receiver&.location
  call_operator_loc = node.call_operator_loc
  message_loc = node.message_loc
  if receiver_loc && call_operator_loc && message_loc
    # dot-leading (dot on the next line)
    #   foo        # line 1 - consecutive
    #     .bar     # line 2
    if receiver_loc.end_line != call_operator_loc.start_line && call_operator_loc.start_line == message_loc.start_line
      (receiver_loc.end_line..call_operator_loc.start_line - 1).each do |line|
        @consecutive_lines << line
      end
    end

    # dot-trailing (dot on the same line as the receiver)
    #   foo.       # line 1 - consecutive
    #     bar      # line 2
    if receiver_loc.end_line == call_operator_loc.start_line && call_operator_loc.start_line != message_loc.start_line
      (call_operator_loc.start_line..message_loc.start_line - 1).each do |line|
        @consecutive_lines << line
      end
    end
  end
  super
end

#visit_def_node(node)

Called by Prism::Visitor for every def node in the AST. Records the keyword start location for endless method definitions like def foo = 123. These are valid without a matching end, so Token must exclude them when deciding if a line is a keyword.

[ GitHub ]

  
# File 'lib/syntax_suggest/visitor.rb', line 75

def visit_def_node(node)
  @endless_def_keyword_offsets << node.def_keyword_loc.start_offset if node.equal_loc
  super
end