Class: RawParseTree

Inherits:
Object
  • Object
show all
Defined in:
lib/parse_tree.rb

Overview

ParseTree is a RubyInline-style extension that accesses and traverses the internal parse tree created by ruby.

class Example
  def blah
    return 1 + 1
  end
end

ParseTree.new.parse_tree(Example)
=> [[:class, :Example, :Object,
       [:defn,
         "blah",
         [:scope,
           [:block,
             [:args],
             [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]

Direct Known Subclasses

ParseTree

Constant Summary collapse

VERSION =
'3.0.8'
NODE_NAMES =
[
 #  00
 :method, :fbody, :cfunc, :scope, :block,
 :if, :case, :when, :opt_n, :while,
 #  10
 :until, :iter, :for, :break, :next,
 :redo, :retry, :begin, :rescue, :resbody,
 #  20
 :ensure, :and, :or, :not, :masgn,
 :lasgn, :dasgn, :dasgn_curr, :gasgn, :iasgn,
 #  30
 :cdecl, :cvasgn, :cvdecl, :op_asgn1, :op_asgn2,
 :op_asgn_and, :op_asgn_or, :call, :fcall, :vcall,
 #  40
 :super, :zsuper, :array, :zarray, :hash,
 :return, :yield, :lvar, :dvar, :gvar,
 #  50
 :ivar, :const, :cvar, :nth_ref, :back_ref,
 :match, :match2, :match3, :lit, :str,
 #  60
 :dstr, :xstr, :dxstr, :evstr, :dregx,
 :dregx_once, :args, :argscat, :argspush, :splat,
 #  70
 :to_ary, :svalue, :block_arg, :block_pass, :defn,
 :defs, :alias, :valias, :undef, :class,
 #  80
 :module, :sclass, :colon2, :colon3, :cref,
 :dot2, :dot3, :flip2, :flip3, :attrset,
 #  90
 :self, :nil, :true, :false, :defined,
 #  95
 :newline, :postexe, :alloca, :dmethod, :bmethod,
 # 100
 :memo, :ifunc, :dsym, :attrasgn,
 :last
]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(include_newlines = $DEBUG) ⇒ RawParseTree

Initializes a ParseTree instance. Includes newline nodes if include_newlines which defaults to $DEBUG.



82
83
84
# File 'lib/parse_tree.rb', line 82

def initialize(include_newlines=$DEBUG)
  @include_newlines = include_newlines
end

Class Method Details

.has_allocaObject



191
192
193
# File 'lib/parse_tree.rb', line 191

def self.has_alloca
  true
end

.translate(klass_or_str, method = nil) ⇒ Object

Front end translation method.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/parse_tree.rb', line 51

def self.translate(klass_or_str, method=nil)
  pt = self.new(false)
  case klass_or_str
  when String then
    sexp = pt.parse_tree_for_string(klass_or_str).first
    if method then
      # class, scope, block, *methods
      sexp.last.last[1..-1].find do |defn|
        defn[1] == method
      end
    else
      sexp
    end
  else
    unless method.nil? then
      if method.to_s =~ /^self\./ then
        method = method.to_s[5..-1].intern
        pt.parse_tree_for_method(klass_or_str, method, true)
      else
        pt.parse_tree_for_method(klass_or_str, method)
      end
    else
      pt.parse_tree(klass_or_str).first
    end
  end
end

Instance Method Details

#parse_tree(*klasses) ⇒ Object

Main driver for ParseTree. Returns an array of arrays containing the parse tree for klasses.

Structure:

[[:class, classname, superclassname, [:defn :method1, ...], ...], ...]

NOTE: v1.0 - v1.1 had the signature (klass, meth=nil). This wasn’t used much at all and since parse_tree_for_method already existed, it was deemed more useful to expand this method to do multiple classes.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/parse_tree.rb', line 99

def parse_tree(*klasses)
  result = []
  klasses.each do |klass|
    klassname = klass.name rescue '' # HACK klass.name should never be nil
                                 # Tempfile's DelegateClass(File) seems to
                                 # cause this
    klassname = "UnnamedClass_#{klass.object_id}" if klassname.empty?
    klassname = klassname.to_sym

    code = if Class === klass then
             sc = klass.superclass
             sc_name = ((sc.nil? or sc.name.empty?) ? "nil" : sc.name).intern
             [:class, klassname, [:const, sc_name]]
           else
             [:module, klassname]
           end

    method_names = []
    method_names += klass.instance_methods false
    method_names += klass.private_instance_methods false
    # protected methods are included in instance_methods, go figure!

    method_names.sort.each do |m|
      r = parse_tree_for_method(klass, m.to_sym)
      code << r
    end

    mods = klass.modules
    mods -= mods.map { |mod| mod.modules }.flatten

    mods.each do |mod| # TODO: add a test for this damnit
      code << process("include #{mod}")
    end

    klass.singleton_methods(false).sort.each do |m|
      code << parse_tree_for_method(klass, m.to_sym, true)
    end

    result << code
  end
  return result
end

#parse_tree_for_method(klass, method, is_cls_meth = false, verbose = true) ⇒ Object

Returns the parse tree for just one method of a class klass.

Format:

[:defn, :name, :body]


149
150
151
152
153
154
155
156
# File 'lib/parse_tree.rb', line 149

def parse_tree_for_method(klass, method, is_cls_meth=false, verbose = true)
  $stderr.puts "** parse_tree_for_method(#{klass}, #{method}):" if $DEBUG
  old_verbose, $VERBOSE = $VERBOSE, verbose
  r = parse_tree_for_meth(klass, method.to_sym, is_cls_meth)
  r
ensure
  $VERBOSE = old_verbose
end

#parse_tree_for_str0(*__1args2__) ⇒ Object

:nodoc:



173
174
175
# File 'lib/parse_tree.rb', line 173

def parse_tree_for_str0(*__1args2__) # :nodoc:
  parse_tree_for_str(*__1args2__)    # just helps clean up the binding
end

#parse_tree_for_string(source, filename = '(string)', line = 1, verbose = true) ⇒ Object

Returns the parse tree for a string source.

Format:

[[sexps] ... ]


165
166
167
168
169
170
171
# File 'lib/parse_tree.rb', line 165

def parse_tree_for_string(source,
                          filename = '(string)', line = 1, verbose = true)
  old_verbose, $VERBOSE = $VERBOSE, verbose
  return parse_tree_for_str0(source, filename, line)
ensure
  $VERBOSE = old_verbose
end