class Solargraph::Parser::Rubyvm::NodeChainer


A factory for generating chains from nodes.

def block_passed? node

def block_passed? node
  node.children.last.is_a?(RubyVM::AbstractSyntaxTree::Node) && node.children.last.type == :BLOCK_PASS
end

def chain

Returns:
  • (Source::Chain) -
def chain
  links = generate_links(@node)
  Chain.new(links, @node, (Parser.is_ast_node?(@node) && @node.type == :SPLAT))
end

def chain node, filename = nil, in_block = false

Returns:
  • (Source::Chain) -

Parameters:
  • filename (String) --
  • node (Parser::AST::Node) --
def chain node, filename = nil, in_block = false
  NodeChainer.new(node, filename, in_block).chain
end

def generate_links n

Returns:
  • (Array) -

Parameters:
  • n (Parser::AST::Node) --
def generate_links n
  return [] unless Parser.is_ast_node?(n)
  return generate_links(n.children[2]) if n.type == :SCOPE
  return generate_links(n.children[0]) if n.type == :SPLAT
  result = []
  if n.type == :ITER
    @in_block += 1
    result.concat generate_links(n.children[0])
    @in_block -= 1
  elsif n.type == :CALL || n.type == :OPCALL
    n.children[0..-3].each do |c|
      result.concat generate_links(c)
    end
    result.push Chain::Call.new(n.children[-2].to_s, node_to_argchains(n.children.last), @in_block > 0 || block_passed?(n))
  elsif n.type == :ATTRASGN
    result.concat generate_links(n.children[0])
    result.push Chain::Call.new(n.children[1].to_s, node_to_argchains(n.children[2]), @in_block > 0 || block_passed?(n))
  elsif n.type == :VCALL
    result.push Chain::Call.new(n.children[0].to_s, [], @in_block > 0 || block_passed?(n))
  elsif n.type == :FCALL
    result.push Chain::Call.new(n.children[0].to_s, node_to_argchains(n.children[1]), @in_block > 0 || block_passed?(n))
  elsif n.type == :SELF
    result.push Chain::Head.new('self')
  elsif n.type == :ZSUPER
    result.push Chain::ZSuper.new('super', @in_block > 0 || block_passed?(n))
  elsif n.type == :SUPER
    result.push Chain::Call.new('super', node_to_argchains(n.children.last), @in_block > 0 || block_passed?(n))
  elsif [:COLON2, :COLON3, :CONST].include?(n.type)
    const = unpack_name(n)
    result.push Chain::Constant.new(const)
  elsif [:LVAR, :LASGN, :DVAR].include?(n.type)
    result.push Chain::Call.new(n.children[0].to_s)
  elsif [:IVAR, :IASGN].include?(n.type)
    result.push Chain::InstanceVariable.new(n.children[0].to_s)
  elsif [:CVAR, :CVASGN].include?(n.type)
    result.push Chain::ClassVariable.new(n.children[0].to_s)
  elsif [:GVAR, :GASGN].include?(n.type)
    result.push Chain::GlobalVariable.new(n.children[0].to_s)
  elsif n.type == :OP_ASGN_OR
    result.concat generate_links n.children[2]
  elsif [:class, :module, :def, :defs].include?(n.type)
    # @todo Undefined or what?

    result.push Chain::UNDEFINED_CALL
  elsif n.type == :AND
    result.concat generate_links(n.children.last)
  elsif n.type == :OR
    result.push Chain::Or.new([NodeChainer.chain(n.children[0], @filename), NodeChainer.chain(n.children[1], @filename)])
  elsif n.type == :begin
    result.concat generate_links(n.children[0])
  elsif n.type == :BLOCK_PASS
    result.push Chain::BlockVariable.new("&#{n.children[1].children[0].to_s}")
  else
    lit = infer_literal_node_type(n)
    result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
  end
  result
end

def initialize node, filename = nil, in_block = false

Parameters:
  • filename (String) --
  • node (Parser::AST::Node) --
def initialize node, filename = nil, in_block = false
  @node = node
  @filename = filename
  @in_block = in_block ? 1 : 0
end

def load_string(code)

Returns:
  • (Source::Chain) -

Parameters:
  • code (String) --
def load_string(code)
  node = Parser.parse(code.sub(/\.$/, ''))
  chain = NodeChainer.new(node).chain
  chain.links.push(Chain::Link.new) if code.end_with?('.')
  chain
end

def node_to_argchains node

def node_to_argchains node
  # @todo Process array, splat, argscat

  return [] unless Parser.is_ast_node?(node)
  if [:ZARRAY, :ARRAY, :LIST].include?(node.type)
    node.children[0..-2].map { |c| NodeChainer.chain(c) }
  elsif node.type == :SPLAT
    [NodeChainer.chain(node)]
  elsif node.type == :ARGSCAT
    result = node.children[0].children[0..-2].map { |c| NodeChainer.chain(c) }
    result.push NodeChainer.chain(node.children[1])
    # @todo Smelly instance variable access

    result.last.instance_variable_set(:@splat, true)
    result
  elsif node.type == :BLOCK_PASS
    result = node_to_argchains(node.children[0])
    result.push Chain.new([Chain::BlockVariable.new("&#{node.children[1].children[0].to_s}")])
    result
  else
    []
  end
end