virtual_keywords 0.1.0 → 0.3.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.
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