virtual_keywords 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/lib/parsetree/History.txt +477 -0
  2. data/lib/parsetree/Manifest.txt +19 -0
  3. data/lib/parsetree/README.txt +97 -0
  4. data/lib/parsetree/Rakefile +37 -0
  5. data/lib/parsetree/bin/parse_tree_abc +89 -0
  6. data/lib/parsetree/bin/parse_tree_audit +28 -0
  7. data/lib/parsetree/bin/parse_tree_deps +62 -0
  8. data/lib/parsetree/bin/parse_tree_show +63 -0
  9. data/lib/parsetree/demo/printer.rb +20 -0
  10. data/lib/parsetree/lib/gauntlet_parsetree.rb +121 -0
  11. data/lib/parsetree/lib/parse_tree.rb +1202 -0
  12. data/lib/parsetree/lib/parse_tree_extensions.rb +59 -0
  13. data/lib/parsetree/lib/unified_ruby.rb +421 -0
  14. data/lib/parsetree/test/something.rb +53 -0
  15. data/lib/parsetree/test/test_parse_tree.rb +2567 -0
  16. data/lib/parsetree/test/test_parse_tree_extensions.rb +107 -0
  17. data/lib/parsetree/test/test_unified_ruby.rb +57 -0
  18. data/lib/parsetree/validate.sh +31 -0
  19. data/lib/sexps/{count_to_ten_sexp.txt → count_to_ten_sexp.rb} +0 -0
  20. data/lib/sexps/{sexps_and.txt → sexps_and.rb} +0 -0
  21. data/lib/sexps/{sexps_case_when.txt → sexps_case_when.rb} +0 -0
  22. data/lib/sexps/{sexps_greet.txt → sexps_greet.rb} +0 -0
  23. data/lib/sexps/sexps_not.rb +24 -0
  24. data/lib/sexps/{sexps_rewritten_keywords.txt → sexps_rewritten_keywords.rb} +0 -0
  25. data/lib/sexps/{sexps_symbolic_and.txt → sexps_symbolic_and.rb} +0 -0
  26. data/lib/sexps/sexps_until.rb +60 -0
  27. data/lib/sexps/{sexps_while.txt → sexps_while.rb} +0 -0
  28. data/lib/spec/class_reflection_spec.rb +64 -0
  29. data/lib/spec/keyword_rewriter_spec.rb +7 -54
  30. data/lib/spec/not_rewriter_spec.rb +25 -0
  31. data/lib/spec/parser_strategy_spec.rb +23 -0
  32. data/lib/spec/sexp_stringifier_spec.rb +19 -0
  33. data/lib/spec/spec_helper.rb +61 -307
  34. data/lib/spec/until_rewriter_spec.rb +26 -0
  35. data/lib/spec/virtualizees/and_user.rb +17 -0
  36. data/lib/spec/virtualizees/case_when_user.rb +20 -0
  37. data/lib/spec/virtualizees/fizzbuzzer.rb +15 -0
  38. data/lib/spec/virtualizees/greeter.rb +127 -0
  39. data/lib/spec/virtualizees/not_user.rb +9 -0
  40. data/lib/spec/virtualizees/operator_user.rb +15 -0
  41. data/lib/spec/virtualizees/or_user.rb +17 -0
  42. data/lib/spec/virtualizees/parents.rb +8 -0
  43. data/lib/spec/virtualizees/until_user.rb +16 -0
  44. data/lib/spec/virtualizees/while_user.rb +16 -0
  45. data/lib/spec/virtualizer_spec.rb +46 -83
  46. data/lib/virtual_keywords/class_reflection.rb +88 -0
  47. data/lib/virtual_keywords/deep_copy_array.rb +12 -0
  48. data/lib/virtual_keywords/keyword_rewriter.rb +54 -0
  49. data/lib/virtual_keywords/parser_strategy.rb +40 -0
  50. data/lib/virtual_keywords/rewritten_keywords.rb +15 -0
  51. data/lib/virtual_keywords/sexp_stringifier.rb +1 -5
  52. data/lib/virtual_keywords/version.rb +1 -1
  53. data/lib/virtual_keywords/virtualizer.rb +30 -115
  54. data/lib/virtual_keywords.rb +31 -5
  55. metadata +117 -90
  56. data/lib/spec/class_mirrorer_spec.rb +0 -18
  57. data/lib/virtual_keywords/class_mirrorer.rb +0 -39
@@ -0,0 +1,1202 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ raise LoadError, "ParseTree doesn't work with ruby #{RUBY_VERSION}" if
4
+ RUBY_VERSION >= "1.9"
5
+ raise LoadError, "ParseTree isn't needed with rubinius" if
6
+ defined? RUBY_ENGINE and RUBY_ENGINE == "rbx"
7
+
8
+ begin; require 'rubygems'; rescue LoadError; end
9
+ require 'inline'
10
+ require 'unified_ruby'
11
+
12
+ class Module
13
+ def modules
14
+ ancestors[1..-1]
15
+ end
16
+ end
17
+
18
+ class Class
19
+ def modules
20
+ a = self.ancestors
21
+ a[1..a.index(superclass)-1]
22
+ end
23
+ end
24
+
25
+ ##
26
+ # ParseTree is a RubyInline-style extension that accesses and
27
+ # traverses the internal parse tree created by ruby.
28
+ #
29
+ # class Example
30
+ # def blah
31
+ # return 1 + 1
32
+ # end
33
+ # end
34
+ #
35
+ # ParseTree.new.parse_tree(Example)
36
+ # => [[:class, :Example, :Object,
37
+ # [:defn,
38
+ # "blah",
39
+ # [:scope,
40
+ # [:block,
41
+ # [:args],
42
+ # [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]
43
+
44
+ class RawParseTree
45
+
46
+ VERSION = '3.0.9'
47
+
48
+ ##
49
+ # Front end translation method.
50
+
51
+ def self.translate(klass_or_str, method=nil)
52
+ pt = self.new(false)
53
+ case klass_or_str
54
+ when String then
55
+ sexp = pt.parse_tree_for_string(klass_or_str).first
56
+ if method then
57
+ # class, scope, block, *methods
58
+ sexp.last.last[1..-1].find do |defn|
59
+ defn[1] == method
60
+ end
61
+ else
62
+ sexp
63
+ end
64
+ else
65
+ unless method.nil? then
66
+ if method.to_s =~ /^self\./ then
67
+ method = method.to_s[5..-1].intern
68
+ pt.parse_tree_for_method(klass_or_str, method, true)
69
+ else
70
+ pt.parse_tree_for_method(klass_or_str, method)
71
+ end
72
+ else
73
+ pt.parse_tree(klass_or_str).first
74
+ end
75
+ end
76
+ end
77
+
78
+ ##
79
+ # Initializes a ParseTree instance. Includes newline nodes if
80
+ # +include_newlines+ which defaults to +$DEBUG+.
81
+
82
+ def initialize(include_newlines=$DEBUG)
83
+ @include_newlines = include_newlines
84
+ end
85
+
86
+ ##
87
+ # Main driver for ParseTree. Returns an array of arrays containing
88
+ # the parse tree for +klasses+.
89
+ #
90
+ # Structure:
91
+ #
92
+ # [[:class, classname, superclassname, [:defn :method1, ...], ...], ...]
93
+ #
94
+ # NOTE: v1.0 - v1.1 had the signature (klass, meth=nil). This wasn't
95
+ # used much at all and since parse_tree_for_method already existed,
96
+ # it was deemed more useful to expand this method to do multiple
97
+ # classes.
98
+
99
+ def parse_tree(*klasses)
100
+ result = []
101
+ klasses.each do |klass|
102
+ klassname = klass.name rescue '' # HACK klass.name should never be nil
103
+ # Tempfile's DelegateClass(File) seems to
104
+ # cause this
105
+ klassname = "UnnamedClass_#{klass.object_id}" if klassname.empty?
106
+ klassname = klassname.to_sym
107
+
108
+ code = if Class === klass then
109
+ sc = klass.superclass
110
+ sc_name = ((sc.nil? or sc.name.empty?) ? "nil" : sc.name).intern
111
+ [:class, klassname, [:const, sc_name]]
112
+ else
113
+ [:module, klassname]
114
+ end
115
+
116
+ method_names = []
117
+ method_names += klass.instance_methods false
118
+ method_names += klass.private_instance_methods false
119
+ # protected methods are included in instance_methods, go figure!
120
+
121
+ method_names.sort.each do |m|
122
+ r = parse_tree_for_method(klass, m.to_sym)
123
+ code << r
124
+ end
125
+
126
+ mods = klass.modules
127
+ mods -= mods.map { |mod| mod.modules }.flatten
128
+
129
+ mods.each do |mod| # TODO: add a test for this damnit
130
+ code << process("include #{mod}")
131
+ end
132
+
133
+ klass.singleton_methods(false).sort.each do |m|
134
+ code << parse_tree_for_method(klass, m.to_sym, true)
135
+ end
136
+
137
+ result << code
138
+ end
139
+ return result
140
+ end
141
+
142
+ ##
143
+ # Returns the parse tree for just one +method+ of a class +klass+.
144
+ #
145
+ # Format:
146
+ #
147
+ # [:defn, :name, :body]
148
+
149
+ def parse_tree_for_method(klass, method, is_cls_meth=false, verbose = true)
150
+ $stderr.puts "** parse_tree_for_method(#{klass}, #{method}):" if $DEBUG
151
+ old_verbose, $VERBOSE = $VERBOSE, verbose
152
+ r = parse_tree_for_meth(klass, method.to_sym, is_cls_meth)
153
+ r
154
+ ensure
155
+ $VERBOSE = old_verbose
156
+ end
157
+
158
+ ##
159
+ # Returns the parse tree for a string +source+.
160
+ #
161
+ # Format:
162
+ #
163
+ # [[sexps] ... ]
164
+
165
+ def parse_tree_for_string(source,
166
+ filename = '(string)', line = 1, verbose = true)
167
+ old_verbose, $VERBOSE = $VERBOSE, verbose
168
+ return parse_tree_for_str0(source, filename, line)
169
+ ensure
170
+ $VERBOSE = old_verbose
171
+ end
172
+
173
+ def parse_tree_for_str0(*__1args2__) # :nodoc:
174
+ parse_tree_for_str(*__1args2__) # just helps clean up the binding
175
+ end
176
+
177
+ if RUBY_VERSION < "1.8.4" then
178
+ inline do |builder|
179
+ builder.add_type_converter("bool", '', '')
180
+ builder.c_singleton "
181
+ bool has_alloca() {
182
+ (void)self;
183
+ #ifdef C_ALLOCA
184
+ return Qtrue;
185
+ #else
186
+ return Qfalse;
187
+ #endif
188
+ }"
189
+ end
190
+ else
191
+ def self.has_alloca
192
+ true
193
+ end
194
+ end
195
+
196
+
197
+ NODE_NAMES = [
198
+ # 00
199
+ :method, :fbody, :cfunc, :scope, :block,
200
+ :if, :case, :when, :opt_n, :while,
201
+ # 10
202
+ :until, :iter, :for, :break, :next,
203
+ :redo, :retry, :begin, :rescue, :resbody,
204
+ # 20
205
+ :ensure, :and, :or, :not, :masgn,
206
+ :lasgn, :dasgn, :dasgn_curr, :gasgn, :iasgn,
207
+ # 30
208
+ :cdecl, :cvasgn, :cvdecl, :op_asgn1, :op_asgn2,
209
+ :op_asgn_and, :op_asgn_or, :call, :fcall, :vcall,
210
+ # 40
211
+ :super, :zsuper, :array, :zarray, :hash,
212
+ :return, :yield, :lvar, :dvar, :gvar,
213
+ # 50
214
+ :ivar, :const, :cvar, :nth_ref, :back_ref,
215
+ :match, :match2, :match3, :lit, :str,
216
+ # 60
217
+ :dstr, :xstr, :dxstr, :evstr, :dregx,
218
+ :dregx_once, :args, :argscat, :argspush, :splat,
219
+ # 70
220
+ :to_ary, :svalue, :block_arg, :block_pass, :defn,
221
+ :defs, :alias, :valias, :undef, :class,
222
+ # 80
223
+ :module, :sclass, :colon2, :colon3, :cref,
224
+ :dot2, :dot3, :flip2, :flip3, :attrset,
225
+ # 90
226
+ :self, :nil, :true, :false, :defined,
227
+ # 95
228
+ :newline, :postexe, :alloca, :dmethod, :bmethod,
229
+ # 100
230
+ :memo, :ifunc, :dsym, :attrasgn,
231
+ :last
232
+ ]
233
+
234
+ if RUBY_VERSION < "1.8.4" then
235
+ NODE_NAMES.delete :alloca unless has_alloca
236
+ end
237
+
238
+ if RUBY_VERSION > "1.9" then
239
+ NODE_NAMES.insert NODE_NAMES.index(:hash), :values
240
+ NODE_NAMES.insert NODE_NAMES.index(:defined), :errinfo
241
+ NODE_NAMES.insert NODE_NAMES.index(:last), :prelude, :lambda
242
+ NODE_NAMES.delete :dmethod
243
+ NODE_NAMES[128] = NODE_NAMES.delete :newline
244
+ end
245
+
246
+ ############################################################
247
+ # END of rdoc methods
248
+ ############################################################
249
+
250
+ inline do |builder|
251
+ builder.add_type_converter("bool", '', '')
252
+ builder.add_type_converter("ID *", '', '')
253
+ builder.add_type_converter("NODE *", '(NODE *)', '(VALUE)')
254
+ builder.include '"intern.h"'
255
+ builder.include '"version.h"'
256
+ builder.include '"rubysig.h"'
257
+ builder.include '"node.h"'
258
+ builder.include '"st.h"'
259
+ builder.include '"env.h"'
260
+
261
+ builder.prefix '#define _sym(s) ID2SYM(rb_intern((s)))'
262
+
263
+ if RUBY_VERSION < "1.8.6" then
264
+ builder.prefix '#define RARRAY_PTR(s) (RARRAY(s)->ptr)'
265
+ builder.prefix '#define RARRAY_LEN(s) (RARRAY(s)->len)'
266
+ end
267
+
268
+ if ENV['ANAL'] or ENV['DOMAIN'] =~ /zenspider/ then
269
+ builder.add_compile_flags "-Wall"
270
+ builder.add_compile_flags "-W"
271
+ builder.add_compile_flags "-Wpointer-arith"
272
+ builder.add_compile_flags "-Wcast-qual"
273
+ builder.add_compile_flags "-Wcast-align"
274
+ builder.add_compile_flags "-Wwrite-strings"
275
+ builder.add_compile_flags "-Wmissing-noreturn"
276
+ builder.add_compile_flags "-Wno-long-long"
277
+
278
+ # NOTE: this flag doesn't work w/ gcc 2.95.x - the FreeBSD default
279
+ builder.add_compile_flags "-Wno-strict-aliasing"
280
+
281
+ # ruby.h screws these up hardcore:
282
+ # builder.add_compile_flags "-Wundef"
283
+ # builder.add_compile_flags "-Wconversion"
284
+ # builder.add_compile_flags "-Wstrict-prototypes"
285
+ # builder.add_compile_flags "-Wmissing-prototypes"
286
+ # builder.add_compile_flags "-Wsign-compare"
287
+ end
288
+
289
+ # NOTE: If you get weird compiler errors like:
290
+ # dereferencing type-punned pointer will break strict-aliasing rules
291
+ # PLEASE do one of the following:
292
+ # 1) Get me a login on your box so I can repro this and get it fixed.
293
+ # 2) Fix it and send me the patch
294
+ # 3) (quick, but dirty and bad), comment out the following line:
295
+ builder.add_compile_flags "-Werror" unless RUBY_PLATFORM =~ /mswin/
296
+
297
+ builder.prefix %{
298
+ #define nd_3rd u3.node
299
+ static unsigned case_level = 0;
300
+ static unsigned when_level = 0;
301
+ static unsigned inside_case_args = 0;
302
+ static int masgn_level = 0;
303
+ }
304
+
305
+ builder.prefix %{
306
+ static VALUE wrap_into_node(const char * name, VALUE val) {
307
+ VALUE n = rb_ary_new();
308
+ rb_ary_push(n, _sym(name));
309
+ if (val) rb_ary_push(n, val);
310
+ return n;
311
+ }
312
+ }
313
+
314
+ builder.prefix %{
315
+ struct METHOD {
316
+ VALUE klass, rklass;
317
+ VALUE recv;
318
+ ID id, oid;
319
+ #if RUBY_VERSION_CODE > 182
320
+ int safe_level;
321
+ #endif
322
+ NODE *body;
323
+ };
324
+
325
+ struct BLOCK {
326
+ NODE *var;
327
+ NODE *body;
328
+ VALUE self;
329
+ struct FRAME frame;
330
+ struct SCOPE *scope;
331
+ VALUE klass;
332
+ NODE *cref;
333
+ int iter;
334
+ int vmode;
335
+ int flags;
336
+ int uniq;
337
+ struct RVarmap *dyna_vars;
338
+ VALUE orig_thread;
339
+ VALUE wrapper;
340
+ VALUE block_obj;
341
+ struct BLOCK *outer;
342
+ struct BLOCK *prev;
343
+ };
344
+ } unless RUBY_VERSION >= "1.9" # we got matz to add this to env.h
345
+
346
+ ##
347
+ # add_to_parse_tree(self, ary, node, local_variables)
348
+
349
+ builder.prefix %Q@
350
+ void add_to_parse_tree(VALUE self, VALUE ary, NODE * n, ID * locals) {
351
+ NODE * volatile node = n;
352
+ VALUE current;
353
+ VALUE node_name;
354
+ static VALUE node_names = Qnil;
355
+
356
+ if (NIL_P(node_names)) {
357
+ node_names = rb_const_get_at(rb_path2class("RawParseTree"),rb_intern("NODE_NAMES"));
358
+ }
359
+
360
+ if (!node) return;
361
+
362
+ again:
363
+
364
+ if (node) {
365
+ node_name = rb_ary_entry(node_names, nd_type(node));
366
+ if (RTEST(ruby_debug)) {
367
+ fprintf(stderr, "%15s: %s%s%s\\n",
368
+ rb_id2name(SYM2ID(node_name)),
369
+ (RNODE(node)->u1.node != NULL ? "u1 " : " "),
370
+ (RNODE(node)->u2.node != NULL ? "u2 " : " "),
371
+ (RNODE(node)->u3.node != NULL ? "u3 " : " "));
372
+ }
373
+ } else {
374
+ node_name = _sym("ICKY");
375
+ }
376
+
377
+ current = rb_ary_new();
378
+ rb_ary_push(ary, current);
379
+ rb_ary_push(current, node_name);
380
+
381
+ switch (nd_type(node)) {
382
+
383
+ case NODE_BLOCK:
384
+ {
385
+ while (node) {
386
+ add_to_parse_tree(self, current, node->nd_head, locals);
387
+ node = node->nd_next;
388
+ }
389
+ if (!masgn_level && RARRAY_LEN(current) == 2) {
390
+ rb_ary_pop(ary);
391
+ rb_ary_push(ary, rb_ary_pop(current));
392
+ return;
393
+ }
394
+ }
395
+ break;
396
+
397
+ case NODE_FBODY:
398
+ case NODE_DEFINED:
399
+ add_to_parse_tree(self, current, node->nd_head, locals);
400
+ break;
401
+
402
+ case NODE_COLON2:
403
+ add_to_parse_tree(self, current, node->nd_head, locals);
404
+ rb_ary_push(current, ID2SYM(node->nd_mid));
405
+ break;
406
+
407
+ case NODE_MATCH2:
408
+ case NODE_MATCH3:
409
+ add_to_parse_tree(self, current, node->nd_recv, locals);
410
+ add_to_parse_tree(self, current, node->nd_value, locals);
411
+ break;
412
+
413
+ case NODE_BEGIN:
414
+ case NODE_OPT_N:
415
+ case NODE_NOT:
416
+ add_to_parse_tree(self, current, node->nd_body, locals);
417
+ break;
418
+
419
+ case NODE_IF:
420
+ add_to_parse_tree(self, current, node->nd_cond, locals);
421
+ if (node->nd_body) {
422
+ add_to_parse_tree(self, current, node->nd_body, locals);
423
+ } else {
424
+ rb_ary_push(current, Qnil);
425
+ }
426
+ if (node->nd_else) {
427
+ add_to_parse_tree(self, current, node->nd_else, locals);
428
+ } else {
429
+ rb_ary_push(current, Qnil);
430
+ }
431
+ break;
432
+
433
+ case NODE_CASE:
434
+ case_level++;
435
+ if (node->nd_head != NULL) {
436
+ add_to_parse_tree(self, current, node->nd_head, locals); /* expr */
437
+ } else {
438
+ rb_ary_push(current, Qnil);
439
+ }
440
+ node = node->nd_body;
441
+ while (node) {
442
+ add_to_parse_tree(self, current, node, locals);
443
+ if (nd_type(node) == NODE_WHEN) { /* when */
444
+ node = node->nd_next;
445
+ } else {
446
+ break; /* else */
447
+ }
448
+ if (! node) {
449
+ rb_ary_push(current, Qnil); /* no else */
450
+ }
451
+ }
452
+ case_level--;
453
+ break;
454
+
455
+ case NODE_WHEN:
456
+ when_level++;
457
+ if (!inside_case_args && case_level < when_level) { /* when without case, ie, no expr in case */
458
+ if (when_level > 0) when_level--;
459
+ rb_ary_pop(ary); /* reset what current is pointing at */
460
+ node = NEW_CASE(0, node);
461
+ goto again;
462
+ }
463
+ inside_case_args++;
464
+ add_to_parse_tree(self, current, node->nd_head, locals); /* args */
465
+ inside_case_args--;
466
+
467
+ if (node->nd_body) {
468
+ add_to_parse_tree(self, current, node->nd_body, locals); /* body */
469
+ } else {
470
+ rb_ary_push(current, Qnil);
471
+ }
472
+
473
+ if (when_level > 0) when_level--;
474
+ break;
475
+
476
+ case NODE_WHILE:
477
+ case NODE_UNTIL:
478
+ add_to_parse_tree(self, current, node->nd_cond, locals);
479
+ if (node->nd_body) {
480
+ add_to_parse_tree(self, current, node->nd_body, locals);
481
+ } else {
482
+ rb_ary_push(current, Qnil);
483
+ }
484
+ rb_ary_push(current, node->nd_3rd == 0 ? Qfalse : Qtrue);
485
+ break;
486
+
487
+ case NODE_BLOCK_PASS:
488
+ add_to_parse_tree(self, current, node->nd_body, locals);
489
+ if (node->nd_iter != (NODE *)1) {
490
+ add_to_parse_tree(self, current, node->nd_iter, locals);
491
+ }
492
+ break;
493
+
494
+ case NODE_ITER:
495
+ case NODE_FOR:
496
+ add_to_parse_tree(self, current, node->nd_iter, locals);
497
+ masgn_level++;
498
+ if (node->nd_var != (NODE *)1
499
+ && node->nd_var != (NODE *)2
500
+ && node->nd_var != NULL) {
501
+ add_to_parse_tree(self, current, node->nd_var, locals);
502
+ } else {
503
+ if (node->nd_var == NULL) {
504
+ // e.g. proc {}
505
+ rb_ary_push(current, Qnil);
506
+ } else {
507
+ // e.g. proc {||}
508
+ rb_ary_push(current, INT2FIX(0));
509
+ }
510
+ }
511
+ masgn_level--;
512
+ add_to_parse_tree(self, current, node->nd_body, locals);
513
+ break;
514
+
515
+ case NODE_BREAK:
516
+ case NODE_NEXT:
517
+ if (node->nd_stts)
518
+ add_to_parse_tree(self, current, node->nd_stts, locals);
519
+
520
+ break;
521
+
522
+ case NODE_YIELD:
523
+ if (node->nd_stts)
524
+ add_to_parse_tree(self, current, node->nd_stts, locals);
525
+
526
+ // if node is newline, it is aref_args w/ a splat, eg: yield([*[1]])
527
+ if (node->nd_stts && nd_type(node->nd_stts) == NODE_NEWLINE)
528
+ rb_ary_push(current, Qtrue);
529
+
530
+ // array is an array, not list of args
531
+ if (node->nd_stts
532
+ && (nd_type(node->nd_stts) == NODE_ARRAY
533
+ || nd_type(node->nd_stts) == NODE_ZARRAY)
534
+ && !node->nd_state)
535
+ rb_ary_push(current, Qtrue);
536
+
537
+ break;
538
+
539
+ case NODE_RESCUE:
540
+ add_to_parse_tree(self, current, node->nd_1st, locals);
541
+ add_to_parse_tree(self, current, node->nd_2nd, locals);
542
+ add_to_parse_tree(self, current, node->nd_3rd, locals);
543
+ break;
544
+
545
+ /*
546
+ // rescue body:
547
+ // begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
548
+ // stmt rescue stmt
549
+ // a = b rescue c
550
+ */
551
+
552
+ case NODE_RESBODY:
553
+ if (node->nd_3rd) {
554
+ add_to_parse_tree(self, current, node->nd_3rd, locals);
555
+ } else {
556
+ rb_ary_push(current, Qnil);
557
+ }
558
+ add_to_parse_tree(self, current, node->nd_2nd, locals);
559
+ add_to_parse_tree(self, current, node->nd_1st, locals);
560
+ break;
561
+
562
+ case NODE_ENSURE:
563
+ add_to_parse_tree(self, current, node->nd_head, locals);
564
+ if (node->nd_ensr) {
565
+ add_to_parse_tree(self, current, node->nd_ensr, locals);
566
+ }
567
+ break;
568
+
569
+ case NODE_AND:
570
+ case NODE_OR:
571
+ add_to_parse_tree(self, current, node->nd_1st, locals);
572
+ add_to_parse_tree(self, current, node->nd_2nd, locals);
573
+ break;
574
+
575
+ case NODE_FLIP2:
576
+ case NODE_FLIP3:
577
+ if (nd_type(node->nd_beg) == NODE_LIT) {
578
+ /*
579
+ new somewhere between 1.8.6 p287 to p368 and 1.8.7 p72 to p160.
580
+ [:flip2, [:call, [:lit, 1], :==, [:array, [:gvar, :$.]]],
581
+ */
582
+ VALUE result = rb_ary_new3(1, _sym("call"));
583
+ add_to_parse_tree(self, result, node->nd_beg, locals);
584
+ rb_ary_push(result, _sym("=="));
585
+ rb_ary_push(result, rb_ary_new3(2, _sym("array"),
586
+ rb_ary_new3(2, _sym("gvar"),
587
+ _sym("$."))));
588
+ rb_ary_push(current, result);
589
+ } else {
590
+ add_to_parse_tree(self, current, node->nd_beg, locals);
591
+ }
592
+
593
+
594
+ // add_to_parse_tree(self, current, node->nd_beg, locals);
595
+ add_to_parse_tree(self, current, node->nd_end, locals);
596
+ break;
597
+
598
+ case NODE_DOT2:
599
+ case NODE_DOT3:
600
+ add_to_parse_tree(self, current, node->nd_beg, locals);
601
+ add_to_parse_tree(self, current, node->nd_end, locals);
602
+ break;
603
+
604
+ case NODE_RETURN:
605
+ if (node->nd_stts)
606
+ add_to_parse_tree(self, current, node->nd_stts, locals);
607
+ break;
608
+
609
+ case NODE_ARGSCAT:
610
+ case NODE_ARGSPUSH:
611
+ add_to_parse_tree(self, current, node->nd_head, locals);
612
+ add_to_parse_tree(self, current, node->nd_body, locals);
613
+ break;
614
+
615
+ case NODE_CALL:
616
+ case NODE_FCALL:
617
+ case NODE_VCALL:
618
+ if (nd_type(node) != NODE_FCALL)
619
+ add_to_parse_tree(self, current, node->nd_recv, locals);
620
+ rb_ary_push(current, ID2SYM(node->nd_mid));
621
+ if (node->nd_args || nd_type(node) != NODE_FCALL)
622
+ add_to_parse_tree(self, current, node->nd_args, locals);
623
+ break;
624
+
625
+ case NODE_SUPER:
626
+ add_to_parse_tree(self, current, node->nd_args, locals);
627
+ break;
628
+
629
+ case NODE_BMETHOD:
630
+ {
631
+ struct BLOCK *data;
632
+ Data_Get_Struct(node->nd_cval, struct BLOCK, data);
633
+ if (data->var == 0 || data->var == (NODE *)1 || data->var == (NODE *)2) {
634
+ rb_ary_push(current, Qnil);
635
+ } else {
636
+ masgn_level++;
637
+ add_to_parse_tree(self, current, data->var, locals);
638
+ masgn_level--;
639
+ }
640
+ add_to_parse_tree(self, current, data->body, locals);
641
+ }
642
+ break;
643
+
644
+ #if RUBY_VERSION_CODE < 190
645
+ case NODE_DMETHOD:
646
+ {
647
+ struct METHOD *data;
648
+ Data_Get_Struct(node->nd_cval, struct METHOD, data);
649
+ rb_ary_push(current, ID2SYM(data->id));
650
+ add_to_parse_tree(self, current, data->body, locals);
651
+ break;
652
+ }
653
+ #endif
654
+
655
+ case NODE_METHOD:
656
+ // You should not ever get here. parse_tree_for_meth passes nd_body
657
+ add_to_parse_tree(self, current, node->nd_body, locals);
658
+ break;
659
+
660
+ case NODE_SCOPE:
661
+ add_to_parse_tree(self, current, node->nd_next, node->nd_tbl);
662
+ break;
663
+
664
+ case NODE_OP_ASGN1:
665
+ add_to_parse_tree(self, current, node->nd_recv, locals);
666
+ #if RUBY_VERSION_CODE < 185
667
+ add_to_parse_tree(self, current, node->nd_args->nd_next, locals);
668
+ rb_ary_pop(rb_ary_entry(current, -1)); /* no idea why I need this */
669
+ #else
670
+ add_to_parse_tree(self, current, node->nd_args->nd_2nd, locals);
671
+ #endif
672
+ switch (node->nd_mid) {
673
+ case 0:
674
+ rb_ary_push(current, _sym("||"));
675
+ break;
676
+ case 1:
677
+ rb_ary_push(current, _sym("&&"));
678
+ break;
679
+ default:
680
+ rb_ary_push(current, ID2SYM(node->nd_mid));
681
+ break;
682
+ }
683
+ add_to_parse_tree(self, current, node->nd_args->nd_head, locals);
684
+ break;
685
+
686
+ case NODE_OP_ASGN2:
687
+ add_to_parse_tree(self, current, node->nd_recv, locals);
688
+ rb_ary_push(current, ID2SYM(node->nd_next->nd_aid));
689
+
690
+ switch (node->nd_next->nd_mid) {
691
+ case 0:
692
+ rb_ary_push(current, _sym("||"));
693
+ break;
694
+ case 1:
695
+ rb_ary_push(current, _sym("&&"));
696
+ break;
697
+ default:
698
+ rb_ary_push(current, ID2SYM(node->nd_next->nd_mid));
699
+ break;
700
+ }
701
+
702
+ add_to_parse_tree(self, current, node->nd_value, locals);
703
+ break;
704
+
705
+ case NODE_OP_ASGN_AND:
706
+ case NODE_OP_ASGN_OR:
707
+ add_to_parse_tree(self, current, node->nd_head, locals);
708
+ add_to_parse_tree(self, current, node->nd_value, locals);
709
+ break;
710
+
711
+ case NODE_MASGN:
712
+ masgn_level++;
713
+ if (node->nd_head) {
714
+ add_to_parse_tree(self, current, node->nd_head, locals);
715
+ } else {
716
+ rb_ary_push(current, Qnil);
717
+ }
718
+ if (node->nd_args) {
719
+ if (node->nd_args != (NODE *)-1) {
720
+ add_to_parse_tree(self, current, node->nd_args, locals);
721
+ } else {
722
+ rb_ary_push(current, wrap_into_node("splat", 0));
723
+ }
724
+ } else {
725
+ rb_ary_push(current, Qnil);
726
+ }
727
+ if (node->nd_value) {
728
+ add_to_parse_tree(self, current, node->nd_value, locals);
729
+ } else {
730
+ rb_ary_push(current, Qnil);
731
+ }
732
+ masgn_level--;
733
+ break;
734
+
735
+ case NODE_LASGN:
736
+ case NODE_IASGN:
737
+ case NODE_DASGN:
738
+ case NODE_CVASGN:
739
+ case NODE_CVDECL:
740
+ case NODE_GASGN:
741
+ rb_ary_push(current, ID2SYM(node->nd_vid));
742
+ add_to_parse_tree(self, current, node->nd_value, locals);
743
+ break;
744
+
745
+ case NODE_CDECL:
746
+ if (node->nd_vid) {
747
+ rb_ary_push(current, ID2SYM(node->nd_vid));
748
+ } else {
749
+ add_to_parse_tree(self, current, node->nd_else, locals);
750
+ }
751
+
752
+ add_to_parse_tree(self, current, node->nd_value, locals);
753
+ break;
754
+
755
+ case NODE_DASGN_CURR:
756
+ rb_ary_push(current, ID2SYM(node->nd_vid));
757
+ if (node->nd_value) {
758
+ add_to_parse_tree(self, current, node->nd_value, locals);
759
+ if (!masgn_level && RARRAY_LEN(current) == 2) {
760
+ rb_ary_pop(ary);
761
+ return;
762
+ }
763
+ } else {
764
+ if (!masgn_level) {
765
+ rb_ary_pop(ary);
766
+ return;
767
+ }
768
+ }
769
+ break;
770
+
771
+ case NODE_VALIAS: /* u1 u2 (alias $global $global2) */
772
+ #if RUBY_VERSION_CODE < 185
773
+ rb_ary_push(current, ID2SYM(node->u2.id));
774
+ rb_ary_push(current, ID2SYM(node->u1.id));
775
+ #else
776
+ rb_ary_push(current, ID2SYM(node->u1.id));
777
+ rb_ary_push(current, ID2SYM(node->u2.id));
778
+ #endif
779
+ break;
780
+ case NODE_ALIAS: /* u1 u2 (alias :blah :blah2) */
781
+ #if RUBY_VERSION_CODE < 185
782
+ rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u2.id)));
783
+ rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u1.id)));
784
+ #else
785
+ add_to_parse_tree(self, current, node->nd_1st, locals);
786
+ add_to_parse_tree(self, current, node->nd_2nd, locals);
787
+ #endif
788
+ break;
789
+
790
+ case NODE_UNDEF: /* u2 (undef name, ...) */
791
+ #if RUBY_VERSION_CODE < 185
792
+ rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u2.id)));
793
+ #else
794
+ add_to_parse_tree(self, current, node->nd_value, locals);
795
+ #endif
796
+ break;
797
+
798
+ case NODE_COLON3: /* u2 (::OUTER_CONST) */
799
+ rb_ary_push(current, ID2SYM(node->u2.id));
800
+ break;
801
+
802
+ case NODE_HASH:
803
+ {
804
+ NODE *list;
805
+
806
+ list = node->nd_head;
807
+ while (list) {
808
+ add_to_parse_tree(self, current, list->nd_head, locals);
809
+ list = list->nd_next;
810
+ if (list == 0)
811
+ rb_bug("odd number list for Hash");
812
+ add_to_parse_tree(self, current, list->nd_head, locals);
813
+ list = list->nd_next;
814
+ }
815
+ }
816
+ break;
817
+
818
+ case NODE_ARRAY:
819
+ while (node) {
820
+ add_to_parse_tree(self, current, node->nd_head, locals);
821
+ node = node->nd_next;
822
+ }
823
+ break;
824
+
825
+ case NODE_DSTR:
826
+ case NODE_DSYM:
827
+ case NODE_DXSTR:
828
+ case NODE_DREGX:
829
+ case NODE_DREGX_ONCE:
830
+ {
831
+ NODE *list = node->nd_next;
832
+ rb_ary_push(current, rb_str_new3(node->nd_lit));
833
+ while (list) {
834
+ if (list->nd_head) {
835
+ switch (nd_type(list->nd_head)) {
836
+ case NODE_STR:
837
+ add_to_parse_tree(self, current, list->nd_head, locals);
838
+ break;
839
+ case NODE_EVSTR:
840
+ add_to_parse_tree(self, current, list->nd_head, locals);
841
+ break;
842
+ default:
843
+ add_to_parse_tree(self, current, list->nd_head, locals);
844
+ break;
845
+ }
846
+ }
847
+ list = list->nd_next;
848
+ }
849
+ switch (nd_type(node)) {
850
+ case NODE_DREGX:
851
+ case NODE_DREGX_ONCE:
852
+ if (node->nd_cflag) {
853
+ rb_ary_push(current, INT2FIX(node->nd_cflag));
854
+ }
855
+ }
856
+ }
857
+ break;
858
+
859
+ case NODE_DEFN:
860
+ case NODE_DEFS:
861
+ if (node->nd_defn) {
862
+ if (nd_type(node) == NODE_DEFS)
863
+ add_to_parse_tree(self, current, node->nd_recv, locals);
864
+ rb_ary_push(current, ID2SYM(node->nd_mid));
865
+ add_to_parse_tree(self, current, node->nd_defn, locals);
866
+ }
867
+ break;
868
+
869
+ case NODE_CLASS:
870
+ case NODE_MODULE:
871
+ if (nd_type(node->nd_cpath) == NODE_COLON2 && ! node->nd_cpath->nd_vid) {
872
+ rb_ary_push(current, ID2SYM((ID)node->nd_cpath->nd_mid));
873
+ } else {
874
+ add_to_parse_tree(self, current, node->nd_cpath, locals);
875
+ }
876
+
877
+ if (nd_type(node) == NODE_CLASS) {
878
+ if (node->nd_super) {
879
+ add_to_parse_tree(self, current, node->nd_super, locals);
880
+ } else {
881
+ rb_ary_push(current, Qnil);
882
+ }
883
+ }
884
+ add_to_parse_tree(self, current, node->nd_body, locals);
885
+ break;
886
+
887
+ case NODE_SCLASS:
888
+ add_to_parse_tree(self, current, node->nd_recv, locals);
889
+ add_to_parse_tree(self, current, node->nd_body, locals);
890
+ break;
891
+
892
+ case NODE_ARGS: {
893
+ NODE *optnode;
894
+ int i = 0, max_args = node->nd_cnt;
895
+
896
+ /* push regular argument names */
897
+ for (; i < max_args; i++) {
898
+ rb_ary_push(current, ID2SYM(locals[i + 3]));
899
+ }
900
+
901
+ /* look for optional arguments */
902
+ masgn_level++;
903
+ optnode = node->nd_opt;
904
+ while (optnode) {
905
+ rb_ary_push(current, ID2SYM(locals[i + 3]));
906
+ i++;
907
+ optnode = optnode->nd_next;
908
+ }
909
+
910
+ /* look for vargs */
911
+ #if RUBY_VERSION_CODE > 184
912
+ if (node->nd_rest) {
913
+ VALUE sym = rb_str_new2("*");
914
+ if (locals[i + 3]) {
915
+ rb_str_concat(sym, rb_str_new2(rb_id2name(locals[i + 3])));
916
+ }
917
+ sym = rb_str_intern(sym);
918
+ rb_ary_push(current, sym);
919
+ }
920
+ #else
921
+ {
922
+ long arg_count = (long)node->nd_rest;
923
+ if (arg_count > 0) {
924
+ /* *arg name */
925
+ VALUE sym = rb_str_new2("*");
926
+ if (locals[i + 3]) {
927
+ rb_str_concat(sym, rb_str_new2(rb_id2name(locals[i + 3])));
928
+ }
929
+ sym = rb_str_intern(sym);
930
+ rb_ary_push(current, sym);
931
+ } else if (arg_count == 0) {
932
+ /* nothing to do in this case, empty list */
933
+ } else if (arg_count == -1) {
934
+ /* nothing to do in this case, handled above */
935
+ } else if (arg_count == -2) {
936
+ /* nothing to do in this case, no name == no use */
937
+ rb_ary_push(current, rb_str_intern(rb_str_new2("*")));
938
+ } else {
939
+ rb_raise(rb_eArgError,
940
+ "not a clue what this arg value is: %ld", arg_count);
941
+ }
942
+ }
943
+ #endif
944
+
945
+ optnode = node->nd_opt;
946
+ if (optnode) {
947
+ add_to_parse_tree(self, current, node->nd_opt, locals);
948
+ }
949
+ masgn_level--;
950
+ } break;
951
+
952
+ case NODE_LVAR:
953
+ case NODE_DVAR:
954
+ case NODE_IVAR:
955
+ case NODE_CVAR:
956
+ case NODE_GVAR:
957
+ case NODE_CONST:
958
+ case NODE_ATTRSET:
959
+ rb_ary_push(current, ID2SYM(node->nd_vid));
960
+ break;
961
+
962
+ case NODE_XSTR: /* u1 (%x{ls}) */
963
+ case NODE_STR: /* u1 */
964
+ case NODE_LIT:
965
+ rb_ary_push(current, node->nd_lit);
966
+ break;
967
+
968
+ case NODE_MATCH: /* u1 -> [:lit, u1] */
969
+ rb_ary_push(current, wrap_into_node("lit", node->nd_lit));
970
+ break;
971
+
972
+ case NODE_NEWLINE:
973
+ rb_ary_push(current, INT2FIX(nd_line(node)));
974
+ rb_ary_push(current, rb_str_new2(node->nd_file));
975
+ if (! RTEST(rb_iv_get(self, "\@include_newlines"))) {
976
+ rb_ary_pop(ary); /* nuke it */
977
+ node = node->nd_next;
978
+ goto again;
979
+ } else {
980
+ add_to_parse_tree(self, current, node->nd_next, locals);
981
+ }
982
+ break;
983
+
984
+ case NODE_NTH_REF: /* u2 u3 ($1) - u3 is local_cnt('~') ignorable? */
985
+ rb_ary_push(current, INT2FIX(node->nd_nth));
986
+ break;
987
+
988
+ case NODE_BACK_REF: /* u2 u3 ($& etc) */
989
+ {
990
+ char c = node->nd_nth;
991
+ rb_ary_push(current, rb_str_intern(rb_str_new(&c, 1)));
992
+ }
993
+ break;
994
+
995
+ case NODE_BLOCK_ARG: /* u1 u3 (def x(&b) */
996
+ rb_ary_push(current, ID2SYM(node->u1.id));
997
+ break;
998
+
999
+ /* these nodes are empty and do not require extra work: */
1000
+ case NODE_RETRY:
1001
+ case NODE_FALSE:
1002
+ case NODE_NIL:
1003
+ case NODE_SELF:
1004
+ case NODE_TRUE:
1005
+ case NODE_ZARRAY:
1006
+ case NODE_ZSUPER:
1007
+ case NODE_REDO:
1008
+ break;
1009
+
1010
+ case NODE_SPLAT:
1011
+ case NODE_TO_ARY:
1012
+ case NODE_SVALUE: /* a = b, c */
1013
+ add_to_parse_tree(self, current, node->nd_head, locals);
1014
+ break;
1015
+
1016
+ case NODE_ATTRASGN: /* literal.meth = y u1 u2 u3 */
1017
+ /* node id node */
1018
+ if (node->nd_1st == RNODE(1)) {
1019
+ add_to_parse_tree(self, current, NEW_SELF(), locals);
1020
+ } else {
1021
+ add_to_parse_tree(self, current, node->nd_1st, locals);
1022
+ }
1023
+ rb_ary_push(current, ID2SYM(node->u2.id));
1024
+ add_to_parse_tree(self, current, node->nd_3rd, locals);
1025
+ break;
1026
+
1027
+ case NODE_EVSTR:
1028
+ add_to_parse_tree(self, current, node->nd_2nd, locals);
1029
+ break;
1030
+
1031
+ case NODE_POSTEXE: /* END { ... } */
1032
+ /* Nothing to do here... we are in an iter block */
1033
+ break;
1034
+
1035
+ case NODE_IFUNC:
1036
+ case NODE_CFUNC:
1037
+ rb_ary_push(current, INT2NUM((long)node->nd_cfnc));
1038
+ rb_ary_push(current, INT2NUM(node->nd_argc));
1039
+ break;
1040
+
1041
+ #if RUBY_VERSION_CODE >= 190
1042
+ case NODE_ERRINFO:
1043
+ case NODE_VALUES:
1044
+ case NODE_PRELUDE:
1045
+ case NODE_LAMBDA:
1046
+ puts("no worky in 1.9 yet");
1047
+ break;
1048
+ #endif
1049
+
1050
+ /* Nodes we found but have yet to decypher */
1051
+ /* I think these are all runtime only... not positive but... */
1052
+ case NODE_MEMO: /* enum.c zip */
1053
+ case NODE_CREF:
1054
+ /* #defines: */
1055
+ /* case NODE_LMASK: */
1056
+ /* case NODE_LSHIFT: */
1057
+ default:
1058
+ rb_warn("Unhandled node #%d type '%s'", nd_type(node), rb_id2name(SYM2ID(rb_ary_entry(node_names, nd_type(node)))));
1059
+ if (RNODE(node)->u1.node != NULL) rb_warning("unhandled u1 value");
1060
+ if (RNODE(node)->u2.node != NULL) rb_warning("unhandled u2 value");
1061
+ if (RNODE(node)->u3.node != NULL) rb_warning("unhandled u3 value");
1062
+ if (RTEST(ruby_debug)) fprintf(stderr, "u1 = %p u2 = %p u3 = %p\\n", (void*)node->nd_1st, (void*)node->nd_2nd, (void*)node->nd_3rd);
1063
+ rb_ary_push(current, INT2FIX(-99));
1064
+ rb_ary_push(current, INT2FIX(nd_type(node)));
1065
+ break;
1066
+ }
1067
+ }
1068
+ @ # end of add_to_parse_tree block
1069
+
1070
+ builder.c %Q{
1071
+ static VALUE parse_tree_for_proc(VALUE proc) {
1072
+ VALUE result = rb_ary_new();
1073
+ struct BLOCK *data;
1074
+ Data_Get_Struct(proc, struct BLOCK, data);
1075
+
1076
+ rb_ary_push(result, _sym("iter"));
1077
+ rb_ary_push(result, rb_ary_new3(4, _sym("call"), Qnil, _sym("proc"),
1078
+ rb_ary_new3(1, _sym("arglist"))));
1079
+ masgn_level++;
1080
+ if (data->var) {
1081
+ add_to_parse_tree(self, result, data->var, NULL);
1082
+ } else {
1083
+ rb_ary_push(result, Qnil);
1084
+ }
1085
+ add_to_parse_tree(self, result, data->body, NULL);
1086
+ masgn_level--;
1087
+
1088
+ return result;
1089
+ }
1090
+ }
1091
+
1092
+ builder.c %Q{
1093
+ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE is_cls_meth) {
1094
+ VALUE n;
1095
+ NODE *node = NULL;
1096
+ ID id;
1097
+ VALUE result = rb_ary_new();
1098
+ VALUE version = rb_const_get_at(rb_cObject,rb_intern("RUBY_VERSION"));
1099
+
1100
+ (void) self; /* quell warnings */
1101
+
1102
+ if (strcmp(StringValuePtr(version), #{RUBY_VERSION.inspect})) {
1103
+ rb_fatal("bad version, %s != #{RUBY_VERSION}\\n", StringValuePtr(version));
1104
+ }
1105
+
1106
+ id = rb_to_id(method);
1107
+ if (RTEST(is_cls_meth)) { /* singleton method */
1108
+ klass = CLASS_OF(klass);
1109
+ }
1110
+ if (st_lookup(RCLASS(klass)->m_tbl, id, &n)) {
1111
+ node = (NODE*)n;
1112
+ rb_ary_push(result, _sym(is_cls_meth ? "defs": "defn"));
1113
+ if (is_cls_meth) {
1114
+ rb_ary_push(result, rb_ary_new3(1, _sym("self")));
1115
+ }
1116
+ rb_ary_push(result, ID2SYM(id));
1117
+ add_to_parse_tree(self, result, node->nd_body, NULL);
1118
+ } else {
1119
+ rb_ary_push(result, Qnil);
1120
+ }
1121
+
1122
+ return result;
1123
+ }
1124
+ }
1125
+
1126
+ extern_mode = RUBY_PLATFORM =~ /mswin/ ? 'RUBY_EXTERN' : 'extern'
1127
+ builder.prefix " #{extern_mode} NODE *ruby_eval_tree_begin; " \
1128
+ if RUBY_VERSION < '1.9.0'
1129
+
1130
+ # FIXME: ruby_in_eval is not properly exported across platforms
1131
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/13558
1132
+ builder.c %Q{
1133
+ static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line) {
1134
+ VALUE tmp;
1135
+ VALUE result = rb_ary_new();
1136
+ NODE *node = NULL;
1137
+ int critical;
1138
+
1139
+ tmp = rb_check_string_type(filename);
1140
+ if (NIL_P(tmp)) {
1141
+ filename = rb_str_new2("(string)");
1142
+ }
1143
+
1144
+ if (NIL_P(line)) {
1145
+ line = LONG2FIX(1);
1146
+ }
1147
+
1148
+ ruby_nerrs = 0;
1149
+ StringValue(source);
1150
+ critical = rb_thread_critical;
1151
+ rb_thread_critical = Qtrue;
1152
+ ruby_in_eval++;
1153
+ node = rb_compile_string(StringValuePtr(filename), source, NUM2INT(line));
1154
+ ruby_in_eval--;
1155
+ rb_thread_critical = critical;
1156
+
1157
+ if (ruby_nerrs > 0) {
1158
+ ruby_nerrs = 0;
1159
+ #if RUBY_VERSION_CODE < 190
1160
+ ruby_eval_tree_begin = 0;
1161
+ #endif
1162
+ rb_exc_raise(ruby_errinfo);
1163
+ }
1164
+
1165
+ add_to_parse_tree(self, result, node, NULL);
1166
+
1167
+ return result;
1168
+ }
1169
+ }
1170
+
1171
+ end # inline call
1172
+ end # RawParseTree class
1173
+
1174
+ class ParseTree < RawParseTree
1175
+ ##
1176
+ # Initializes a ParseTree instance. Includes newline nodes if
1177
+ # +include_newlines+ which defaults to +$DEBUG+.
1178
+
1179
+ def initialize(include_newlines=$DEBUG)
1180
+ super
1181
+ @unifier = Unifier.new
1182
+ end
1183
+
1184
+ ##
1185
+ # Main driver for ParseTree. Returns a Sexp instance containing the
1186
+ # AST representing the input given. This is a UnifiedRuby sexp, not
1187
+ # a raw sexp from ruby. If you want raw, use the old
1188
+ # parse_tree_for_xxx methods... Please tell me if/why you want raw,
1189
+ # I'd like to know so I can justify keeping the code around.
1190
+
1191
+ def process(input, verbose = nil, file = "(string)", line = -1)
1192
+ case input
1193
+ when Array then
1194
+ @unifier.process(input)
1195
+ when String then
1196
+ pt = self.parse_tree_for_string(input, file, line, verbose).first
1197
+ @unifier.process(pt)
1198
+ else
1199
+ raise ArgumentError, "Unknown input type #{input.inspect}"
1200
+ end
1201
+ end
1202
+ end