ParseTree 1.1.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.
@@ -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