ParseTree 1.3.7 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +18 -0
- data/Makefile +27 -11
- data/Manifest.txt +4 -1
- data/bin/parse_tree_abc +9 -2
- data/bin/parse_tree_deps +2 -1
- data/demo/printer.rb +20 -0
- data/lib/parse_tree.rb +5 -3
- data/lib/sexp.rb +257 -0
- data/lib/sexp_processor.rb +2 -179
- data/test/something.rb +6 -0
- data/test/test_parse_tree.rb +15 -0
- data/test/test_sexp.rb +298 -0
- data/test/test_sexp_processor.rb +0 -150
- metadata +49 -44
data/History.txt
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
*** 1.4.0 / 2005-10-15
|
2
|
+
|
3
|
+
+ 5 minor enhancements
|
4
|
+
+ Improved Makefile's install rule, uninstall, and added FILTER to all.
|
5
|
+
+ Fixed minor issues w/ Makefile.
|
6
|
+
+ Added -I=loadpath to parse_tree_abc.
|
7
|
+
+ Added *args support for methods.
|
8
|
+
+ Split out sexp to its own file.
|
9
|
+
+ 2 bug fixes
|
10
|
+
+ Fixed weird bug in parse_tree_deps where sort was failing on deps.
|
11
|
+
+ ! Fixed fatal bug in parse_tree.rb caused by safe_level fix in ruby 1.8.3.
|
12
|
+
|
13
|
+
*** 1.3.8 / 2005-09-27
|
14
|
+
|
15
|
+
+ 1 bug fix:
|
16
|
+
+ Our private version of struct METHOD went out of sync w/ latest ruby.
|
17
|
+
+ Only use this if you are on 1.8.3+.
|
18
|
+
|
1
19
|
*** 1.3.7 / 2005-07-13
|
2
20
|
|
3
21
|
+ 3 bug fixes:
|
data/Makefile
CHANGED
@@ -3,9 +3,27 @@ RUBY_DEBUG?=
|
|
3
3
|
RUBY_FLAGS?=-w -Ilib:bin:../../RubyInline/dev
|
4
4
|
RUBY_LIB?=$(shell $(RUBY) -rrbconfig -e 'include Config; print CONFIG["sitelibdir"]')
|
5
5
|
PREFIX?=/usr/local
|
6
|
+
FILTER?=
|
7
|
+
|
8
|
+
LIB_FILES= \
|
9
|
+
composite_sexp_processor.rb \
|
10
|
+
parse_tree.rb \
|
11
|
+
sexp.rb \
|
12
|
+
sexp_processor.rb \
|
13
|
+
$(END)
|
14
|
+
|
15
|
+
TEST_FILES= \
|
16
|
+
test_sexp_processor.rb \
|
17
|
+
$(END)
|
18
|
+
|
19
|
+
BIN_FILES= \
|
20
|
+
parse_tree_abc \
|
21
|
+
parse_tree_show \
|
22
|
+
parse_tree_deps \
|
23
|
+
$(END)
|
6
24
|
|
7
25
|
all test: FORCE
|
8
|
-
$(RUBY) $(RUBY_DEBUG) $(RUBY_FLAGS) test/test_all.rb
|
26
|
+
$(RUBY) $(RUBY_DEBUG) $(RUBY_FLAGS) test/test_all.rb $(FILTER)
|
9
27
|
|
10
28
|
# we only install test_sexp_processor.rb to help make ruby_to_c's
|
11
29
|
# subclass tests work.
|
@@ -14,19 +32,17 @@ docs:
|
|
14
32
|
rdoc -d -I png --main SexpProcessor -x test_\* -x something.rb
|
15
33
|
|
16
34
|
install:
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
cp -f bin/parse_tree_abc $(PREFIX)/bin
|
21
|
-
chmod 444 $(RUBY_LIB)/parse_tree.rb $(RUBY_LIB)/sexp_processor.rb $(RUBY_LIB)/composite_sexp_processor.rb $(RUBY_LIB)/test_sexp_processor.rb
|
22
|
-
chmod 555 $(PREFIX)/bin/parse_tree_show $(PREFIX)/bin/parse_tree_abc
|
35
|
+
cd lib && install -m 0444 $(LIB_FILES) $(RUBY_LIB)
|
36
|
+
cd test && install -m 0444 $(TEST_FILES) $(RUBY_LIB)
|
37
|
+
cd bin && install -m 0555 $(BIN_FILES) $(PREFIX)/bin
|
23
38
|
|
24
39
|
uninstall:
|
25
|
-
|
26
|
-
|
40
|
+
cd $(RUBY_LIB) && rm -f $(LIB_FILES) $(TEST_FILES)
|
41
|
+
cd $(PREFIX)/bin && rm -f $(BIN_FILES)
|
27
42
|
|
28
43
|
audit:
|
29
|
-
ZenTest
|
44
|
+
ZenTest -I=lib:test $(addprefix lib/,$(LIB_FILES)) test/test_all.rb
|
45
|
+
# test_composite_sexp_processor.rb test_sexp_processor.rb
|
30
46
|
|
31
47
|
clean:
|
32
48
|
-find . -name \*~ | xargs rm
|
@@ -36,6 +52,6 @@ demo:
|
|
36
52
|
echo 1+1 | $(RUBY) $(RUBY_FLAGS) ./bin/parse_tree_show -f
|
37
53
|
|
38
54
|
gem:
|
39
|
-
|
55
|
+
ruby ParseTree.gemspec
|
40
56
|
|
41
57
|
FORCE:
|
data/Manifest.txt
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
History.txt
|
2
2
|
Makefile
|
3
3
|
Manifest.txt
|
4
|
-
README.txt
|
5
4
|
ParseTree.gemspec
|
5
|
+
README.txt
|
6
6
|
bin/parse_tree_abc
|
7
7
|
bin/parse_tree_deps
|
8
8
|
bin/parse_tree_show
|
9
|
+
demo/printer.rb
|
9
10
|
lib/composite_sexp_processor.rb
|
10
11
|
lib/parse_tree.rb
|
12
|
+
lib/sexp.rb
|
11
13
|
lib/sexp_processor.rb
|
12
14
|
test/something.rb
|
13
15
|
test/test_all.rb
|
14
16
|
test/test_composite_sexp_processor.rb
|
15
17
|
test/test_parse_tree.rb
|
18
|
+
test/test_sexp.rb
|
16
19
|
test/test_sexp_processor.rb
|
17
20
|
validate.sh
|
data/bin/parse_tree_abc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
1
|
+
#!/usr/local/bin/ruby -ws
|
2
2
|
|
3
3
|
# ABC metric
|
4
4
|
#
|
@@ -6,9 +6,16 @@
|
|
6
6
|
#
|
7
7
|
# A simple way to measure the complexity of a function or method.
|
8
8
|
|
9
|
+
if defined? $I and String === $I then
|
10
|
+
$I.split(/:/).each do |dir|
|
11
|
+
$: << dir
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
9
15
|
PARSE_TREE_ABC=true
|
10
16
|
|
11
17
|
begin require 'rubygems' rescue LoadError end
|
18
|
+
require 'sexp'
|
12
19
|
require 'parse_tree'
|
13
20
|
require 'sexp_processor'
|
14
21
|
|
@@ -78,5 +85,5 @@ score.sort_by { |k,v| v }.reverse.each do |key,val|
|
|
78
85
|
tval += val
|
79
86
|
printf "%3d) %-50s = %2d + %2d + %2d = %6.2f\n", count, name, a, b, c, val
|
80
87
|
count += 1
|
81
|
-
end
|
88
|
+
end rescue nil
|
82
89
|
printf "%3d) %-50s = %2d + %2d + %2d = %6.2f\n", count, "Total", ta, tb, tc, tval
|
data/bin/parse_tree_deps
CHANGED
@@ -33,7 +33,7 @@ class DependencyAnalyzer < SexpProcessor
|
|
33
33
|
end
|
34
34
|
|
35
35
|
deps = analyzer.dependencies
|
36
|
-
deps.keys.
|
36
|
+
deps.keys.sort_by {|k| k.to_s}.each do |dep_to|
|
37
37
|
dep_from = deps[dep_to]
|
38
38
|
puts "#{dep_to}: #{dep_from.uniq.sort.join(", ")}"
|
39
39
|
end
|
@@ -57,5 +57,6 @@ end
|
|
57
57
|
if __FILE__ == $0 then
|
58
58
|
ARGV.each { |name| require name }
|
59
59
|
ObjectSpace.each_object(Module) { |klass| new_classes << klass }
|
60
|
+
new_classes.delete DependencyAnalyzer unless defined? $a
|
60
61
|
DependencyAnalyzer.process(*(new_classes - old_classes))
|
61
62
|
end
|
data/demo/printer.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
require 'rubygems'
|
3
|
+
require 'sexp_processor'
|
4
|
+
|
5
|
+
class QuickPrinter < SexpProcessor
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.strict = false
|
9
|
+
self.auto_shift_type = true
|
10
|
+
end
|
11
|
+
def process_defn(exp)
|
12
|
+
name = exp.shift
|
13
|
+
args = process exp.shift
|
14
|
+
body = process exp.shift
|
15
|
+
puts " def #{name}"
|
16
|
+
return s(:defn, name, args, body)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
QuickPrinter.new.process(*ParseTree.new.parse_tree(QuickPrinter))
|
data/lib/parse_tree.rb
CHANGED
@@ -24,7 +24,7 @@ require 'inline'
|
|
24
24
|
|
25
25
|
class ParseTree
|
26
26
|
|
27
|
-
VERSION = '1.
|
27
|
+
VERSION = '1.4.0'
|
28
28
|
|
29
29
|
##
|
30
30
|
# Initializes a ParseTree instance. Includes newline nodes if
|
@@ -129,13 +129,14 @@ class ParseTree
|
|
129
129
|
# builder.add_compile_flags "-Wmissing-prototypes"
|
130
130
|
# builder.add_compile_flags "-Wsign-compare"
|
131
131
|
|
132
|
-
builder.prefix %
|
132
|
+
builder.prefix %{
|
133
133
|
#define nd_3rd u3.node
|
134
134
|
|
135
135
|
struct METHOD {
|
136
136
|
VALUE klass, rklass;
|
137
137
|
VALUE recv;
|
138
138
|
ID id, oid;
|
139
|
+
#{ RUBY_VERSION <= "1.8.2" ? "" : "int safe_level;" }
|
139
140
|
NODE *body;
|
140
141
|
};
|
141
142
|
|
@@ -586,7 +587,8 @@ again_no_block:
|
|
586
587
|
arg_count = node->nd_rest;
|
587
588
|
if (arg_count > 0) {
|
588
589
|
// *arg name
|
589
|
-
|
590
|
+
VALUE sym = rb_str_intern(rb_str_plus(rb_str_new2("*"), rb_str_new2(rb_id2name(locals[node->nd_rest + 1]))));
|
591
|
+
rb_ary_push(current, sym);
|
590
592
|
} else if (arg_count == -1) {
|
591
593
|
// nothing to do in this case, handled above
|
592
594
|
} else if (arg_count == -2) {
|
data/lib/sexp.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
##
|
2
|
+
# Sexps are the basic storage mechanism of SexpProcessor. Sexps have
|
3
|
+
# a +type+ (to be renamed +node_type+) which is the first element of
|
4
|
+
# the Sexp. The type is used by SexpProcessor to determine whom to
|
5
|
+
# dispatch the Sexp to for processing.
|
6
|
+
|
7
|
+
$TESTING ||= false # unless defined $TESTING
|
8
|
+
|
9
|
+
class Sexp < Array # ZenTest FULL
|
10
|
+
|
11
|
+
@@array_types = [ :array, :args, ]
|
12
|
+
|
13
|
+
##
|
14
|
+
# Named positional parameters.
|
15
|
+
# Use with +SexpProcessor.require_empty=false+.
|
16
|
+
attr_accessor :accessors
|
17
|
+
|
18
|
+
##
|
19
|
+
# Create a new Sexp containing +args+.
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
@accessors = []
|
23
|
+
super(args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_array(a)
|
27
|
+
ary = Array === a ? a : [a]
|
28
|
+
|
29
|
+
result = self.new
|
30
|
+
|
31
|
+
ary.each do |x|
|
32
|
+
case x
|
33
|
+
when Sexp
|
34
|
+
result << x
|
35
|
+
when Array
|
36
|
+
result << self.from_array(x)
|
37
|
+
else
|
38
|
+
result << x
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
def ==(obj) # :nodoc:
|
46
|
+
if obj.class == self.class then
|
47
|
+
super
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def ===(sexp)
|
54
|
+
return nil unless Sexp === sexp
|
55
|
+
pattern = self # this is just for my brain
|
56
|
+
|
57
|
+
return true if pattern == sexp
|
58
|
+
|
59
|
+
sexp.each do |subset|
|
60
|
+
return true if pattern === subset
|
61
|
+
end
|
62
|
+
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def =~(pattern)
|
67
|
+
return pattern === self
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Returns true if the node_type is +array+ or +args+.
|
72
|
+
#
|
73
|
+
# REFACTOR: to TypedSexp - we only care when we have units.
|
74
|
+
|
75
|
+
def array_type?
|
76
|
+
type = self.first
|
77
|
+
@@array_types.include? type
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Enumeratates the sexp yielding to +b+ when the node_type == +t+.
|
82
|
+
|
83
|
+
def each_of_type(t, &b)
|
84
|
+
each do | elem |
|
85
|
+
if Sexp === elem then
|
86
|
+
elem.each_of_type(t, &b)
|
87
|
+
b.call(elem) if elem.first == t
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Replaces all elements whose node_type is +from+ with +to+. Used
|
94
|
+
# only for the most trivial of rewrites.
|
95
|
+
|
96
|
+
def find_and_replace_all(from, to)
|
97
|
+
each_with_index do | elem, index |
|
98
|
+
if Sexp === elem then
|
99
|
+
elem.find_and_replace_all(from, to)
|
100
|
+
else
|
101
|
+
self[index] = to if elem == from
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def gsub(pattern, repl)
|
107
|
+
return repl if pattern == self
|
108
|
+
|
109
|
+
new = self.map do |subset|
|
110
|
+
case subset
|
111
|
+
when Sexp then
|
112
|
+
subset.gsub(pattern, repl)
|
113
|
+
else
|
114
|
+
subset
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
return Sexp.from_array(new)
|
119
|
+
end
|
120
|
+
|
121
|
+
def inspect # :nodoc:
|
122
|
+
sexp_str = self.map {|x|x.inspect}.join(', ')
|
123
|
+
return "s(#{sexp_str})"
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Fancy-Schmancy method used to implement named positional accessors
|
128
|
+
# via +accessors+.
|
129
|
+
#
|
130
|
+
# Example:
|
131
|
+
#
|
132
|
+
# class MyProcessor < SexpProcessor
|
133
|
+
# def initialize
|
134
|
+
# super
|
135
|
+
# self.require_empty = false
|
136
|
+
# self.sexp_accessors = {
|
137
|
+
# :call => [:lhs, :name, :rhs]
|
138
|
+
# }
|
139
|
+
# ...
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# def process_call(exp)
|
143
|
+
# lhs = exp.lhs
|
144
|
+
# name = exp.name
|
145
|
+
# rhs = exp.rhs
|
146
|
+
# ...
|
147
|
+
# end
|
148
|
+
# end
|
149
|
+
|
150
|
+
def method_missing(meth, *a, &b)
|
151
|
+
super unless @accessors.include? meth
|
152
|
+
|
153
|
+
index = @accessors.index(meth) + 1 # skip type
|
154
|
+
return self.at(index)
|
155
|
+
end
|
156
|
+
|
157
|
+
def pretty_print(q) # :nodoc:
|
158
|
+
q.group(1, 's(', ')') do
|
159
|
+
q.seplist(self) {|v| q.pp v }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Returns the Sexp without the node_type.
|
165
|
+
|
166
|
+
def sexp_body
|
167
|
+
self[1..-1]
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# If run with debug, Sexp will raise if you shift on an empty
|
172
|
+
# Sexp. Helps with debugging.
|
173
|
+
|
174
|
+
def shift
|
175
|
+
raise "I'm empty" if self.empty?
|
176
|
+
super
|
177
|
+
end if $DEBUG or $TESTING
|
178
|
+
|
179
|
+
##
|
180
|
+
# Returnes the bare bones structure of the sexp.
|
181
|
+
# s(:a, :b, s(:c, :d), :e) => s(:a, s(:c))
|
182
|
+
|
183
|
+
def structure
|
184
|
+
result = self.class.new
|
185
|
+
if Array === self.first then
|
186
|
+
result = self.first.structure
|
187
|
+
else
|
188
|
+
result << self.shift
|
189
|
+
self.grep(Array).each do |subexp|
|
190
|
+
result << subexp.structure
|
191
|
+
end
|
192
|
+
end
|
193
|
+
result
|
194
|
+
end
|
195
|
+
|
196
|
+
def sub(pattern, repl)
|
197
|
+
return repl.dup if pattern == self
|
198
|
+
|
199
|
+
done = false
|
200
|
+
|
201
|
+
new = self.map do |subset|
|
202
|
+
if done then
|
203
|
+
subset
|
204
|
+
else
|
205
|
+
case subset
|
206
|
+
when Sexp then
|
207
|
+
if pattern == subset then
|
208
|
+
done = true
|
209
|
+
repl.dup
|
210
|
+
elsif pattern === subset then
|
211
|
+
done = true
|
212
|
+
subset.sub pattern, repl
|
213
|
+
else
|
214
|
+
subset
|
215
|
+
end
|
216
|
+
else
|
217
|
+
subset
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
return Sexp.from_array(new)
|
223
|
+
end
|
224
|
+
|
225
|
+
def to_a # :nodoc:
|
226
|
+
self.map { |o| Sexp === o ? o.to_a : o }
|
227
|
+
end
|
228
|
+
|
229
|
+
def to_s # :nodoc:
|
230
|
+
inspect
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
class SexpMatchSpecial < Sexp; end
|
236
|
+
|
237
|
+
class SexpAny < SexpMatchSpecial
|
238
|
+
def ===(o)
|
239
|
+
return Sexp === o
|
240
|
+
end
|
241
|
+
|
242
|
+
def inspect
|
243
|
+
"ANY"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
module SexpMatchSpecials
|
248
|
+
def ANY(); return SexpAny.new; end
|
249
|
+
end
|
250
|
+
|
251
|
+
##
|
252
|
+
# This is just a stupid shortcut to make indentation much cleaner.
|
253
|
+
|
254
|
+
def s(*args)
|
255
|
+
Sexp.new(*args)
|
256
|
+
end
|
257
|
+
|
data/lib/sexp_processor.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
|
2
2
|
$TESTING = false unless defined? $TESTING
|
3
3
|
|
4
|
+
require 'sexp'
|
5
|
+
|
4
6
|
class Object
|
5
7
|
|
6
8
|
##
|
@@ -13,185 +15,6 @@ class Object
|
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
|
-
##
|
17
|
-
# Sexps are the basic storage mechanism of SexpProcessor. Sexps have
|
18
|
-
# a +type+ (to be renamed +node_type+) which is the first element of
|
19
|
-
# the Sexp. The type is used by SexpProcessor to determine whom to
|
20
|
-
# dispatch the Sexp to for processing.
|
21
|
-
|
22
|
-
class Sexp < Array # ZenTest FULL
|
23
|
-
|
24
|
-
@@array_types = [ :array, :args, ]
|
25
|
-
|
26
|
-
##
|
27
|
-
# Named positional parameters.
|
28
|
-
# Use with +SexpProcessor.require_empty=false+.
|
29
|
-
attr_accessor :accessors
|
30
|
-
|
31
|
-
##
|
32
|
-
# Create a new Sexp containing +args+.
|
33
|
-
|
34
|
-
def initialize(*args)
|
35
|
-
@accessors = []
|
36
|
-
super(args)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.from_array(a)
|
40
|
-
ary = Array === a ? a : [a]
|
41
|
-
|
42
|
-
result = self.new
|
43
|
-
|
44
|
-
ary.each do |x|
|
45
|
-
case x
|
46
|
-
when Sexp
|
47
|
-
result << x
|
48
|
-
when Array
|
49
|
-
result << self.from_array(x)
|
50
|
-
else
|
51
|
-
result << x
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
result
|
56
|
-
end
|
57
|
-
|
58
|
-
##
|
59
|
-
# Returns true if the node_type is +array+ or +args+.
|
60
|
-
#
|
61
|
-
# REFACTOR: to TypedSexp - we only care when we have units.
|
62
|
-
|
63
|
-
def array_type?
|
64
|
-
type = self.first
|
65
|
-
@@array_types.include? type
|
66
|
-
end
|
67
|
-
|
68
|
-
##
|
69
|
-
# Enumeratates the sexp yielding to +b+ when the node_type == +t+.
|
70
|
-
|
71
|
-
def each_of_type(t, &b)
|
72
|
-
each do | elem |
|
73
|
-
if Sexp === elem then
|
74
|
-
elem.each_of_type(t, &b)
|
75
|
-
b.call(elem) if elem.first == t
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
##
|
81
|
-
# Replaces all elements whose node_type is +from+ with +to+. Used
|
82
|
-
# only for the most trivial of rewrites.
|
83
|
-
|
84
|
-
def find_and_replace_all(from, to)
|
85
|
-
each_with_index do | elem, index |
|
86
|
-
if Sexp === elem then
|
87
|
-
elem.find_and_replace_all(from, to)
|
88
|
-
else
|
89
|
-
self[index] = to if elem == from
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
##
|
95
|
-
# Fancy-Schmancy method used to implement named positional accessors
|
96
|
-
# via +accessors+.
|
97
|
-
#
|
98
|
-
# Example:
|
99
|
-
#
|
100
|
-
# class MyProcessor < SexpProcessor
|
101
|
-
# def initialize
|
102
|
-
# super
|
103
|
-
# self.require_empty = false
|
104
|
-
# self.sexp_accessors = {
|
105
|
-
# :call => [:lhs, :name, :rhs]
|
106
|
-
# }
|
107
|
-
# ...
|
108
|
-
# end
|
109
|
-
#
|
110
|
-
# def process_call(exp)
|
111
|
-
# lhs = exp.lhs
|
112
|
-
# name = exp.name
|
113
|
-
# rhs = exp.rhs
|
114
|
-
# ...
|
115
|
-
# end
|
116
|
-
# end
|
117
|
-
|
118
|
-
def method_missing(meth, *a, &b)
|
119
|
-
super unless @accessors.include? meth
|
120
|
-
|
121
|
-
index = @accessors.index(meth) + 1 # skip type
|
122
|
-
return self.at(index)
|
123
|
-
end
|
124
|
-
|
125
|
-
##
|
126
|
-
# Returns the Sexp without the node_type.
|
127
|
-
|
128
|
-
def sexp_body
|
129
|
-
self[1..-1]
|
130
|
-
end
|
131
|
-
|
132
|
-
##
|
133
|
-
# Returnes the bare bones structure of the sexp.
|
134
|
-
# s(:a, :b, s(:c, :d), :e) => s(:a, s(:c))
|
135
|
-
|
136
|
-
def structure
|
137
|
-
result = self.class.new
|
138
|
-
if Array === self.first then
|
139
|
-
result = self.first.structure
|
140
|
-
else
|
141
|
-
result << self.shift
|
142
|
-
self.grep(Array).each do |subexp|
|
143
|
-
result << subexp.structure
|
144
|
-
end
|
145
|
-
end
|
146
|
-
result
|
147
|
-
end
|
148
|
-
|
149
|
-
def ==(obj) # :nodoc:
|
150
|
-
case obj
|
151
|
-
when Sexp
|
152
|
-
super
|
153
|
-
else
|
154
|
-
false
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def to_a # :nodoc:
|
159
|
-
self.map { |o| Sexp === o ? o.to_a : o }
|
160
|
-
end
|
161
|
-
|
162
|
-
def inspect # :nodoc:
|
163
|
-
sexp_str = self.map {|x|x.inspect}.join(', ')
|
164
|
-
return "s(#{sexp_str})"
|
165
|
-
end
|
166
|
-
|
167
|
-
def pretty_print(q) # :nodoc:
|
168
|
-
q.group(1, 's(', ')') do
|
169
|
-
q.seplist(self) {|v| q.pp v }
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
def to_s # :nodoc:
|
174
|
-
inspect
|
175
|
-
end
|
176
|
-
|
177
|
-
##
|
178
|
-
# If run with debug, Sexp will raise if you shift on an empty
|
179
|
-
# Sexp. Helps with debugging.
|
180
|
-
|
181
|
-
def shift
|
182
|
-
raise "I'm empty" if self.empty?
|
183
|
-
super
|
184
|
-
end if $DEBUG or $TESTING
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
##
|
189
|
-
# This is just a stupid shortcut to make indentation much cleaner.
|
190
|
-
|
191
|
-
def s(*args)
|
192
|
-
Sexp.new(*args)
|
193
|
-
end
|
194
|
-
|
195
18
|
##
|
196
19
|
# SexpProcessor base exception class.
|
197
20
|
|
data/test/something.rb
CHANGED
data/test/test_parse_tree.rb
CHANGED
@@ -177,6 +177,21 @@ class TestParseTree < Test::Unit::TestCase
|
|
177
177
|
[:call, [:lit, 3], :downto, [:array, [:lit, 1]]],
|
178
178
|
nil,
|
179
179
|
[:fcall, :puts, [:array, [:str, "hello"]]]]]]]
|
180
|
+
@@opt_args = [:defn, :opt_args,
|
181
|
+
[:scope,
|
182
|
+
[:block,
|
183
|
+
[:args, :arg1, :arg2, :"*args", [:block, [:lasgn, :arg2, [:lit, 42]]]],
|
184
|
+
[:lasgn, :arg3,
|
185
|
+
[:call,
|
186
|
+
[:call,
|
187
|
+
[:lvar, :arg1],
|
188
|
+
:*,
|
189
|
+
[:array, [:lvar, :arg2]]],
|
190
|
+
:*,
|
191
|
+
[:array, [:lit, 7]]]],
|
192
|
+
[:fcall, :puts, [:array, [:call, [:lvar, :arg3], :to_s]]],
|
193
|
+
[:return,
|
194
|
+
[:str, "foo"]]]]]
|
180
195
|
@@multi_args = [:defn, :multi_args,
|
181
196
|
[:scope,
|
182
197
|
[:block,
|
data/test/test_sexp.rb
ADDED
@@ -0,0 +1,298 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
$TESTING = true
|
4
|
+
|
5
|
+
require 'test/unit' if $0 == __FILE__ unless defined? $ZENTEST and $ZENTEST
|
6
|
+
require 'test/unit/testcase'
|
7
|
+
require 'sexp_processor'
|
8
|
+
require 'stringio'
|
9
|
+
require 'pp'
|
10
|
+
|
11
|
+
class SexpTestCase < Test::Unit::TestCase
|
12
|
+
|
13
|
+
# KEY for regex tests
|
14
|
+
# :a == no change
|
15
|
+
# :b == will change (but sometimes ONLY once)
|
16
|
+
# :c == change to
|
17
|
+
|
18
|
+
include SexpMatchSpecials
|
19
|
+
|
20
|
+
def util_equals3(x, y)
|
21
|
+
result = x === y
|
22
|
+
assert_not_nil result, "#{x.inspect} does not === #{y.inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
@any = ANY()
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_stupid
|
30
|
+
# shuts up test/unit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TestSexp < SexpTestCase # ZenTest FULL
|
35
|
+
|
36
|
+
def util_pretty_print(expect, input)
|
37
|
+
io = StringIO.new
|
38
|
+
PP.pp(input, io)
|
39
|
+
io.rewind
|
40
|
+
assert_equal(expect, io.read.chomp)
|
41
|
+
end
|
42
|
+
|
43
|
+
def setup
|
44
|
+
super
|
45
|
+
@sexp_class = Object.const_get(self.class.name[4..-1])
|
46
|
+
@processor = SexpProcessor.new
|
47
|
+
@sexp = @sexp_class.new(1, 2, 3)
|
48
|
+
@basic_sexp = s(:lasgn, :var, s(:lit, 42))
|
49
|
+
@re = s(:lit, 42)
|
50
|
+
@bad1 = s(:lit, 24)
|
51
|
+
@bad1 = s(:blah, 42)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_class_from_array
|
55
|
+
# raise NotImplementedError, 'Need to write test_class_from_array'
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_class_index
|
59
|
+
# raise NotImplementedError, 'Need to write test_class_index'
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_accessors; end # handled
|
63
|
+
|
64
|
+
def test_accessors_equals
|
65
|
+
a = s(:call, s(:lit, 1), "func", s(:array, s(:lit, 2)))
|
66
|
+
a.accessors = [:lhs, :name, :rhs]
|
67
|
+
|
68
|
+
assert_equal a.accessors, [:lhs, :name, :rhs]
|
69
|
+
|
70
|
+
assert_equal s(:lit, 1), a.lhs
|
71
|
+
assert_equal "func", a.name
|
72
|
+
assert_equal s(:array, s(:lit, 2)), a.rhs
|
73
|
+
|
74
|
+
a.accessors = []
|
75
|
+
|
76
|
+
assert_raises NoMethodError do
|
77
|
+
a.lhs
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_array_type_eh
|
82
|
+
assert_equal false, @sexp.array_type?
|
83
|
+
@sexp.unshift :array
|
84
|
+
assert_equal true, @sexp.array_type?
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_each_of_type
|
88
|
+
# TODO: huh... this tests fails if top level sexp :b is removed
|
89
|
+
@sexp = s(:b, s(:a, s(:b, s(:a), :a, s(:b, :a), s(:b, s(:a)))))
|
90
|
+
count = 0
|
91
|
+
@sexp.each_of_type(:a) do |exp|
|
92
|
+
count += 1
|
93
|
+
end
|
94
|
+
assert_equal(3, count, "must find 3 a's in #{@sexp.inspect}")
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_equals2_array
|
98
|
+
# can't use assert_equals because it uses array as receiver
|
99
|
+
assert_not_equal(@sexp, [1, 2, 3],
|
100
|
+
"Sexp must not be equal to equivalent array")
|
101
|
+
# both directions just in case
|
102
|
+
# HACK - this seems to be a bug in ruby as far as I'm concerned
|
103
|
+
# assert_not_equal([1, 2, 3], @sexp,
|
104
|
+
# "Sexp must not be equal to equivalent array")
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_equals2_not_body
|
108
|
+
sexp2 = s(1, 2, 5)
|
109
|
+
assert_not_equal(@sexp, sexp2)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_equals2_sexp
|
113
|
+
sexp2 = s(1, 2, 3)
|
114
|
+
if @sexp.class == Sexp then
|
115
|
+
# sexp3 = t(1, 2, 3, Type.str)
|
116
|
+
# case @sexp
|
117
|
+
# when TypedSexp
|
118
|
+
# assert_equal(@sexp, sexp3)
|
119
|
+
# assert_not_equal(@sexp, sexp2)
|
120
|
+
# when Sexp
|
121
|
+
assert_equal(@sexp, sexp2)
|
122
|
+
# assert_not_equal(@sexp, sexp3)
|
123
|
+
else
|
124
|
+
assert_not_equal(@sexp, sexp2)
|
125
|
+
# else
|
126
|
+
# flunk "unknown type"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_equals3_any
|
131
|
+
util_equals3 @any, s()
|
132
|
+
util_equals3 @any, s(:a)
|
133
|
+
util_equals3 @any, s(:a, :b, s(:c))
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_equals3_full_match
|
137
|
+
util_equals3 s(), s() # 0
|
138
|
+
util_equals3 s(:blah), s(:blah) # 1
|
139
|
+
util_equals3 s(:a, :b), s(:a, :b) # 2
|
140
|
+
util_equals3 @basic_sexp, @basic_sexp.dup # deeper structure
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_equals3_mismatch
|
144
|
+
assert_nil s() === s(:a)
|
145
|
+
assert_nil s(:a) === s()
|
146
|
+
assert_nil s(:blah1) === s(:blah2)
|
147
|
+
assert_nil s(:a) === s(:a, :b)
|
148
|
+
assert_nil s(:a, :b) === s(:a)
|
149
|
+
assert_nil s(:a1, :b) === s(:a2, :b)
|
150
|
+
assert_nil s(:a, :b1) === s(:a, :b2)
|
151
|
+
assert_nil @basic_sexp === @basic_sexp.dup.push(42)
|
152
|
+
assert_nil @basic_sexp.dup.push(42) === @basic_sexp
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_equals3_subset_match
|
156
|
+
util_equals3 s(:a), s(s(:a), s(:b)) # left
|
157
|
+
util_equals3 s(:a), s(:blah, s(:a ), s(:b)) # mid 1
|
158
|
+
util_equals3 s(:a, 1), s(:blah, s(:a, 1), s(:b)) # mid 2
|
159
|
+
util_equals3 @basic_sexp, s(:blah, @basic_sexp.dup, s(:b)) # mid deeper
|
160
|
+
util_equals3 @basic_sexp, s(@basic_sexp.dup, s(:a), s(:b)) # left deeper
|
161
|
+
|
162
|
+
util_equals3 s(:a), s(:blah, s(:blah, s(:a))) # left deeper
|
163
|
+
end
|
164
|
+
|
165
|
+
# def test_equalstilde_any
|
166
|
+
# result = @basic_sexp =~ s(:lit, ANY())
|
167
|
+
# p result
|
168
|
+
# assert result
|
169
|
+
# end
|
170
|
+
|
171
|
+
def test_equalstilde_fancy
|
172
|
+
assert_nil s(:b) =~ s(:a, s(:b), :c)
|
173
|
+
assert_not_nil s(:a, s(:b), :c) =~ s(:b)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_equalstilde_plain
|
177
|
+
result = @basic_sexp =~ @re
|
178
|
+
assert result
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_find_and_replace_all
|
182
|
+
@sexp = s(:a, s(:b, s(:a), s(:b), s(:b, s(:a))))
|
183
|
+
expected = s(:a, s(:a, s(:a), s(:a), s(:a, s(:a))))
|
184
|
+
|
185
|
+
@sexp.find_and_replace_all(:b, :a)
|
186
|
+
|
187
|
+
assert_equal(expected, @sexp)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_gsub
|
191
|
+
assert_equal s(:c), s().gsub(s(), s(:c))
|
192
|
+
assert_equal s(:c), s(:b).gsub(s(:b), s(:c))
|
193
|
+
assert_equal s(:a), s(:a).gsub(s(:b), s(:c))
|
194
|
+
assert_equal s(:a, s(:c)), s(:a, s(:b)).gsub(s(:b), s(:c))
|
195
|
+
|
196
|
+
assert_equal(s(:a, s(:c), s(:c)),
|
197
|
+
s(:a, s(:b), s(:b)).gsub(s(:b), s(:c)))
|
198
|
+
assert_equal(s(:a, s(:c), s(:a, s(:c))),
|
199
|
+
s(:a, s(:b), s(:a, s(:b))).gsub(s(:b), s(:c)))
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_inspect
|
203
|
+
k = @sexp_class
|
204
|
+
n = k.name[0].chr.downcase
|
205
|
+
assert_equal("#{n}()",
|
206
|
+
k.new().inspect)
|
207
|
+
assert_equal("#{n}(:a)",
|
208
|
+
k.new(:a).inspect)
|
209
|
+
assert_equal("#{n}(:a, :b)",
|
210
|
+
k.new(:a, :b).inspect)
|
211
|
+
assert_equal("#{n}(:a, #{n}(:b))",
|
212
|
+
k.new(:a, k.new(:b)).inspect)
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_method_missing
|
216
|
+
assert_raises NoMethodError do
|
217
|
+
@sexp.no_such_method
|
218
|
+
end
|
219
|
+
|
220
|
+
@sexp.accessors = [:its_a_method_now]
|
221
|
+
|
222
|
+
assert_nothing_raised do
|
223
|
+
assert_equal 2, @sexp.its_a_method_now
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_pretty_print
|
228
|
+
util_pretty_print("s()",
|
229
|
+
s())
|
230
|
+
util_pretty_print("s(:a)",
|
231
|
+
s(:a))
|
232
|
+
util_pretty_print("s(:a, :b)",
|
233
|
+
s(:a, :b))
|
234
|
+
util_pretty_print("s(:a, s(:b))",
|
235
|
+
s(:a, s(:b)))
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_sexp_body
|
239
|
+
assert_equal [2, 3], @sexp.sexp_body
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_shift
|
243
|
+
assert_equal(1, @sexp.shift)
|
244
|
+
assert_equal(2, @sexp.shift)
|
245
|
+
assert_equal(3, @sexp.shift)
|
246
|
+
|
247
|
+
assert_raise(RuntimeError) do
|
248
|
+
@sexp.shift
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_structure
|
253
|
+
@sexp = s(:a, 1, 2, s(:b, 3, 4), 5, 6)
|
254
|
+
expected = s(:a, s(:b))
|
255
|
+
|
256
|
+
assert_equal(expected, @sexp.structure)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_sub
|
260
|
+
assert_equal s(:c), s().sub(s(), s(:c))
|
261
|
+
assert_equal s(:c), s(:b).sub(s(:b), s(:c))
|
262
|
+
assert_equal s(:a), s(:a).sub(s(:b), s(:c))
|
263
|
+
assert_equal s(:a, s(:c)), s(:a, s(:c)).sub(s(:b), s(:c))
|
264
|
+
|
265
|
+
assert_equal s(:a, s(:c), s(:b)), s(:a, s(:b), s(:b)).sub(s(:b), s(:c))
|
266
|
+
|
267
|
+
assert_equal(s(:a, s(:c), s(:a)),
|
268
|
+
s(:a, s(:b), s(:a)).sub(s(:b), s(:c)))
|
269
|
+
assert_equal(s(:a, s(:c), s(:a, s(:a))),
|
270
|
+
s(:a, s(:b), s(:a, s(:a))).sub(s(:b), s(:c)))
|
271
|
+
assert_equal(s(:a, s(:a), s(:a, s(:c), s(:b))),
|
272
|
+
s(:a, s(:a), s(:a, s(:b), s(:b))).sub(s(:b), s(:c)))
|
273
|
+
assert_equal(s(:a, s(:c, s(:b))),
|
274
|
+
s(:a, s(:b)).sub(s(:b), s(:c, s(:b))))
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_to_a
|
278
|
+
assert_equal([1, 2, 3], @sexp.to_a)
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_to_s
|
282
|
+
test_inspect
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
class TestSexpAny < SexpTestCase
|
287
|
+
|
288
|
+
def setup
|
289
|
+
super
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_equals3
|
293
|
+
util_equals3 @any, s()
|
294
|
+
util_equals3 @any, s(:a)
|
295
|
+
util_equals3 @any, s(:a, :b, s(:c))
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
data/test/test_sexp_processor.rb
CHANGED
@@ -78,156 +78,6 @@ end
|
|
78
78
|
|
79
79
|
# Real test classes:
|
80
80
|
|
81
|
-
class TestSexp < Test::Unit::TestCase # ZenTest FULL
|
82
|
-
|
83
|
-
def setup
|
84
|
-
@sexp_class = Object.const_get(self.class.name[4..-1])
|
85
|
-
@processor = SexpProcessor.new
|
86
|
-
@sexp = @sexp_class.new(1, 2, 3)
|
87
|
-
end
|
88
|
-
|
89
|
-
def test_new_nested
|
90
|
-
@sexp = s(:lasgn, "var", s(:str, "foo"))
|
91
|
-
assert_equal('s(:lasgn, "var", s(:str, "foo"))',
|
92
|
-
@sexp.inspect)
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_equals_array
|
96
|
-
# can't use assert_equals because it uses array as receiver
|
97
|
-
assert_not_equal(@sexp, [1, 2, 3],
|
98
|
-
"Sexp must not be equal to equivalent array")
|
99
|
-
# both directions just in case
|
100
|
-
# HACK - not sure why it is failing now that we split out TypedSexp
|
101
|
-
# assert_not_equal([1, 2, 3], @sexp,
|
102
|
-
# "Sexp must not be equal to equivalent array")
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_equals_sexp
|
106
|
-
sexp2 = s(1, 2, 3)
|
107
|
-
assert_equal(@sexp, sexp2)
|
108
|
-
end
|
109
|
-
|
110
|
-
def test_equals_not_body
|
111
|
-
sexp2 = s(1, 2, 5)
|
112
|
-
assert_not_equal(@sexp, sexp2)
|
113
|
-
end
|
114
|
-
|
115
|
-
def test_to_a
|
116
|
-
assert_equal([1, 2, 3], @sexp.to_a)
|
117
|
-
end
|
118
|
-
|
119
|
-
def test_accessors=
|
120
|
-
a = s(:call, s(:lit, 1), "func", s(:array, s(:lit, 2)))
|
121
|
-
a.accessors = [:lhs, :name, :rhs]
|
122
|
-
|
123
|
-
assert_equal a.accessors, [:lhs, :name, :rhs]
|
124
|
-
|
125
|
-
assert_equal s(:lit, 1), a.lhs
|
126
|
-
assert_equal "func", a.name
|
127
|
-
assert_equal s(:array, s(:lit, 2)), a.rhs
|
128
|
-
|
129
|
-
a.accessors = []
|
130
|
-
|
131
|
-
assert_raises NoMethodError do
|
132
|
-
a.lhs
|
133
|
-
end
|
134
|
-
end
|
135
|
-
def test_accessors; end # handled
|
136
|
-
|
137
|
-
def test_sexp_body
|
138
|
-
assert_equal [2, 3], @sexp.sexp_body
|
139
|
-
end
|
140
|
-
|
141
|
-
def test_array_type?
|
142
|
-
assert_equal false, @sexp.array_type?
|
143
|
-
@sexp.unshift :array
|
144
|
-
assert_equal true, @sexp.array_type?
|
145
|
-
end
|
146
|
-
|
147
|
-
def test_each_of_type
|
148
|
-
# TODO: huh... this tests fails if top level sexp :b is removed
|
149
|
-
@sexp = s(:b, s(:a, s(:b, s(:a), :a, s(:b, :a), s(:b, s(:a)))))
|
150
|
-
count = 0
|
151
|
-
@sexp.each_of_type(:a) do |exp|
|
152
|
-
count += 1
|
153
|
-
end
|
154
|
-
assert_equal(3, count, "must find 3 a's in #{@sexp.inspect}")
|
155
|
-
end
|
156
|
-
|
157
|
-
def test_find_and_replace_all
|
158
|
-
@sexp = s(:a, s(:b, s(:a), s(:b), s(:b, s(:a))))
|
159
|
-
expected = s(:a, s(:a, s(:a), s(:a), s(:a, s(:a))))
|
160
|
-
|
161
|
-
@sexp.find_and_replace_all(:b, :a)
|
162
|
-
|
163
|
-
assert_equal(expected, @sexp)
|
164
|
-
end
|
165
|
-
|
166
|
-
def test_structure
|
167
|
-
@sexp = s(:a, 1, 2, s(:b, 3, 4), 5, 6)
|
168
|
-
expected = s(:a, s(:b))
|
169
|
-
|
170
|
-
assert_equal(expected, @sexp.structure)
|
171
|
-
end
|
172
|
-
|
173
|
-
def test_method_missing
|
174
|
-
assert_raises NoMethodError do
|
175
|
-
@sexp.no_such_method
|
176
|
-
end
|
177
|
-
|
178
|
-
@sexp.accessors = [:its_a_method_now]
|
179
|
-
|
180
|
-
assert_nothing_raised do
|
181
|
-
assert_equal 2, @sexp.its_a_method_now
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def test_inspect
|
186
|
-
k = @sexp_class
|
187
|
-
n = k.name[0].chr.downcase
|
188
|
-
assert_equal("#{n}()",
|
189
|
-
k.new().inspect)
|
190
|
-
assert_equal("#{n}(:a)",
|
191
|
-
k.new(:a).inspect)
|
192
|
-
assert_equal("#{n}(:a, :b)",
|
193
|
-
k.new(:a, :b).inspect)
|
194
|
-
assert_equal("#{n}(:a, #{n}(:b))",
|
195
|
-
k.new(:a, k.new(:b)).inspect)
|
196
|
-
end
|
197
|
-
|
198
|
-
def test_to_s
|
199
|
-
test_inspect
|
200
|
-
end
|
201
|
-
|
202
|
-
def util_pretty_print(expect, input)
|
203
|
-
io = StringIO.new
|
204
|
-
PP.pp(input, io)
|
205
|
-
io.rewind
|
206
|
-
assert_equal(expect, io.read.chomp)
|
207
|
-
end
|
208
|
-
|
209
|
-
def test_pretty_print
|
210
|
-
util_pretty_print("s()",
|
211
|
-
s())
|
212
|
-
util_pretty_print("s(:a)",
|
213
|
-
s(:a))
|
214
|
-
util_pretty_print("s(:a, :b)",
|
215
|
-
s(:a, :b))
|
216
|
-
util_pretty_print("s(:a, s(:b))",
|
217
|
-
s(:a, s(:b)))
|
218
|
-
end
|
219
|
-
|
220
|
-
def test_shift
|
221
|
-
assert_equal(1, @sexp.shift)
|
222
|
-
assert_equal(2, @sexp.shift)
|
223
|
-
assert_equal(3, @sexp.shift)
|
224
|
-
|
225
|
-
assert_raise(RuntimeError) do
|
226
|
-
@sexp.shift
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
81
|
class TestSexpProcessor < Test::Unit::TestCase
|
232
82
|
|
233
83
|
def setup
|
metadata
CHANGED
@@ -1,69 +1,74 @@
|
|
1
|
-
|
2
|
-
rubygems_version: 0.8.
|
1
|
+
!ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11.1
|
3
3
|
specification_version: 1
|
4
4
|
name: ParseTree
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2005-07
|
6
|
+
version: 1.4.0
|
7
|
+
date: 2005-10-17 00:00:00 -07:00
|
8
8
|
summary: Extract and enumerate ruby parse trees.
|
9
9
|
require_paths:
|
10
|
-
|
11
|
-
|
10
|
+
- lib
|
11
|
+
- test
|
12
12
|
email: ryand-ruby@zenspider.com
|
13
13
|
homepage: http://www.zenspider.com/ZSS/Products/ParseTree/
|
14
14
|
rubyforge_project: parsetree
|
15
|
-
description:
|
16
|
-
an entire class or a specific method and returns it as a s-expression (aka sexp)
|
17
|
-
using ruby's arrays, strings, symbols, and integers."
|
15
|
+
description: ParseTree is a C extension (using RubyInline) that extracts the parse tree for an entire class or a specific method and returns it as a s-expression (aka sexp) using ruby's arrays, strings, symbols, and integers.
|
18
16
|
autorequire: parse_tree
|
19
17
|
default_executable:
|
20
18
|
bindir: bin
|
21
19
|
has_rdoc: true
|
22
20
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
23
21
|
requirements:
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
version: 0.0.0
|
22
|
+
- - ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
28
25
|
version:
|
29
26
|
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
30
29
|
authors:
|
31
|
-
|
30
|
+
- Ryan Davis
|
32
31
|
files:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
32
|
+
- History.txt
|
33
|
+
- Makefile
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
- bin/parse_tree_abc
|
37
|
+
- bin/parse_tree_deps
|
38
|
+
- bin/parse_tree_show
|
39
|
+
- demo/printer.rb
|
40
|
+
- lib/composite_sexp_processor.rb
|
41
|
+
- lib/parse_tree.rb
|
42
|
+
- lib/sexp.rb
|
43
|
+
- lib/sexp_processor.rb
|
44
|
+
- test/something.rb
|
45
|
+
- test/test_all.rb
|
46
|
+
- test/test_composite_sexp_processor.rb
|
47
|
+
- test/test_parse_tree.rb
|
48
|
+
- test/test_sexp.rb
|
49
|
+
- test/test_sexp_processor.rb
|
50
|
+
- validate.sh
|
49
51
|
test_files:
|
50
|
-
|
52
|
+
- test/test_all.rb
|
51
53
|
rdoc_options: []
|
54
|
+
|
52
55
|
extra_rdoc_files: []
|
56
|
+
|
53
57
|
executables:
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
- parse_tree_abc
|
59
|
+
- parse_tree_deps
|
60
|
+
- parse_tree_show
|
57
61
|
extensions: []
|
62
|
+
|
58
63
|
requirements: []
|
64
|
+
|
59
65
|
dependencies:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
version:
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: RubyInline
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 3.2.0
|
74
|
+
version:
|