class AbstractSyntaxTreeKit

Constants

HashElement
VERSION

Public Class Methods

parse(src) click to toggle source
# File lib/astkit.rb, line 100
def self.parse(src)
  root = RubyVM::AbstractSyntaxTree.parse(src)
  new.traverse(root)
end
walk(node) { |node| ... } click to toggle source
# File lib/astkit.rb, line 105
def self.walk(node, &block)
  yield node

  case node.type
  when :SCOPE
    if node.body.instance_of?(Array)
      node.body.each do |child|
        walk(child, &block)
      end
    else
      walk(node.body, &block)
    end
  when :FCALL
    walk(node.arguments, &block)
  when :ARRAY
  when :ZARRAY
  when :LIT
  when :STR
  when :ARGS
  else
    raise "Unexpected node type[#{node.type}]"
  end
end

Public Instance Methods

traverse(node) click to toggle source
# File lib/astkit.rb, line 129
def traverse(node)
  return node unless node.instance_of?(RubyVM::AbstractSyntaxTree::Node)

  case node.type
  when :SCOPE
    Node::SCOPE.new(
      node: node,
      local_table: node.children[0],
      arguments: traverse(node.children[1]),
      body: body(node.children[2])
    )
  when :ARRAY
    Node::ARRAY.new(
      node: node,
      elements: elements(node)
    )
  when :ZARRAY
    Node::ZARRAY.new(node: node)
  when :STR
    Node::STR.new(
      node: node,
      value: node.children[0]
    )
  when :FCALL
    Node::FCALL.new(
      node: node,
      method_id: node.children[0],
      arguments: traverse(node.children[1])
    )
  when :LIT
    Node::LIT.new(
      node: node,
      value: node.children[0]
    )
  when :DEFN
    Node::DEFN.new(
      node: node,
      method_id: node.children[0],
      method_definition: traverse(node.children[1])
    )
  when :KW_ARG
    Node::KW_ARG.new(
      node: node,
      body: traverse(node.children[0]),
      next_keyword_argument: traverse(node.children[1])
    )
  when :LASGN
    Node::LASGN.new(
      node: node,
      name: node.children[0],
      value: traverse(node.children[1])
    )
  when :ARGS
    Node::ARGS.new(
      node: node,
      parameter_count: node.children[0],
      rest_argument: node.children[6],
      keyword_arguments: traverse(node.children[7]),
      block_argument: node.children[9]
    )
  when :CDECL
    if node.children[1].instance_of?(Symbol)
      Node::CDECL.new(
        node: node,
        extension: traverse(node.children[0]),
        name: node.children[1],
        value: traverse(node.children[2])
      )
    else
      Node::CDECL.new(
        node: node,
        name: node.children[0],
        value: traverse(node.children[1])
      )
    end
  when :COLON2
    Node::COLON2.new(
      node: node,
      receiver: traverse(node.children[0]),
      name: node.children[1]
    )
  when :COLON3
    Node::COLON3.new(
      node: node,
      name: node.children[0]
    )
  when :CONST
    Node::CONST.new(
      node: node,
      name: node.children[0]
    )
  when :CALL
    Node::CALL.new(
      node: node,
      receiver: traverse(node.children[0]),
      method_id: node.children[1],
      arguments: traverse(node.children[2])
    )
  when :OPCALL
    opcall(node)
  when :HASH
    hash(node)
  when :NIL
    Node::NIL.new(node: node)
  when :TRUE
    Node::TRUE.new(node: node)
  when :FALSE
    Node::FALSE.new(node: node)
  when :OR
    Node::OR.new(
      node: node,
      left: traverse(node.children[0]),
      right: traverse(node.children[1])
    )
  when :AND
    Node::AND.new(
      node: node,
      left: traverse(node.children[0]),
      right: traverse(node.children[1])
    )
  when :LVAR
    Node::LVAR.new(
      node: node,
      name: node.children[0]
    )
  when :IF
    Node::IF.new(
      node: node,
      condition: traverse(node.children[0]),
      body: traverse(node.children[1]),
      els: traverse(node.children[2])
    )
  when :UNLESS
    Node::UNLESS.new(
      node: node,
      condition: traverse(node.children[0]),
      body: traverse(node.children[1]),
      els: traverse(node.children[2])
    )
  when :CASE
    Node::CASE.new(
      node: node,
      expression: traverse(node.children[0]),
      case_clauses: case_clauses(node.children[1])
    )
  when :CASE2
    Node::CASE2.new(
      node: node,
      case_clauses: case_clauses(node.children[1])
    )
  when :WHEN
    if node.children[2]&.type == :WHEN
      Node::WHEN.new(
        node: node,
        expressions: traverse(node.children[0]),
        body: traverse(node.children[1])
      )
    else
      Node::WHEN.new(
        node: node,
        expressions: traverse(node.children[0]),
        body: traverse(node.children[1]),
        els: traverse(node.children[2])
      )
    end
  when :FOR
    Node::FOR.new(
      node: node,
      receiver: traverse(node.children[0]),
      body: traverse(node.children[1])
    )
  when :VCALL
    vcall(node)
  when :BEGIN
    nbegin(node)
  when :ITER
    Node::ITER.new(
      node: node,
      receiver: traverse(node.children[0]),
      body: traverse(node.children[1])
    )
  when :DVAR
    dvar(node)
  when :BLOCK
    block(node)
  when :DOT2
    Node::DOT2.new(
      node: node,
      nd_begin: traverse(node.children[0]),
      nd_end: traverse(node.children[1])
    )
  when :DOT3
    Node::DOT3.new(
      node: node,
      nd_begin: traverse(node.children[0]),
      nd_end: traverse(node.children[1])
    )
  when :MASGN
    Node::MASGN.new(
      node: node,
      rhs: traverse(node.children[0]),
      lhs: traverse(node.children[1]),
      splat: traverse(node.children[2])
    )
  when :WHILE
    Node::WHILE.new(
      node: node,
      condition: traverse(node.children[0]),
      body: traverse(node.children[1])
    )
  when :UNTIL
    Node::UNTIL.new(
      node: node,
      condition: traverse(node.children[0]),
      body: traverse(node.children[1])
    )
  when :BREAK
    Node::BREAK.new(node: node)
  when :NEXT
    Node::NEXT.new(node: node)
  when :REDO
    Node::REDO.new(node: node)
  when :RETRY
    Node::RETRY.new(node: node)
  when :RESCUE
    Node::RESCUE.new(
      node: node,
      body: traverse(node.children[0]),
      rescue_body: traverse(node.children[1]),
      else_body: traverse(node.children[2])
    )
  when :RESBODY
    Node::RESBODY.new(
      node: node,
      exceptions: traverse(node.children[0]),
      clause: traverse(node.children[1]),
      next_rescue: traverse(node.children[2])
    )
  when :ERRINFO
    Node::ERRINFO.new(node: node)
  when :ENSURE
    Node::ENSURE.new(
      node: node,
      body: traverse(node.children[0]),
      clause: traverse(node.children[1])
    )
  when :GASGN
    Node::GASGN.new(
      node: node,
      name: node.children[0],
      value: traverse(node.children[1])
    )
  when :MODULE
    Node::MODULE.new(
      node: node,
      path: traverse(node.children[0]),
      body: traverse(node.children[1])
    )
  when :CLASS
    Node::CLASS.new(
      node: node,
      path: traverse(node.children[0]),
      superclass: traverse(node.children[1]),
      body: traverse(node.children[2])
    )
  when :IASGN
    Node::IASGN.new(
      node: node,
      name: node.children[0],
      value: traverse(node.children[1])
    )
  when :CVASGN
    Node::CVASGN.new(
      node: node,
      name: node.children[0],
      value: traverse(node.children[1])
    )
  when :FLIP2
    Node::FLIP2.new(
      node: node,
      nd_begin: traverse(node.children[0]),
      nd_end: traverse(node.children[1])
    )
  when :FLIP3
    Node::FLIP3.new(
      node: node,
      nd_begin: traverse(node.children[0]),
      nd_end: traverse(node.children[1])
    )
  when :SELF
    Node::SELF.new(node: node)
  when :GVAR
    Node::GVAR.new(
      node: node,
      name: node.children[0]
    )
  when :IVAR
    Node::IVAR.new(
      node: node,
      name: node.children[0]
    )
  when :CVAR
    Node::CVAR.new(
      node: node,
      name: node.children[0]
    )
  when :NTH_REF
    Node::NTH_REF.new(
      node: node,
      name: node.children[0]
    )
  when :BACK_REF
    Node::BACK_REF.new(
      node: node,
      name: node.children[0]
    )
  when :QCALL
    Node::QCALL.new(
      node: node,
      receiver: traverse(node.children[0]),
      method_id: node.children[1],
      arguments: traverse(node.children[2])
    )
  when :ZSUPER
    Node::ZSUPER.new(node: node)
  when :SUPER
    Node::SUPER.new(
      node: node,
      arguments: traverse(node.children[0])
    )
  when :LAMBDA
    Node::LAMBDA.new(
      node: node,
      body: traverse(node.children[0])
    )
  when :ATTRASGN
    Node::ATTRASGN.new(
      node: node,
      receiver: traverse(node.children[0]),
      method_id: node.children[1],
      arguments: traverse(node.children[2])
    )
  when :DSYM
    Node::DSYM.new(
      node: node,
      interpolation: traverse(node.children[0]),
      tail_str: traverse(node.children[1])
    )
  when :DSTR
    Node::DSTR.new(
      node: node,
      pre_str: node.children[0],
      interpolation: traverse(node.children[1]),
      tail_str: traverse(node.children[2])
    )
  when :EVSTR
    Node::EVSTR.new(
      node: node,
      body: traverse(node.children[0])
    )
  when :DEFINED
    Node::DEFINED.new(
      node: node,
      expression: traverse(node.children[0])
    )
  when :SCLASS
    Node::SCLASS.new(
      node: node,
      receiver: traverse(node.children[0]),
      body: traverse(node.children[1])
    )
  when :MATCH
    Node::MATCH.new(
      node: node,
      value: traverse(node.children[0])
    )
  when :MATCH2
    Node::MATCH2.new(
      node: node,
      regexp: traverse(node.children[0]),
      string: traverse(node.children[1])
    )
  when :MATCH3
    Node::MATCH3.new(
      node: node,
      regexp: traverse(node.children[0]),
      string: traverse(node.children[1])
    )
  when :XSTR
    Node::XSTR.new(
      node: node,
      value: node.children[0]
    )
  when :RETURN
    Node::RETURN.new(node: node)
  when :VALUES
    Node::VALUES.new(
      node: node,
      elements: elements(node)
    )
  when :YIELD
    Node::YIELD.new(node: node)
  when :DASGN
    Node::DASGN.new(
      node: node,
      name: node.children[0],
      value: traverse(node.children[1])
    )
  when :DASGN_CURR
    Node::DASGN_CURR.new(
      node: node,
      name: node.children[0],
      value: traverse(node.children[1])
    )
  when :OP_ASGN1
    Node::OP_ASGN1.new(
      node: node,
      receiver: traverse(node.children[0]),
      operator: node.children[1],
      index: traverse(node.children[2]),
      value: traverse(node.children[3])
    )
  when :OP_ASGN2
    # p node.children
  when :OP_ASGN_AND
    Node::OP_ASGN_AND.new(
      node: node,
      variable: traverse(node.children[0]),
      value: traverse(node.children[2])
    )
  when :OP_ASGN_OR
    Node::OP_ASGN_OR.new(
      node: node,
      variable: traverse(node.children[0]),
      value: traverse(node.children[2])
    )
  when :OP_CDECL
    Node::OP_CDECL.new(
      node: node,
      namespace: traverse(node.children[0]),
      operator: node.children[1],
      value: traverse(node.children[2])
    )
  when :DXSTR
    Node::DXSTR.new(
      node: node,
      pre_str: node.children[0],
      interpolation: traverse(node.children[1]),
      tail_str: traverse(node.children[2])
    )
  when :ONCE
    Node::ONCE.new(
      node: node,
      body: traverse(node.children[0])
    )
  when :DREGX
    Node::DREGX.new(
      node: node,
      interpolation: traverse(node.children[0]),
      tail_str: traverse(node.children[1])
    )
  when :UNDEF
    Node::UNDEF.new(
      node: node,
      old_name: traverse(node.children[0])
    )
  when :VALIAS
    Node::VALIAS.new(
      node: node,
      new_name: node.children[0],
      old_name: node.children[1]
    )
  when :ALIAS
    Node::VALIAS.new(
      node: node,
      new_name: traverse(node.children[0]),
      old_name: traverse(node.children[1])
    )
  when :DEFS
    Node::DEFS.new(
      node: node,
      receiver: traverse(node.children[0]),
      name: node.children[1],
      body: traverse(node.children[2])
    )
  when :SPLAT
    Node::SPLAT.new(
      node: node,
      element: traverse(node.children[0])
    )
  when :ARGSPUSH
    Node::ARGSPUSH.new(
      node: node,
      array: traverse(node.children[0]),
      element: traverse(node.children[1])
    )
  else
    raise "Unexpected node type[#{node.type}]"
  end
end

Private Instance Methods

block(node) click to toggle source
# File lib/astkit.rb, line 669
def block(node)
  Node::BLOCK.new(
    node: node,
    statements: statements(node.children)
  )
end
body(node) click to toggle source
# File lib/astkit.rb, line 676
def body(node)
  traverse(node)
end
case_clauses(node) click to toggle source
# File lib/astkit.rb, line 694
def case_clauses(node)
  list = [traverse(node)]

  if node.children[2]&.type == :WHEN
    list << case_clauses(node.children[2])
  end

  list.flatten
end
dvar(node) click to toggle source
# File lib/astkit.rb, line 662
def dvar(node)
  Node::DVAR.new(
    node: node,
    name: node.children[0]
  )
end
elements(node) click to toggle source
# File lib/astkit.rb, line 680
def elements(node)
  node.children[0..-2].map { |child| traverse(child) }
end
hash(node) click to toggle source
# File lib/astkit.rb, line 641
def hash(node)
  Node::HASH.new(
    node: node,
    elements: hash_elements(node.children[0])
  )
end
hash_elements(node) click to toggle source
# File lib/astkit.rb, line 684
def hash_elements(node)
  node.children[0..-2].each_slice(2).map do |key_node, value_node|
    HashElement.new(traverse(key_node), traverse(value_node))
  end
end
nbegin(node) click to toggle source
# File lib/astkit.rb, line 655
def nbegin(node)
  Node::NBEGIN.new(
    node: node,
    body: traverse(node.children[0])
  )
end
opcall(node) click to toggle source
# File lib/astkit.rb, line 632
def opcall(node)
  Node::OPCALL.new(
    node: node,
    receiver: traverse(node.children[0]),
    method_id: node.children[1],
    arguments: traverse(node.children[2])
  )
end
statements(list) click to toggle source
# File lib/astkit.rb, line 690
def statements(list)
  list.map { |l| traverse(l) }
end
vcall(node) click to toggle source
# File lib/astkit.rb, line 648
def vcall(node)
  Node::VCALL.new(
    node: node,
    name: node.children[0]
  )
end