ParseTree 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ *** 1.1.0 / 2004-11-12
2
+
3
+ + 2 minor enhancement
4
+ + Added SexpProcessor and CompositeSexpProcessor
5
+ + Allowed show.rb to read from standard input.
6
+ + 3 bug fixes
7
+ + Fixed makefile issues for BSD's make - so dumb.
8
+ + Added super as a call in abc.rb's metrics
9
+ + Commented out a compiler flag to work with GCC 2.95.
10
+
11
+
12
+ *** 1.0.0 / 2004-11-06
13
+
14
+ + 1 major enhancement
15
+ + Birthday!
@@ -0,0 +1,25 @@
1
+ RUBY?=ruby
2
+ RUBY_FLAGS?=-w -I.
3
+ RUBY_LIB?=$(shell $(RUBY) -rrbconfig -e 'include Config; print CONFIG["sitelibdir"]')
4
+ PREFIX?=/usr/local
5
+
6
+ all test:
7
+ $(RUBY) $(RUBY_FLAGS) test_all.rb
8
+
9
+ # we only install test_sexp_processor.rb to help make ruby_to_c's
10
+ # subclass tests work.
11
+
12
+ install:
13
+ cp -f parse_tree.rb test_sexp_processor.rb sexp_processor.rb composite_sexp_processor.rb $(RUBY_LIB)
14
+ cp -f parse_tree_show $(PREFIX)/bin
15
+ cp -f parse_tree_abc $(PREFIX)/bin
16
+ 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
+ chmod 555 $(PREFIX)/bin/parse_tree_show $(PREFIX)/bin/parse_tree_abc
18
+
19
+ uninstall:
20
+ 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
+ rm -f $(PREFIX)/bin/parse_tree_show $(PREFIX)/bin/parse_tree_abc
22
+
23
+ clean:
24
+ -rm *~ diff.txt
25
+ -rm -r $$HOME/.ruby_inline
@@ -0,0 +1,14 @@
1
+ History.txt
2
+ Makefile
3
+ Manifest.txt
4
+ README.txt
5
+ composite_sexp_processor.rb
6
+ parse_tree.rb
7
+ parse_tree_abc
8
+ parse_tree_show
9
+ sexp_processor.rb
10
+ something.rb
11
+ test_all.rb
12
+ test_composite_sexp_processor.rb
13
+ test_parse_tree.rb
14
+ test_sexp_processor.rb
@@ -0,0 +1,104 @@
1
+ ParseTree
2
+ http://www.zenspider.com/ZSS/Products/ParseTree/
3
+ support@zenspider.com
4
+
5
+ ** DESCRIPTION:
6
+
7
+ ParseTree is a C extension (using RubyInline) that extracts the parse
8
+ tree for an entire class or a specific method and returns it as a
9
+ s-expression (aka sexp) using ruby's arrays, strings, symbols, and
10
+ integers.
11
+
12
+ As an example:
13
+
14
+ def conditional1(arg1)
15
+ if arg1 == 0 then
16
+ return 1
17
+ end
18
+ return 0
19
+ end
20
+
21
+ becomes:
22
+
23
+ [:defn,
24
+ "conditional1",
25
+ [:scope,
26
+ [:block,
27
+ [:args, "arg1"],
28
+ [:if,
29
+ [:call, [:lvar, "arg1"], "==", [:array, [:lit, 0]]],
30
+ [:return, [:lit, 1]],
31
+ nil],
32
+ [:return, [:lit, 0]]]]]
33
+
34
+ ** FEATURES/PROBLEMS:
35
+
36
+ + Uses RubyInline, so it just drops in.
37
+ + Includes SexpProcessor and CompositeSexpProcessor.
38
+ + Allows you to write very clean filters.
39
+ + Includes show.rb, which lets you quickly snoop code.
40
+ + Includes abc.rb, which lets you get abc metrics on code.
41
+ + abc metrics = numbers of assignments, branches, and calls.
42
+ + whitespace independent metric for method complexity.
43
+ + Only works on methods in classes/modules, not arbitrary code.
44
+ + Does not work on the core classes, as they are not ruby (yet).
45
+
46
+ ** SYNOPSYS:
47
+
48
+ sexp_array = ParseTree.new.parse_tree(klass)
49
+
50
+ or:
51
+
52
+ class MyProcessor < SexpProcessor
53
+ def initialize
54
+ super
55
+ self.strict = false
56
+ end
57
+ def process_lit(exp)
58
+ val = exp.shift
59
+ return val
60
+ end
61
+ end
62
+
63
+ or:
64
+
65
+ % ./parse_tree_show myfile.rb
66
+
67
+ or:
68
+
69
+ % ./parse_tree_abc myfile.rb
70
+
71
+ ** REQUIREMENTS:
72
+
73
+ + RubyInline 3 or better.
74
+
75
+ ** INSTALL:
76
+
77
+ + sudo make install
78
+ + renames show.rb to parse_tree_show
79
+ + renames abc.rb to parse_tree_abc
80
+
81
+ ** LICENSE:
82
+
83
+ (The MIT License)
84
+
85
+ Copyright (c) 2001-2004 Ryan Davis, Zen Spider Software
86
+
87
+ Permission is hereby granted, free of charge, to any person obtaining
88
+ a copy of this software and associated documentation files (the
89
+ "Software"), to deal in the Software without restriction, including
90
+ without limitation the rights to use, copy, modify, merge, publish,
91
+ distribute, sublicense, and/or sell copies of the Software, and to
92
+ permit persons to whom the Software is furnished to do so, subject to
93
+ the following conditions:
94
+
95
+ The above copyright notice and this permission notice shall be
96
+ included in all copies or substantial portions of the Software.
97
+
98
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
99
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
100
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
101
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
102
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
103
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
104
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,24 @@
1
+ require 'sexp_processor'
2
+
3
+ class CompositeSexpProcessor < SexpProcessor
4
+
5
+ attr_reader :processors
6
+
7
+ def initialize(*processors)
8
+ super
9
+ @processors = []
10
+ end
11
+
12
+ def <<(processor)
13
+ raise ArgumentError, "Can only add sexp processors" unless
14
+ SexpProcessor === processor
15
+ @processors << processor
16
+ end
17
+
18
+ def process(exp)
19
+ @processors.each do |processor|
20
+ exp = processor.process(exp)
21
+ end
22
+ exp
23
+ end
24
+ end
@@ -0,0 +1,545 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ begin
4
+ require 'rubygems'
5
+ require_gem 'RubyInline'
6
+ rescue LoadError
7
+ require 'inline'
8
+ end
9
+
10
+ class ParseTree
11
+
12
+ VERSION = '1.1.0'
13
+
14
+ inline do |builder|
15
+ builder.add_type_converter("VALUE", '', '')
16
+ builder.add_type_converter("NODE *", '(NODE *)', '(VALUE)')
17
+ builder.include '"intern.h"'
18
+ builder.include '"node.h"'
19
+ builder.include '"st.h"'
20
+ builder.add_compile_flags "-Wall"
21
+ builder.add_compile_flags "-W"
22
+ builder.add_compile_flags "-Wpointer-arith"
23
+ builder.add_compile_flags "-Wcast-qual"
24
+ builder.add_compile_flags "-Wcast-align"
25
+ builder.add_compile_flags "-Wwrite-strings"
26
+ builder.add_compile_flags "-Wmissing-noreturn"
27
+ builder.add_compile_flags "-Werror"
28
+ # NOTE: this flag doesn't work w/ gcc 2.95.x - the FreeBSD default
29
+ # builder.add_compile_flags "-Wno-strict-aliasing"
30
+ # ruby.h screws these up hardcore:
31
+ # builder.add_compile_flags "-Wundef"
32
+ # builder.add_compile_flags "-Wconversion"
33
+ # builder.add_compile_flags "-Wstrict-prototypes"
34
+ # builder.add_compile_flags "-Wmissing-prototypes"
35
+ # builder.add_compile_flags "-Wsign-compare",
36
+
37
+ builder.prefix %q{
38
+ static char node_type_string[][60] = {
39
+ // 00
40
+ "method", "fbody", "cfunc", "scope", "block",
41
+ "if", "case", "when", "opt_n", "while",
42
+ // 10
43
+ "until", "iter", "for", "break", "next",
44
+ "redo", "retry", "begin", "rescue", "resbody",
45
+ // 20
46
+ "ensure", "and", "or", "not", "masgn",
47
+ "lasgn", "dasgn", "dasgn_curr", "gasgn", "iasgn",
48
+ // 30
49
+ "cdecl", "cvasgn", "cvdecl", "op_asgn1", "op_asgn2",
50
+ "op_asgn_and", "op_asgn_or", "call", "fcall", "vcall",
51
+ // 40
52
+ "super", "zsuper", "array", "zarray", "hash",
53
+ "return", "yield", "lvar", "dvar", "gvar",
54
+ // 50
55
+ "ivar", "const", "cvar", "nth_ref", "back_ref",
56
+ "match", "match2", "match3", "lit", "str",
57
+ // 60
58
+ "dstr", "xstr", "dxstr", "evstr", "dregx",
59
+ "dregx_once", "args", "argscat", "argspush", "splat",
60
+ // 70
61
+ "to_ary", "svalue", "block_arg", "block_pass", "defn",
62
+ "defs", "alias", "valias", "undef", "class",
63
+ // 80
64
+ "module", "sclass", "colon2", "colon3", "cref",
65
+ "dot2", "dot3", "flip2", "flip3", "attrset",
66
+ // 90
67
+ "self", "nil", "true", "false", "defined",
68
+ // 95
69
+ "newline", "postexe",
70
+ #ifdef C_ALLOCA
71
+ "alloca",
72
+ #endif
73
+ "dmethod", "bmethod",
74
+ // 100 / 99
75
+ "memo", "ifunc", "dsym", "attrasgn",
76
+ // 104 / 103
77
+ "last"
78
+ };
79
+ }
80
+
81
+ builder.c_raw %q^
82
+ // FIX!!!
83
+ static ID *dump_local_tbl;
84
+
85
+ static void add_to_parse_tree(VALUE ary, NODE * n) {
86
+ NODE * volatile node = n;
87
+ NODE * volatile contnode = NULL;
88
+ VALUE old_ary = Qnil;
89
+ VALUE current;
90
+ VALUE node_name;
91
+
92
+ if (!node) return;
93
+
94
+ again:
95
+
96
+ if (node) {
97
+ node_name = ID2SYM(rb_intern(node_type_string[nd_type(node)]));
98
+ } else {
99
+ node_name = ID2SYM(rb_intern("ICKY"));
100
+ }
101
+
102
+ current = rb_ary_new();
103
+ rb_ary_push(ary, current);
104
+ rb_ary_push(current, node_name);
105
+
106
+ again_no_block:
107
+
108
+ switch (nd_type(node)) {
109
+
110
+ case NODE_BLOCK:
111
+ if (contnode) {
112
+ add_to_parse_tree(current, node);
113
+ break;
114
+ }
115
+
116
+ contnode = node->nd_next;
117
+
118
+ // NOTE: this will break the moment there is a block w/in a block
119
+ old_ary = ary;
120
+ ary = current;
121
+ node = node->nd_head;
122
+ goto again;
123
+ break;
124
+
125
+ case NODE_FBODY:
126
+ case NODE_DEFINED:
127
+ add_to_parse_tree(current, node->nd_head);
128
+ break;
129
+
130
+ case NODE_COLON2:
131
+ add_to_parse_tree(current, node->nd_head);
132
+ rb_ary_push(current, rb_str_new2(rb_id2name(node->nd_mid)));
133
+ break;
134
+
135
+ case NODE_BEGIN:
136
+ node = node->nd_body;
137
+ goto again;
138
+
139
+ case NODE_MATCH2:
140
+ case NODE_MATCH3:
141
+ add_to_parse_tree(current, node->nd_recv);
142
+ add_to_parse_tree(current, node->nd_value);
143
+ break;
144
+
145
+ case NODE_OPT_N:
146
+ add_to_parse_tree(current, node->nd_body);
147
+ break;
148
+
149
+ case NODE_IF:
150
+ add_to_parse_tree(current, node->nd_cond);
151
+ if (node->nd_body) {
152
+ add_to_parse_tree(current, node->nd_body);
153
+ } else {
154
+ rb_ary_push(current, Qnil);
155
+ }
156
+ if (node->nd_else) {
157
+ add_to_parse_tree(current, node->nd_else);
158
+ } else {
159
+ rb_ary_push(current, Qnil);
160
+ }
161
+ break;
162
+
163
+ case NODE_CASE:
164
+ add_to_parse_tree(current, node->nd_head); /* expr */
165
+ node = node->nd_body;
166
+ while (node) {
167
+ add_to_parse_tree(current, node);
168
+ if (nd_type(node) == NODE_WHEN) { /* when */
169
+ node = node->nd_next;
170
+ } else {
171
+ break; /* else */
172
+ }
173
+ if (! node) {
174
+ rb_ary_push(current, Qnil); /* no else */
175
+ }
176
+ }
177
+ break;
178
+
179
+ case NODE_WHEN:
180
+ add_to_parse_tree(current, node->nd_head); /* args */
181
+ if (node->nd_body) {
182
+ add_to_parse_tree(current, node->nd_body); /* body */
183
+ } else {
184
+ rb_ary_push(current, Qnil);
185
+ }
186
+ break;
187
+
188
+ case NODE_WHILE:
189
+ case NODE_UNTIL:
190
+ add_to_parse_tree(current, node->nd_cond);
191
+ add_to_parse_tree(current, node->nd_body);
192
+ break;
193
+
194
+ case NODE_BLOCK_PASS:
195
+ add_to_parse_tree(current, node->nd_body);
196
+ add_to_parse_tree(current, node->nd_iter);
197
+ break;
198
+
199
+ case NODE_ITER:
200
+ case NODE_FOR:
201
+ add_to_parse_tree(current, node->nd_iter);
202
+ if (node->nd_var != (NODE *)-1 && node->nd_var != NULL) {
203
+ add_to_parse_tree(current, node->nd_var);
204
+ } else {
205
+ rb_ary_push(current, Qnil);
206
+ }
207
+ add_to_parse_tree(current, node->nd_body);
208
+ break;
209
+
210
+ case NODE_BREAK:
211
+ case NODE_NEXT:
212
+ case NODE_YIELD:
213
+ if (node->nd_stts)
214
+ add_to_parse_tree(current, node->nd_stts);
215
+ break;
216
+
217
+ case NODE_RESCUE:
218
+ {
219
+ NODE *resq, *n;
220
+ int i;
221
+
222
+ add_to_parse_tree(current, node->nd_head);
223
+ resq = node->nd_resq;
224
+ while (resq) {
225
+ if (nd_type(resq) == NODE_ARRAY) {
226
+ n = resq;
227
+ for (i = 0; i < resq->nd_alen; i++) {
228
+ add_to_parse_tree(current, n->nd_head);
229
+ n = n->nd_next;
230
+ }
231
+ } else {
232
+ add_to_parse_tree(current, resq->nd_args);
233
+ }
234
+ add_to_parse_tree(current, resq->nd_body);
235
+ resq = resq->nd_head;
236
+ }
237
+ if (node->nd_else) {
238
+ add_to_parse_tree(current, node->nd_else);
239
+ }
240
+ }
241
+ break;
242
+
243
+ case NODE_ENSURE:
244
+ add_to_parse_tree(current, node->nd_head);
245
+ if (node->nd_ensr) {
246
+ add_to_parse_tree(current, node->nd_ensr);
247
+ }
248
+ break;
249
+
250
+ case NODE_AND:
251
+ case NODE_OR:
252
+ add_to_parse_tree(current, node->nd_1st);
253
+ add_to_parse_tree(current, node->nd_2nd);
254
+ break;
255
+
256
+ case NODE_NOT:
257
+ add_to_parse_tree(current, node->nd_body);
258
+ break;
259
+
260
+ case NODE_DOT2:
261
+ case NODE_DOT3:
262
+ case NODE_FLIP2:
263
+ case NODE_FLIP3:
264
+ add_to_parse_tree(current, node->nd_beg);
265
+ add_to_parse_tree(current, node->nd_end);
266
+ break;
267
+
268
+ case NODE_RETURN:
269
+ if (node->nd_stts)
270
+ add_to_parse_tree(current, node->nd_stts);
271
+ break;
272
+
273
+ case NODE_ARGSCAT:
274
+ case NODE_ARGSPUSH:
275
+ add_to_parse_tree(current, node->nd_head);
276
+ add_to_parse_tree(current, node->nd_body);
277
+ break;
278
+
279
+ case NODE_CALL:
280
+ case NODE_FCALL:
281
+ case NODE_VCALL:
282
+ if (nd_type(node) != NODE_FCALL)
283
+ add_to_parse_tree(current, node->nd_recv);
284
+ rb_ary_push(current, rb_str_new2(rb_id2name(node->nd_mid)));
285
+ if (node->nd_args || nd_type(node) != NODE_FCALL)
286
+ add_to_parse_tree(current, node->nd_args);
287
+ break;
288
+
289
+ case NODE_SUPER:
290
+ add_to_parse_tree(current, node->nd_args);
291
+ break;
292
+
293
+ case NODE_DMETHOD:
294
+ {
295
+ struct METHOD *data;
296
+ Data_Get_Struct(node->nd_cval, struct METHOD, data);
297
+ break;
298
+ }
299
+
300
+ case NODE_SCOPE:
301
+ dump_local_tbl = node->nd_tbl;
302
+ add_to_parse_tree(current, node->nd_next);
303
+ break;
304
+
305
+ case NODE_OP_ASGN1:
306
+ add_to_parse_tree(current, node->nd_recv);
307
+ add_to_parse_tree(current, node->nd_args->nd_next);
308
+ add_to_parse_tree(current, node->nd_args->nd_head);
309
+ break;
310
+
311
+ case NODE_OP_ASGN2:
312
+ add_to_parse_tree(current, node->nd_recv);
313
+ add_to_parse_tree(current, node->nd_value);
314
+ break;
315
+
316
+ case NODE_OP_ASGN_AND:
317
+ case NODE_OP_ASGN_OR:
318
+ add_to_parse_tree(current, node->nd_head);
319
+ add_to_parse_tree(current, node->nd_value);
320
+ break;
321
+
322
+ case NODE_MASGN:
323
+ add_to_parse_tree(current, node->nd_head);
324
+ if (node->nd_args) {
325
+ if (node->nd_args != (NODE *)-1) {
326
+ add_to_parse_tree(current, node->nd_args);
327
+ }
328
+ }
329
+ add_to_parse_tree(current, node->nd_value);
330
+ break;
331
+
332
+ case NODE_LASGN:
333
+ case NODE_IASGN:
334
+ case NODE_DASGN:
335
+ case NODE_DASGN_CURR:
336
+ case NODE_CDECL:
337
+ case NODE_CVASGN:
338
+ case NODE_CVDECL:
339
+ case NODE_GASGN:
340
+ rb_ary_push(current, rb_str_new2(rb_id2name(node->nd_vid)));
341
+ add_to_parse_tree(current, node->nd_value);
342
+ break;
343
+
344
+ case NODE_HASH:
345
+ {
346
+ NODE *list;
347
+
348
+ list = node->nd_head;
349
+ while (list) {
350
+ add_to_parse_tree(current, list->nd_head);
351
+ list = list->nd_next;
352
+ if (list == 0)
353
+ rb_bug("odd number list for Hash");
354
+ add_to_parse_tree(current, list->nd_head);
355
+ list = list->nd_next;
356
+ }
357
+ }
358
+ break;
359
+
360
+ case NODE_ARRAY:
361
+ while (node) {
362
+ add_to_parse_tree(current, node->nd_head);
363
+ node = node->nd_next;
364
+ }
365
+ break;
366
+
367
+ case NODE_DSTR:
368
+ case NODE_DXSTR:
369
+ case NODE_DREGX:
370
+ case NODE_DREGX_ONCE:
371
+ {
372
+ NODE *list = node->nd_next;
373
+ if (nd_type(node) == NODE_DREGX || nd_type(node) == NODE_DREGX_ONCE) {
374
+ break;
375
+ }
376
+ rb_ary_push(current, rb_str_new3(node->nd_lit));
377
+ while (list) {
378
+ if (list->nd_head) {
379
+ switch (nd_type(list->nd_head)) {
380
+ case NODE_STR:
381
+ add_to_parse_tree(current, list->nd_head);
382
+ break;
383
+ case NODE_EVSTR:
384
+ add_to_parse_tree(current, list->nd_head->nd_body);
385
+ break;
386
+ default:
387
+ add_to_parse_tree(current, list->nd_head);
388
+ break;
389
+ }
390
+ }
391
+ list = list->nd_next;
392
+ }
393
+ }
394
+ break;
395
+
396
+ case NODE_DEFN:
397
+ case NODE_DEFS:
398
+ if (node->nd_defn) {
399
+ if (nd_type(node) == NODE_DEFS)
400
+ add_to_parse_tree(current, node->nd_recv);
401
+ rb_ary_push(current, rb_str_new2(rb_id2name(node->nd_mid)));
402
+ add_to_parse_tree(current, node->nd_defn);
403
+ }
404
+ break;
405
+
406
+ case NODE_CLASS:
407
+ case NODE_MODULE:
408
+ rb_ary_push(current, rb_str_new2(rb_id2name((ID)node->nd_cpath->nd_mid)));
409
+ if (node->nd_super && nd_type(node) == NODE_CLASS) {
410
+ add_to_parse_tree(current, node->nd_super);
411
+ }
412
+ add_to_parse_tree(current, node->nd_body);
413
+ break;
414
+
415
+ case NODE_SCLASS:
416
+ add_to_parse_tree(current, node->nd_recv);
417
+ add_to_parse_tree(current, node->nd_body);
418
+ break;
419
+
420
+ case NODE_ARGS:
421
+ if (dump_local_tbl &&
422
+ (node->nd_cnt || node->nd_opt || node->nd_rest != -1)) {
423
+ int i;
424
+ NODE *optnode;
425
+
426
+ for (i = 0; i < node->nd_cnt; i++) {
427
+ // regular arg names
428
+ rb_ary_push(current, rb_str_new2(rb_id2name(dump_local_tbl[i + 3])));
429
+ }
430
+
431
+ optnode = node->nd_opt;
432
+ while (optnode) {
433
+ // optional arg names
434
+ rb_ary_push(current, rb_str_new2(rb_id2name(dump_local_tbl[i + 3])));
435
+ i++;
436
+ optnode = optnode->nd_next;
437
+ }
438
+ if (node->nd_rest != -1) {
439
+ // *arg name
440
+ rb_ary_push(current, rb_str_new2(rb_id2name(dump_local_tbl[node->nd_rest + 1])));
441
+ }
442
+ optnode = node->nd_opt;
443
+ //
444
+ if (optnode) {
445
+ add_to_parse_tree(current, node->nd_opt);
446
+ }
447
+ }
448
+ break;
449
+
450
+ case NODE_LVAR:
451
+ case NODE_DVAR:
452
+ case NODE_IVAR:
453
+ case NODE_CVAR:
454
+ case NODE_GVAR:
455
+ case NODE_CONST:
456
+ case NODE_ATTRSET:
457
+ rb_ary_push(current, rb_str_new2(rb_id2name(node->nd_vid)));
458
+ break;
459
+
460
+ case NODE_STR:
461
+ case NODE_LIT:
462
+ rb_ary_push(current, node->nd_lit);
463
+ break;
464
+
465
+ case NODE_NEWLINE:
466
+ rb_ary_push(current, INT2FIX(nd_line(node)));
467
+ rb_ary_push(current, rb_str_new2(node->nd_file));
468
+ rb_ary_pop(ary); // nuke it for now
469
+
470
+ node = node->nd_next;
471
+ goto again;
472
+
473
+ // these are things we know we do not need to translate to C.
474
+ case NODE_BLOCK_ARG:
475
+ case NODE_SELF:
476
+ case NODE_NIL:
477
+ case NODE_TRUE:
478
+ case NODE_FALSE:
479
+ case NODE_ZSUPER:
480
+ case NODE_BMETHOD:
481
+ case NODE_REDO:
482
+ case NODE_RETRY:
483
+ case NODE_COLON3:
484
+ case NODE_NTH_REF:
485
+ case NODE_BACK_REF:
486
+ case NODE_ZARRAY:
487
+ case NODE_XSTR:
488
+ case NODE_UNDEF:
489
+ case NODE_ALIAS:
490
+ case NODE_VALIAS:
491
+ break;
492
+
493
+ default:
494
+ rb_ary_push(current, INT2FIX(-99));
495
+ rb_ary_push(current, INT2FIX(nd_type(node)));
496
+ break;
497
+ }
498
+
499
+ // finish:
500
+ if (contnode) {
501
+ node = contnode;
502
+ contnode = NULL;
503
+ current = ary;
504
+ ary = old_ary;
505
+ old_ary = Qnil;
506
+ goto again_no_block;
507
+ }
508
+ }
509
+ ^
510
+
511
+ builder.c %q{
512
+ static VALUE parse_tree_for_method(VALUE klass, VALUE method) {
513
+ NODE *node = NULL;
514
+ ID id;
515
+ VALUE result = rb_ary_new();
516
+
517
+ (void) self; // quell warnings
518
+
519
+ id = rb_to_id(method);
520
+ if (st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *) &node)) {
521
+ rb_ary_push(result, ID2SYM(rb_intern("defn")));
522
+ rb_ary_push(result, method);
523
+ add_to_parse_tree(result, node->nd_body);
524
+ } else {
525
+ rb_ary_push(result, Qnil);
526
+ }
527
+
528
+ return result;
529
+ }
530
+ }
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