ParseTree 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|