module ReplTypeCompletor

Constants

VERSION

Attributes

last_completion_error[R]

Public Class Methods

analyze(code, binding:, filename: nil) click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 31
def analyze(code, binding:, filename: nil)
  verbose, $VERBOSE = $VERBOSE, nil
  result = analyze_code(code, binding)
  Result.new(result, binding, filename) if result
rescue Exception => e
  handle_exception(e)
  nil
ensure
  $VERBOSE = verbose
end
handle_exception(e) click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 42
def handle_exception(e)
  @last_completion_error = e
end
info() click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 46
def info
  require 'rbs'
  prism_info = "Prism: #{Prism::VERSION}"
  rbs_info = "RBS: #{RBS::VERSION}"
  if rbs_load_error
    rbs_info << " #{rbs_load_error.inspect}"
  elsif !rbs_load_started?
    rbs_info << ' signatures not loaded'
  elsif !rbs_loaded?
    rbs_info << ' signatures loading'
  end
  "ReplTypeCompletor: #{VERSION}, #{prism_info}, #{rbs_info}"
end
load_rbs() click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 23
def load_rbs
  Types.load_rbs_builder unless rbs_loaded?
end
preload_rbs() click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 27
def preload_rbs
  Types.preload_rbs_builder
end
rbs_load_error() click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 11
def rbs_load_error
  Types.rbs_load_error
end
rbs_load_started?() click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 15
def rbs_load_started?
  Types.rbs_load_started?
end
rbs_loaded?() click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 19
def rbs_loaded?
  !!Types.rbs_builder
end

Private Class Methods

analyze_code(code, binding = Object::TOPLEVEL_BINDING) click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 62
def analyze_code(code, binding = Object::TOPLEVEL_BINDING)
  ast = Prism.parse(code, scopes: [binding.local_variables]).value
  *parents, target_node = find_target ast, code.bytesize
  return unless target_node

  calculate_scope = -> { TypeAnalyzer.calculate_target_type_scope(binding, parents, target_node).last }
  calculate_type_scope = ->(node) { TypeAnalyzer.calculate_target_type_scope binding, [*parents, target_node], node }

  case target_node
  when Prism::StringNode
    return unless target_node.closing&.empty?

    call_node, args_node = parents.last(2)
    return unless call_node.is_a?(Prism::CallNode) && call_node.receiver.nil?
    return unless args_node.is_a?(Prism::ArgumentsNode) && args_node.arguments.size == 1

    if call_node.name == :require || call_node.name == :require_relative
      [call_node.name, target_node.content]
    end
  when Prism::SymbolNode
    return unless !target_node.closing || target_node.closing.empty?

    name = target_node.value.to_s
    if parents.last.is_a? Prism::BlockArgumentNode # method(&:target)
      receiver_type, _scope = calculate_type_scope.call target_node
      [:call, name, receiver_type, false]
    else
      [:symbol, name] unless name.empty?
    end
  when Prism::CallNode, Prism::CallTargetNode
    return if target_node.is_a?(Prism::CallNode) && target_node.opening

    name = target_node.message.to_s
    return [:lvar_or_method, name, calculate_scope.call] if target_node.receiver.nil?

    self_call = target_node.receiver.is_a? Prism::SelfNode
    op = target_node.call_operator
    receiver_type, _scope = calculate_type_scope.call target_node.receiver
    receiver_type = receiver_type.nonnillable if op == '&.'
    [op == '::' ? :call_or_const : :call, name, receiver_type, self_call]
  when Prism::LocalVariableReadNode, Prism::LocalVariableTargetNode
    [:lvar_or_method, target_node.name.to_s, calculate_scope.call]
  when Prism::ConstantPathNode, Prism::ConstantPathTargetNode
    name = target_node.name.to_s
    if target_node.parent # A::B
      receiver, scope = calculate_type_scope.call(target_node.parent)
      [:const, name, receiver, scope]
    else # ::A
      scope = calculate_scope.call
      [:const, name, Types::SingletonType.new(Object), scope]
    end
  when Prism::ConstantReadNode, Prism::ConstantTargetNode
    [:const, target_node.name.to_s, nil, calculate_scope.call]
  when Prism::GlobalVariableReadNode, Prism::GlobalVariableTargetNode
    [:gvar, target_node.name.to_s, calculate_scope.call]
  when Prism::InstanceVariableReadNode, Prism::InstanceVariableTargetNode
    [:ivar, target_node.name.to_s, calculate_scope.call]
  when Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
    [:cvar, target_node.name.to_s, calculate_scope.call]
  end
end
find_target(node, position) click to toggle source
# File repl_type_completor-0.1.7/lib/repl_type_completor.rb, line 124
def find_target(node, position)
  # Skip because NumberedParametersNode#location gives location of whole block
  return if node.is_a? Prism::NumberedParametersNode

  node.compact_child_nodes.each do |n|
    match = find_target(n, position)
    next unless match

    match.unshift node
    return match
  end

  [node] if node.location.end_offset == position
end