ParseTree 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +19 -0
- data/Makefile +24 -7
- data/Manifest.txt +12 -10
- data/ParseTree.gemspec +39 -0
- data/README.txt +1 -1
- data/bin/parse_tree_abc +86 -0
- data/bin/parse_tree_deps +66 -0
- data/bin/parse_tree_show +49 -0
- data/lib/composite_sexp_processor.rb +43 -0
- data/{parse_tree.rb → lib/parse_tree.rb} +104 -32
- data/{sexp_processor.rb → lib/sexp_processor.rb} +89 -19
- data/{something.rb → test/something.rb} +0 -0
- data/test/test_all.rb +13 -0
- data/{test_composite_sexp_processor.rb → test/test_composite_sexp_processor.rb} +0 -0
- data/test/test_parse_tree.rb +275 -0
- data/{test_sexp_processor.rb → test/test_sexp_processor.rb} +0 -9
- metadata +22 -16
- data/composite_sexp_processor.rb +0 -24
- data/parse_tree_abc +0 -62
- data/parse_tree_show +0 -28
- data/test_all.rb +0 -7
- data/test_parse_tree.rb +0 -275
data/History.txt
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
*** 1.2.0 / 2004-11-29
|
2
|
+
|
3
|
+
+ 9 minor enhancements
|
4
|
+
+ ParseTree now returns symbols for all data except in :str and :lit.
|
5
|
+
+ This WILL break existing code! (as if any exists)
|
6
|
+
+ ParseTree.parse_tree now takes a list of classes, no optional method.
|
7
|
+
+ ParseTree.parse_tree_for_method(klass, method) added.
|
8
|
+
+ ParseTree.parse_tree now returns a list of :class/:module nodes.
|
9
|
+
+ Added -f to parse_tree_show for uber fast demos.
|
10
|
+
+ Added -q to parse_tree_show to NOT use pp so it is mucho faster.
|
11
|
+
+ running with $DEBUG will trace the methods and nodes as processed.
|
12
|
+
+ Added rdoc to everything.
|
13
|
+
+ Gemified
|
14
|
+
+ 4 bug fixes
|
15
|
+
+ Bus error in iter/for nodes where arg list is empty now fixed.
|
16
|
+
+ Bus error when handling 'def method(*)' is now fixed.
|
17
|
+
+ Unnamed classes and superclasses (ugh) are now handled.
|
18
|
+
+ parse_tree_abc now enumerates actual types rather than every token.
|
19
|
+
|
1
20
|
*** 1.1.0 / 2004-11-12
|
2
21
|
|
3
22
|
+ 2 minor enhancement
|
data/Makefile
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
RUBY?=ruby
|
2
|
-
RUBY_FLAGS?=-w -
|
2
|
+
RUBY_FLAGS?=-w -Ilib
|
3
3
|
RUBY_LIB?=$(shell $(RUBY) -rrbconfig -e 'include Config; print CONFIG["sitelibdir"]')
|
4
4
|
PREFIX?=/usr/local
|
5
5
|
|
6
|
-
all test:
|
7
|
-
$(RUBY) $(RUBY_FLAGS) test_all.rb
|
6
|
+
all test: FORCE
|
7
|
+
$(RUBY) $(RUBY_FLAGS) test/test_all.rb
|
8
8
|
|
9
9
|
# we only install test_sexp_processor.rb to help make ruby_to_c's
|
10
10
|
# subclass tests work.
|
11
11
|
|
12
|
+
docs:
|
13
|
+
rdoc -d -I png --main SexpProcessor -x test_\* -x something.rb
|
14
|
+
|
12
15
|
install:
|
13
|
-
cp -f parse_tree.rb
|
14
|
-
cp -f
|
15
|
-
cp -f
|
16
|
+
cp -f lib/parse_tree.rb lib/sexp_processor.rb lib/composite_sexp_processor.rb $(RUBY_LIB)
|
17
|
+
cp -f test/test_sexp_processor.rb $(RUBY_LIB)
|
18
|
+
cp -f bin/parse_tree_show $(PREFIX)/bin
|
19
|
+
cp -f bin/parse_tree_abc $(PREFIX)/bin
|
16
20
|
chmod 444 $(RUBY_LIB)/parse_tree.rb $(RUBY_LIB)/sexp_processor.rb $(RUBY_LIB)/composite_sexp_processor.rb $(RUBY_LIB)/test_sexp_processor.rb
|
17
21
|
chmod 555 $(PREFIX)/bin/parse_tree_show $(PREFIX)/bin/parse_tree_abc
|
18
22
|
|
@@ -20,6 +24,19 @@ uninstall:
|
|
20
24
|
rm -f $(RUBY_LIB)/parse_tree.rb $(RUBY_LIB)/sexp_processor.rb $(RUBY_LIB)/composite_sexp_processor.rb $(RUBY_LIB)/test_sexp_processor.rb
|
21
25
|
rm -f $(PREFIX)/bin/parse_tree_show $(PREFIX)/bin/parse_tree_abc
|
22
26
|
|
27
|
+
audit:
|
28
|
+
ZenTest composite_sexp_processor.rb sexp_processor.rb test_all.rb test_composite_sexp_processor.rb test_sexp_processor.rb
|
29
|
+
|
23
30
|
clean:
|
24
|
-
-
|
31
|
+
-find . -name \*~ | xargs rm
|
32
|
+
-rm -f diff diff.txt
|
25
33
|
-rm -r $$HOME/.ruby_inline
|
34
|
+
-rm -r doc
|
35
|
+
|
36
|
+
demo:
|
37
|
+
echo 1+1 | $(RUBY) $(RUBY_FLAGS) ./bin/parse_tree_show -f
|
38
|
+
|
39
|
+
gem:
|
40
|
+
gem ParseTree.gemspec
|
41
|
+
|
42
|
+
FORCE:
|
data/Manifest.txt
CHANGED
@@ -2,13 +2,15 @@ History.txt
|
|
2
2
|
Makefile
|
3
3
|
Manifest.txt
|
4
4
|
README.txt
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
parse_tree_show
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
ParseTree.gemspec
|
6
|
+
bin/parse_tree_abc
|
7
|
+
bin/parse_tree_deps
|
8
|
+
bin/parse_tree_show
|
9
|
+
lib/composite_sexp_processor.rb
|
10
|
+
lib/parse_tree.rb
|
11
|
+
lib/sexp_processor.rb
|
12
|
+
test/something.rb
|
13
|
+
test/test_all.rb
|
14
|
+
test/test_composite_sexp_processor.rb
|
15
|
+
test/test_parse_tree.rb
|
16
|
+
test/test_sexp_processor.rb
|
data/ParseTree.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
$: << "./lib"
|
5
|
+
require 'parse_tree'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
|
9
|
+
s.name = 'ParseTree'
|
10
|
+
s.version = ParseTree::VERSION
|
11
|
+
s.summary = "Extract and enumerate ruby parse trees."
|
12
|
+
|
13
|
+
paragraphs = File.read("README.txt").split(/\n\n+/)
|
14
|
+
s.description = paragraphs[2]
|
15
|
+
puts "Description = #{s.description}"
|
16
|
+
|
17
|
+
s.requirements << "RubyInline."
|
18
|
+
s.files = IO.readlines("Manifest.txt").map {|f| f.chomp }
|
19
|
+
|
20
|
+
s.require_paths = ['lib', 'test']
|
21
|
+
s.autorequire = 'parse_tree'
|
22
|
+
|
23
|
+
s.bindir = "bin"
|
24
|
+
s.executables = s.files.grep(Regexp.new(s.bindir)) { |f| File.basename(f) }
|
25
|
+
puts "Executables = #{s.executables.join(", ")}"
|
26
|
+
|
27
|
+
s.has_rdoc = true
|
28
|
+
s.test_suite_file = "test/test_all.rb"
|
29
|
+
|
30
|
+
s.author = "Ryan Davis"
|
31
|
+
s.email = "ryand-ruby@zenspider.com"
|
32
|
+
s.homepage = "http://www.zenspider.com/ZSS/Products/ParseTree/"
|
33
|
+
s.rubyforge_project = "parsetree"
|
34
|
+
end
|
35
|
+
|
36
|
+
if $0 == __FILE__
|
37
|
+
Gem.manage_gems
|
38
|
+
Gem::Builder.new(spec).build
|
39
|
+
end
|
data/README.txt
CHANGED
data/bin/parse_tree_abc
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
# ABC metric
|
4
|
+
#
|
5
|
+
# Assignments, Branches, and Calls
|
6
|
+
#
|
7
|
+
# A simple way to measure the complexity of a function or method.
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'rubygems'
|
11
|
+
require_gem 'ParseTree'
|
12
|
+
rescue LoadError
|
13
|
+
require 'parse_tree'
|
14
|
+
end
|
15
|
+
|
16
|
+
old_classes = []
|
17
|
+
ObjectSpace.each_object(Module) do |klass|
|
18
|
+
old_classes << klass
|
19
|
+
end
|
20
|
+
|
21
|
+
ARGV.each do |name|
|
22
|
+
require name
|
23
|
+
end
|
24
|
+
|
25
|
+
new_classes = []
|
26
|
+
ObjectSpace.each_object(Module) do |klass|
|
27
|
+
new_classes << klass
|
28
|
+
end
|
29
|
+
|
30
|
+
score = {}
|
31
|
+
|
32
|
+
new_classes -= old_classes
|
33
|
+
|
34
|
+
def sexp_types(exp)
|
35
|
+
result = []
|
36
|
+
if Array === exp.first then
|
37
|
+
result = sexp_types(exp.first)
|
38
|
+
else
|
39
|
+
result << exp.shift
|
40
|
+
exp.grep(Array).each do |subexp|
|
41
|
+
result.concat(sexp_types(subexp))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
klasses = ParseTree.new.parse_tree(*new_classes)
|
48
|
+
klasses.each do |klass|
|
49
|
+
klass.shift # :class
|
50
|
+
klassname = klass.shift
|
51
|
+
klass.shift # superclass
|
52
|
+
methods = klass
|
53
|
+
|
54
|
+
methods.each do |defn|
|
55
|
+
a=b=c=0
|
56
|
+
defn.shift
|
57
|
+
methodname = defn.shift
|
58
|
+
tokens = sexp_types(defn)
|
59
|
+
tokens.each do |token|
|
60
|
+
case token
|
61
|
+
when :attrasgn, :attrset, :dasgn_curr, :iasgn, :lasgn, :masgn then
|
62
|
+
a += 1
|
63
|
+
when :and, :case, :else, :if, :iter, :or, :rescue, :until, :when, :while then
|
64
|
+
b += 1
|
65
|
+
when :call, :fcall, :super, :vcall, :yield then
|
66
|
+
c += 1
|
67
|
+
when :args, :argscat, :array, :begin, :block, :block_arg, :block_pass, :bool, :cfunc, :colon2, :const, :cvar, :defined, :defn, :dregx, :dstr, :dvar, :dxstr, :ensure, :false, :fbody, :gvar, :hash, :ivar, :lit, :long, :lvar, :match2, :match3, :nil, :not, :nth_ref, :return, :scope, :self, :splat, :str, :to_ary, :true, :unknown, :value, :void, :zarray, :zarray, :zclass, :zsuper then
|
68
|
+
# ignore
|
69
|
+
else
|
70
|
+
puts "unhandled token #{token.inspect}" if $VERBOSE
|
71
|
+
end
|
72
|
+
end
|
73
|
+
key = ["#{klassname}.#{methodname}", a, b, c]
|
74
|
+
val = a+b+c
|
75
|
+
score[key] = val
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
puts "Method = assignments + branches + calls = total"
|
80
|
+
puts
|
81
|
+
count = 1
|
82
|
+
score.sort_by { |k,v| v }.reverse.each do |key,val|
|
83
|
+
name, a, b, c = *key
|
84
|
+
printf "%3d) %-50s = %2d + %2d + %2d = %3d\n", count, name, a, b, c, val
|
85
|
+
count += 1
|
86
|
+
end
|
data/bin/parse_tree_deps
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/local/bin/ruby -ws
|
2
|
+
|
3
|
+
old_classes = []; new_classes = []
|
4
|
+
|
5
|
+
ObjectSpace.each_object(Module) { |klass| old_classes << klass } if defined? $a
|
6
|
+
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'rubygems'
|
11
|
+
require_gem 'ParseTree'
|
12
|
+
rescue LoadError
|
13
|
+
require 'parse_tree'
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'sexp_processor'
|
17
|
+
|
18
|
+
ObjectSpace.each_object(Module) { |klass| old_classes << klass } unless defined? $a
|
19
|
+
|
20
|
+
class DependencyAnalyzer < SexpProcessor
|
21
|
+
|
22
|
+
attr_reader :dependencies
|
23
|
+
attr_accessor :current_class
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
super
|
27
|
+
self.auto_shift_type = true
|
28
|
+
@dependencies = Hash.new { |h,k| h[k] = [] }
|
29
|
+
@current_method = nil
|
30
|
+
@current_class = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.process(*klasses)
|
34
|
+
analyzer = self.new
|
35
|
+
klasses.each do |start_klass|
|
36
|
+
analyzer.current_class = start_klass
|
37
|
+
analyzer.process(ParseTree.new.parse_tree(start_klass))
|
38
|
+
end
|
39
|
+
|
40
|
+
deps = analyzer.dependencies
|
41
|
+
deps.keys.sort.each do |dep_to|
|
42
|
+
dep_from = deps[dep_to]
|
43
|
+
puts "#{dep_to}: #{dep_from.uniq.sort.join(", ")}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_defn(exp)
|
48
|
+
name = exp.shift
|
49
|
+
@current_method = name
|
50
|
+
return s(:defn, name, process(exp.shift), process(exp.shift))
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_const(exp)
|
54
|
+
name = exp.shift
|
55
|
+
const = (defined?($c) ? @current_class.name : "#{@current_class}.#{@current_method}")
|
56
|
+
is_class = ! (Object.const_get(name) rescue nil).nil?
|
57
|
+
@dependencies[name] << const if is_class
|
58
|
+
return s(:const, name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if __FILE__ == $0 then
|
63
|
+
ARGV.each { |name| require name }
|
64
|
+
ObjectSpace.each_object(Module) { |klass| new_classes << klass }
|
65
|
+
DependencyAnalyzer.process(*(new_classes - old_classes))
|
66
|
+
end
|
data/bin/parse_tree_show
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/local/bin/ruby -ws
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'rubygems'
|
7
|
+
require_gem 'ParseTree'
|
8
|
+
rescue LoadError
|
9
|
+
require 'parse_tree'
|
10
|
+
end
|
11
|
+
|
12
|
+
def discover_new_classes_from
|
13
|
+
old_classes = []
|
14
|
+
ObjectSpace.each_object(Module) do |klass|
|
15
|
+
old_classes << klass
|
16
|
+
end
|
17
|
+
|
18
|
+
yield
|
19
|
+
|
20
|
+
new_classes = []
|
21
|
+
ObjectSpace.each_object(Module) do |klass|
|
22
|
+
new_classes << klass
|
23
|
+
end
|
24
|
+
|
25
|
+
new_classes - old_classes
|
26
|
+
end
|
27
|
+
|
28
|
+
$f = false unless defined? $f
|
29
|
+
|
30
|
+
new_classes = discover_new_classes_from do
|
31
|
+
ARGV.unshift "-" if ARGV.empty?
|
32
|
+
ARGV.each do |name|
|
33
|
+
if name == "-" then
|
34
|
+
code = $stdin.read
|
35
|
+
code = "class Example; def example; #{code}; end; end" if $f
|
36
|
+
eval code unless code.nil?
|
37
|
+
else
|
38
|
+
require name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
result = ParseTree.new.parse_tree(*new_classes)
|
44
|
+
unless defined? $q then
|
45
|
+
pp result
|
46
|
+
else
|
47
|
+
p result
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'sexp_processor'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Implements the Composite pattern on SexpProcessor. Need we say more?
|
5
|
+
#
|
6
|
+
# Yeah... probably. Implements a SexpProcessor of SexpProcessors so
|
7
|
+
# you can easily chain multiple to each other. At some stage we plan
|
8
|
+
# on having all of them run +process+ and but only ever output
|
9
|
+
# something when +generate+ is called, allowing for deferred final
|
10
|
+
# processing.
|
11
|
+
|
12
|
+
class CompositeSexpProcessor < SexpProcessor
|
13
|
+
|
14
|
+
##
|
15
|
+
# The list o' processors to run.
|
16
|
+
|
17
|
+
attr_reader :processors
|
18
|
+
|
19
|
+
def initialize # :nodoc:
|
20
|
+
super
|
21
|
+
@processors = []
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Add a +processor+ to the list of processors to run.
|
26
|
+
|
27
|
+
def <<(processor)
|
28
|
+
raise ArgumentError, "Can only add sexp processors" unless
|
29
|
+
SexpProcessor === processor
|
30
|
+
@processors << processor
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Run +exp+ through all of the processors, returning the final
|
35
|
+
# result.
|
36
|
+
|
37
|
+
def process(exp)
|
38
|
+
@processors.each do |processor|
|
39
|
+
exp = processor.process(exp)
|
40
|
+
end
|
41
|
+
exp
|
42
|
+
end
|
43
|
+
end
|
@@ -4,12 +4,80 @@ begin
|
|
4
4
|
require 'rubygems'
|
5
5
|
require_gem 'RubyInline'
|
6
6
|
rescue LoadError
|
7
|
-
require
|
7
|
+
require "inline"
|
8
8
|
end
|
9
9
|
|
10
|
+
##
|
11
|
+
# ParseTree is a RubyInline-style extension that accesses and
|
12
|
+
# traverses the internal parse tree created by ruby.
|
13
|
+
#
|
14
|
+
# class Example
|
15
|
+
# def blah
|
16
|
+
# return 1 + 1
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# ParseTree.new.parse_tree(Example)
|
21
|
+
# => [[:defn,
|
22
|
+
# "blah",
|
23
|
+
# [:scope,
|
24
|
+
# [:block,
|
25
|
+
# [:args],
|
26
|
+
# [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]
|
27
|
+
|
10
28
|
class ParseTree
|
11
29
|
|
12
|
-
VERSION = '1.
|
30
|
+
VERSION = '1.2.0'
|
31
|
+
|
32
|
+
##
|
33
|
+
# Main driver for ParseTree. Returns an array of arrays containing
|
34
|
+
# the parse tree for +klasses+.
|
35
|
+
#
|
36
|
+
# Structure:
|
37
|
+
#
|
38
|
+
# [[:class, classname, superclassname, [:defn :method1, ...], ...], ...]
|
39
|
+
#
|
40
|
+
# NOTE: v1.0 - v1.1 had the signature (klass, meth=nil). This wasn't
|
41
|
+
# used much at all and since parse_tree_for_method already existed,
|
42
|
+
# it was deemed more useful to expand this method to do multiple
|
43
|
+
# classes.
|
44
|
+
|
45
|
+
def parse_tree(*klasses)
|
46
|
+
result = []
|
47
|
+
klasses.each do |klass|
|
48
|
+
raise "You should call parse_tree_for_method(#{klasses.first}, #{klass}) instead of parse_tree" if Symbol === klass or String === klass
|
49
|
+
klassname = klass.name
|
50
|
+
klassname = "UnnamedClass_#{klass.object_id}" if klassname.empty?
|
51
|
+
klassname = klassname.to_sym
|
52
|
+
|
53
|
+
code = if Class === klass then
|
54
|
+
superclass = klass.superclass.name
|
55
|
+
superclass = "nil" if superclass.empty?
|
56
|
+
superclass = superclass.to_sym
|
57
|
+
[:class, klassname, superclass]
|
58
|
+
else
|
59
|
+
[:module, klassname]
|
60
|
+
end
|
61
|
+
|
62
|
+
klass.instance_methods(false).sort.each do |m|
|
63
|
+
$stderr.puts "parse_tree_for_method(#{klass}, #{m}):" if $DEBUG
|
64
|
+
code << parse_tree_for_method(klass, m.to_sym)
|
65
|
+
end
|
66
|
+
result << code
|
67
|
+
end
|
68
|
+
return result
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Returns the parse tree for just one +method+ of a class +klass+.
|
73
|
+
#
|
74
|
+
# Format:
|
75
|
+
#
|
76
|
+
# [:defn, :name, :body]
|
77
|
+
|
78
|
+
def parse_tree_for_method(klass, method)
|
79
|
+
parse_tree_for_meth(klass, method.to_sym)
|
80
|
+
end
|
13
81
|
|
14
82
|
inline do |builder|
|
15
83
|
builder.add_type_converter("VALUE", '', '')
|
@@ -95,6 +163,10 @@ again:
|
|
95
163
|
|
96
164
|
if (node) {
|
97
165
|
node_name = ID2SYM(rb_intern(node_type_string[nd_type(node)]));
|
166
|
+
if (RTEST(ruby_debug)) {
|
167
|
+
fputs(node_type_string[nd_type(node)], stderr);
|
168
|
+
fputs("\n", stderr);
|
169
|
+
}
|
98
170
|
} else {
|
99
171
|
node_name = ID2SYM(rb_intern("ICKY"));
|
100
172
|
}
|
@@ -129,7 +201,7 @@ again_no_block:
|
|
129
201
|
|
130
202
|
case NODE_COLON2:
|
131
203
|
add_to_parse_tree(current, node->nd_head);
|
132
|
-
rb_ary_push(current,
|
204
|
+
rb_ary_push(current, ID2SYM(node->nd_mid));
|
133
205
|
break;
|
134
206
|
|
135
207
|
case NODE_BEGIN:
|
@@ -199,7 +271,9 @@ again_no_block:
|
|
199
271
|
case NODE_ITER:
|
200
272
|
case NODE_FOR:
|
201
273
|
add_to_parse_tree(current, node->nd_iter);
|
202
|
-
if (node->nd_var != (NODE *)
|
274
|
+
if (node->nd_var != (NODE *)1
|
275
|
+
&& node->nd_var != (NODE *)2
|
276
|
+
&& node->nd_var != NULL) {
|
203
277
|
add_to_parse_tree(current, node->nd_var);
|
204
278
|
} else {
|
205
279
|
rb_ary_push(current, Qnil);
|
@@ -281,7 +355,7 @@ again_no_block:
|
|
281
355
|
case NODE_VCALL:
|
282
356
|
if (nd_type(node) != NODE_FCALL)
|
283
357
|
add_to_parse_tree(current, node->nd_recv);
|
284
|
-
rb_ary_push(current,
|
358
|
+
rb_ary_push(current, ID2SYM(node->nd_mid));
|
285
359
|
if (node->nd_args || nd_type(node) != NODE_FCALL)
|
286
360
|
add_to_parse_tree(current, node->nd_args);
|
287
361
|
break;
|
@@ -337,7 +411,7 @@ again_no_block:
|
|
337
411
|
case NODE_CVASGN:
|
338
412
|
case NODE_CVDECL:
|
339
413
|
case NODE_GASGN:
|
340
|
-
rb_ary_push(current,
|
414
|
+
rb_ary_push(current, ID2SYM(node->nd_vid));
|
341
415
|
add_to_parse_tree(current, node->nd_value);
|
342
416
|
break;
|
343
417
|
|
@@ -398,14 +472,14 @@ again_no_block:
|
|
398
472
|
if (node->nd_defn) {
|
399
473
|
if (nd_type(node) == NODE_DEFS)
|
400
474
|
add_to_parse_tree(current, node->nd_recv);
|
401
|
-
rb_ary_push(current,
|
475
|
+
rb_ary_push(current, ID2SYM(node->nd_mid));
|
402
476
|
add_to_parse_tree(current, node->nd_defn);
|
403
477
|
}
|
404
478
|
break;
|
405
479
|
|
406
480
|
case NODE_CLASS:
|
407
481
|
case NODE_MODULE:
|
408
|
-
rb_ary_push(current,
|
482
|
+
rb_ary_push(current, ID2SYM((ID)node->nd_cpath->nd_mid));
|
409
483
|
if (node->nd_super && nd_type(node) == NODE_CLASS) {
|
410
484
|
add_to_parse_tree(current, node->nd_super);
|
411
485
|
}
|
@@ -422,25 +496,36 @@ again_no_block:
|
|
422
496
|
(node->nd_cnt || node->nd_opt || node->nd_rest != -1)) {
|
423
497
|
int i;
|
424
498
|
NODE *optnode;
|
499
|
+
long arg_count;
|
425
500
|
|
426
501
|
for (i = 0; i < node->nd_cnt; i++) {
|
427
502
|
// regular arg names
|
428
|
-
rb_ary_push(current,
|
503
|
+
rb_ary_push(current, ID2SYM(dump_local_tbl[i + 3]));
|
429
504
|
}
|
430
505
|
|
431
506
|
optnode = node->nd_opt;
|
432
507
|
while (optnode) {
|
433
508
|
// optional arg names
|
434
|
-
rb_ary_push(current,
|
509
|
+
rb_ary_push(current, ID2SYM(dump_local_tbl[i + 3]));
|
435
510
|
i++;
|
436
511
|
optnode = optnode->nd_next;
|
437
512
|
}
|
438
|
-
|
513
|
+
|
514
|
+
arg_count = node->nd_rest;
|
515
|
+
if (arg_count > 0) {
|
439
516
|
// *arg name
|
440
|
-
rb_ary_push(current,
|
517
|
+
rb_ary_push(current, ID2SYM(dump_local_tbl[node->nd_rest + 1]));
|
518
|
+
} else if (arg_count == -1) {
|
519
|
+
// nothing to do in this case, handled above
|
520
|
+
} else if (arg_count == -2) {
|
521
|
+
// nothing to do in this case, no name == no use
|
522
|
+
} else {
|
523
|
+
puts("not a clue what this arg value is");
|
524
|
+
exit(1);
|
441
525
|
}
|
526
|
+
|
442
527
|
optnode = node->nd_opt;
|
443
|
-
//
|
528
|
+
// block?
|
444
529
|
if (optnode) {
|
445
530
|
add_to_parse_tree(current, node->nd_opt);
|
446
531
|
}
|
@@ -454,7 +539,7 @@ again_no_block:
|
|
454
539
|
case NODE_GVAR:
|
455
540
|
case NODE_CONST:
|
456
541
|
case NODE_ATTRSET:
|
457
|
-
rb_ary_push(current,
|
542
|
+
rb_ary_push(current, ID2SYM(node->nd_vid));
|
458
543
|
break;
|
459
544
|
|
460
545
|
case NODE_STR:
|
@@ -506,10 +591,10 @@ again_no_block:
|
|
506
591
|
goto again_no_block;
|
507
592
|
}
|
508
593
|
}
|
509
|
-
^
|
594
|
+
^ # end of add_to_parse_tree block
|
510
595
|
|
511
596
|
builder.c %q{
|
512
|
-
static VALUE
|
597
|
+
static VALUE parse_tree_for_meth(VALUE klass, VALUE method) {
|
513
598
|
NODE *node = NULL;
|
514
599
|
ID id;
|
515
600
|
VALUE result = rb_ary_new();
|
@@ -519,7 +604,7 @@ static VALUE parse_tree_for_method(VALUE klass, VALUE method) {
|
|
519
604
|
id = rb_to_id(method);
|
520
605
|
if (st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *) &node)) {
|
521
606
|
rb_ary_push(result, ID2SYM(rb_intern("defn")));
|
522
|
-
rb_ary_push(result,
|
607
|
+
rb_ary_push(result, ID2SYM(id));
|
523
608
|
add_to_parse_tree(result, node->nd_body);
|
524
609
|
} else {
|
525
610
|
rb_ary_push(result, Qnil);
|
@@ -528,18 +613,5 @@ static VALUE parse_tree_for_method(VALUE klass, VALUE method) {
|
|
528
613
|
return result;
|
529
614
|
}
|
530
615
|
}
|
531
|
-
end
|
532
|
-
|
533
|
-
def parse_tree(klass, meth=nil)
|
534
|
-
code = []
|
535
|
-
if meth then
|
536
|
-
code = parse_tree_for_method(klass, meth.to_s)
|
537
|
-
else
|
538
|
-
klass.instance_methods(false).sort.each do |m|
|
539
|
-
code << parse_tree_for_method(klass, m)
|
540
|
-
end
|
541
|
-
end
|
542
|
-
return code
|
543
|
-
end
|
544
|
-
|
545
|
-
end
|
616
|
+
end # inline call
|
617
|
+
end # ParseTree class
|