class ParseTree

Constants

NODE_SYMBOLS

Public Class Methods

new(include_newlines = false) click to toggle source
# File lib/parse_tree_reloaded.rb, line 81
def initialize(include_newlines = false)
  @include_newlines = include_newlines
end

Public Instance Methods

parse_tree_for_method(klass, method, is_cls_method = false, newlines = @include_newlines) click to toggle source
# File lib/parse_tree_reloaded.rb, line 85
def parse_tree_for_method(klass, method, is_cls_method = false, newlines = @include_newlines)
  @newlines = newlines
  @locals = []
  @current_sexp = nil
  method = method.to_sym
  id = rb_to_id(method)
  table = RCLASS(klass).m_tbl
  if (r, n = st_lookup(table, id))[0]
    sexp = [:defn, method, to_sexp(n.dereference.to_NODE.nd_body)]
    sexp.extend Sexp
    sexp
  else
    [nil]
  end
end
parse_tree_for_string(string, filename = nil, line = nil, newlines = @include_newlines) click to toggle source
# File lib/parse_tree_reloaded.rb, line 101
def parse_tree_for_string(string, filename = nil, line = nil, newlines = @include_newlines)
  filename ||= '(string)'
  line ||= 1
  @newlines = newlines
  @locals = []
  @current_sexp = nil
  
  node = rb_compile_string(filename, string, line)
  [to_sexp(node)]
end
to_sexp(node) click to toggle source
# File lib/parse_tree_reloaded.rb, line 112
def to_sexp(node)
  return nil if node.nil?
  c_type = nd_type(node)
  type = NODE_SYMBOLS[c_type]
  
  if type == :newline
    if @newlines
      newline_sexp = []
      newline_sexp << :newline      
      newline_sexp << nd_line(node)
      newline_sexp << node.nd_file
      @current_sexp << newline_sexp
    end
    return to_sexp(node.nd_next)
  end
  
  sexp = []
  sexp.extend Sexp
  last_current_sexp = @current_sexp
  @current_sexp = sexp
  sexp << type
  
  #    puts(('  ' * @level) + type.to_s)
  #    @level += 1
  
  case type
  when :block, :array
    begin
      sexp << to_sexp(node.nd_head)
    end while node = node.nd_next
  when :method
  when :fbody
  when :cfunc
  when :scope
    locals_before = @locals
    @locals = node.nd_tbl
    nd_next = node.nd_next
    sexp << to_sexp(nd_next) unless nd_next.nil?
    @locals = locals_before
  when :if
    sexp << to_sexp(node.nd_cond)
    sexp << to_sexp(node.nd_body)
    sexp << to_sexp(node.nd_else)
  when :case
    sexp << to_sexp(node.nd_head)
    child = node.nd_body
    loop do
      child_sexp = to_sexp(child)
      sexp << child_sexp
      if child_sexp[0] == :when #when clause
        child = child.nd_next
        if child.nil? #no else clause used
          sexp << nil
          break
        end
      else #else clause
        break
      end
    end
  when :when
    #    if (!case_level) { /* when without case, ie, no expr in case */
    #      rb_ary_pop(ary); /* reset what current is pointing at */
    #      node = NEW_CASE(0, node);
    #      goto again;
    #    }
    sexp << to_sexp(node.nd_head)
    sexp << to_sexp(node.nd_body)
  when :while, :until
    sexp << to_sexp(node.nd_cond)
    sexp << to_sexp(node.nd_body)
    sexp << !node.nd_3rd.nil?
  when :iter, :for
    sexp << to_sexp(node.nd_iter)
    #            if (node->nd_var != (NODE *)1
    #        && node->nd_var != (NODE *)2
    #        && node->nd_var != NULL) {
    if node.nd_var
      sexp << to_sexp(node.nd_var)
    else
      sexp << nil
    end
    sexp << to_sexp(node.nd_body)
  when :break, :next, :return, :yield
    stts = node.nd_stts
    sexp << to_sexp(stts) unless stts.nil?
  when :begin, :opt_n, :not
    sexp << to_sexp(node.nd_body)
  when :rescue
    sexp << to_sexp(node.nd_1st)
    sexp << to_sexp(node.nd_2nd)
    nd_3rd = node.nd_3rd
    sexp << to_sexp(nd_3rd) unless nd_3rd.nil?
  when :resbody
    sexp << to_sexp(node.nd_3rd)
    nd_2nd = node.nd_2nd
    sexp << to_sexp(nd_2nd) unless nd_2nd.nil?
    nd_1st = node.nd_1st
    sexp << to_sexp(nd_1st) unless nd_1st.nil?
  when :ensure
    sexp << to_sexp(node.nd_head)
    ensr = node.nd_ensr
    sexp << zo_sexp(ensr) unless ensr.nil?
  when :and, :or
    sexp << to_sexp(node.nd_1st)
    sexp << to_sexp(node.nd_2nd)
  when :masgn
    sexp << to_sexp(node.nd_head)
    args = node.nd_args
    sexp << to_sexp(args) unless args.nil?
    value = node.nd_value
    sexp << to_sexp(node.nd_value) unless value.nil?
  when :lasgn, :dasgn, :dasgn_curr, :gasgn, :iasgn, :cdecl, :cvasgn, :cvdecl
    sexp << ID2SYM(node.nd_vid)
    value = node.nd_value
    sexp << to_sexp(value) unless value.nil?
  when :op_asgn1
  when :op_asgn2
  when :op_asgn_and, :op_asgn_or
    sexp << to_sexp(node.nd_head)
    sexp << to_sexp(node.nd_value)
  when :call, :fcall, :vcall
    sexp << to_sexp(node.nd_recv) if type == :call
    sexp << ID2SYM(node.nd_mid)
    if type == :call || type == :fcall
      args = node.nd_args
      sexp << to_sexp(args) if args
    end
  when :super
    
  when :hash
    list = node.nd_head
    while list
      sexp << to_sexp(list.nd_head)
      list = list.nd_next
      raise "ParseTree error: Odd number list for Hash" if list.nil?
      sexp << to_sexp(list.nd_head)
      list = list.nd_next
    end
  when :lvar, :dvar, :gvar, :ivar, :const, :cvar, :attrset
    sexp << ID2SYM(node.nd_vid)
  when :nth_ref
    sexp << node.nd_nth
  when :back_ref
  when :match
  when :match2, :match3
    sexp << to_sexp(node.nd_recv)
    sexp << to_sexp(node.nd_value)
  when :lit, :str, :xstr
    sexp << node.nd_lit
  when :dstr, :dxstr, :dregx, :dregx_once, :dsym
    sexp << node.nd_lit
    list = node.nd_next
    while list
      head = list.nd_head
      if head
        child_sexp = to_sexp(head)
        child_sexp = child_sexp[1] if child_sexp[0] == :evstr
        sexp << child_sexp
      end
      list = list.nd_next
    end
  when :evstr
    sexp << to_sexp(node.nd_body)
  when :args
    arg_flag = node.nd_rest
    if @locals
      #regular args
      i = 0
      while i < node.nd_cnt do
        sexp << ID2SYM(@locals[i + 3])
        i += 1
      end
      #optional args
      optnode = node.nd_opt
      while optnode do
        sexp << ID2SYM(@locals[i + 3])
        i += 1
        optnode = optnode.nd_next
      end
      #special args
      case
      when arg_flag > 0: sexp << "*#{locals[i + 3].to_s}".to_sym #*arg
      when arg_flag == 0: #empty list
      when arg_flag == -1: #all handled above
      when arg_flag == -2: #no name
      else raise "ParseTree error: Unknown arg flag #{arg_flag}"
      end
      #assigns of optional args
      opt = node.nd_opt;
      if opt
        sexp << to_sexp(opt)
      end
    end
  when :argscat, :argspush
    sexp << to_sexp(node.nd_head)
    sexp << to_sexp(node.nd_body)
  when :splat, :to_ary, :svalue
    sexp << to_sexp(node.nd_head)
  when :block_arg
    sexp << ID2SYM(node.nd_u1id)
  when :block_pass
    sexp << to_sexp(node.nd_body)
    sexp << to_sexp(node.nd_iter)
  when :defn, :defs
    defn = node.nd_defn
    if defn
      sexp << to_sexp(node.nd_recv) if type == :defs
      sexp << ID2SYM(node.nd_mid)
      sexp << to_sexp(defn)
    end
  when :alias
  when :valias
  when :undef
  when :class, :module
    sexp << ID2SYM(node.nd_cpath.nd_mid)
    sexp << to_sexp(node.nd_super) if type == :class
    sexp << to_sexp(node.nd_body)
  when :sclass
  when :colon2
  when :colon3
  when :cref
  when :dot2
  when :dot3
  when :flip2
  when :flip3
  when :defined
  when :postexe
  when :alloca
  when :dmethod
  when :bmethod
    block = DATA_PTR(node.nd_cval).to_struct_BLOCK
    var = block.var
    sexp << to_sexp(var) unless var.nil?
    sexp << to_sexp(block.body)
  when :memo
  when :ifunc
  when :attrasgn
    nd_1st = node.nd_1st
    if nd_1st == RNODE(1)
      sexp << to_sexp(NEW_SELF())
    else
      sexp << to_sexp(nd_1st)
    end
    sexp << ID2SYM(node.nd_u2id)
    sexp << to_sexp(node.nd_3rd)
  when :last
  when :retry, :redo, :self, :nil, :true, :false, :zsuper, :zarray
    # empty nodes
  when :last
    raise "ParseTree error: Unsupported node type '#{type}'"
  else
    raise "ParseTree error: Unknown node type '#{c_type}'"
  end
  
  #    @level -= 1
  #    puts(('  ' * @level) + type.to_s + ' end')
  
  @current_sexp = last_current_sexp
  sexp
end