rubyjs 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README +128 -0
  2. data/Rakefile +9 -0
  3. data/bin/rubyjs +140 -0
  4. data/examples/ex1/Rakefile +7 -0
  5. data/examples/ex1/ex1.js +771 -0
  6. data/examples/ex1/ex1.rb +42 -0
  7. data/examples/ex1/index.html +7 -0
  8. data/examples/hw/Rakefile +9 -0
  9. data/examples/hw/hw.js +635 -0
  10. data/examples/hw/hw.rb +7 -0
  11. data/examples/hw/index.html +7 -0
  12. data/patches/parse_tree.rb.diff +34 -0
  13. data/rubyjs.gemspec +24 -0
  14. data/src/rubyjs.rb +4 -0
  15. data/src/rubyjs/code_generator.rb +474 -0
  16. data/src/rubyjs/compiler.rb +2007 -0
  17. data/src/rubyjs/debug_name_generator.rb +75 -0
  18. data/src/rubyjs/encoder.rb +171 -0
  19. data/src/rubyjs/eval_into.rb +59 -0
  20. data/src/rubyjs/lib/core.rb +1008 -0
  21. data/src/rubyjs/lib/json.rb +101 -0
  22. data/src/rubyjs/model.rb +287 -0
  23. data/src/rubyjs/name_generator.rb +71 -0
  24. data/src/rwt/AbsolutePanel.rb +161 -0
  25. data/src/rwt/DOM.Konqueror.rb +89 -0
  26. data/src/rwt/DOM.Opera.rb +65 -0
  27. data/src/rwt/DOM.rb +1044 -0
  28. data/src/rwt/Event.Opera.rb +35 -0
  29. data/src/rwt/Event.rb +429 -0
  30. data/src/rwt/HTTPRequest.IE6.rb +5 -0
  31. data/src/rwt/HTTPRequest.rb +74 -0
  32. data/src/rwt/Label.rb +164 -0
  33. data/src/rwt/Panel.rb +90 -0
  34. data/src/rwt/RootPanel.rb +16 -0
  35. data/src/rwt/UIObject.rb +495 -0
  36. data/src/rwt/Widget.rb +193 -0
  37. data/src/rwt/ported-from/AbsolutePanel.java +158 -0
  38. data/src/rwt/ported-from/DOM.java +571 -0
  39. data/src/rwt/ported-from/DOMImpl.java +426 -0
  40. data/src/rwt/ported-from/DOMImplOpera.java +82 -0
  41. data/src/rwt/ported-from/DOMImplStandard.java +234 -0
  42. data/src/rwt/ported-from/HTTPRequest.java +81 -0
  43. data/src/rwt/ported-from/HTTPRequestImpl.java +103 -0
  44. data/src/rwt/ported-from/Label.java +163 -0
  45. data/src/rwt/ported-from/Panel.java +99 -0
  46. data/src/rwt/ported-from/UIObject.java +614 -0
  47. data/src/rwt/ported-from/Widget.java +221 -0
  48. data/test/benchmark/bm_call_conv1.js +16 -0
  49. data/test/benchmark/bm_call_conv2.js +14 -0
  50. data/test/benchmark/bm_var_acc1.js +13 -0
  51. data/test/benchmark/bm_var_acc2.js +11 -0
  52. data/test/benchmark/bm_vm1_block.js +15 -0
  53. data/test/benchmark/bm_vm1_block.rb +15 -0
  54. data/test/benchmark/bm_vm1_const.js +13 -0
  55. data/test/benchmark/bm_vm1_const.rb +13 -0
  56. data/test/benchmark/bm_vm1_ensure.js +17 -0
  57. data/test/benchmark/bm_vm1_ensure.rb +15 -0
  58. data/test/benchmark/common.js +4 -0
  59. data/test/benchmark/common.rb +5 -0
  60. data/test/benchmark/params.yaml +7 -0
  61. data/test/browser.test.html +4059 -0
  62. data/test/browser.test.js +3225 -0
  63. data/test/common.Browser.rb +13 -0
  64. data/test/common.rb +8 -0
  65. data/test/gen_browser_test_suite.rb +129 -0
  66. data/test/gen_test_suite.rb +41 -0
  67. data/test/run_benchs.rb +58 -0
  68. data/test/run_tests.rb +22 -0
  69. data/test/test_args.rb +24 -0
  70. data/test/test_array.rb +26 -0
  71. data/test/test_case.rb +35 -0
  72. data/test/test_class.rb +55 -0
  73. data/test/test_eql.rb +9 -0
  74. data/test/test_exception.rb +61 -0
  75. data/test/test_expr.rb +12 -0
  76. data/test/test_hash.rb +29 -0
  77. data/test/test_if.rb +28 -0
  78. data/test/test_inspect.rb +10 -0
  79. data/test/test_lebewesen.rb +39 -0
  80. data/test/test_massign.rb +66 -0
  81. data/test/test_new.rb +12 -0
  82. data/test/test_range.rb +53 -0
  83. data/test/test_regexp.rb +22 -0
  84. data/test/test_send.rb +65 -0
  85. data/test/test_simple_output.rb +5 -0
  86. data/test/test_splat.rb +21 -0
  87. data/test/test_string.rb +51 -0
  88. data/test/test_yield.rb +152 -0
  89. data/utils/js/Makefile +9 -0
  90. data/utils/js/RunScript.class +0 -0
  91. data/utils/js/RunScript.java +73 -0
  92. data/utils/js/js.jar +0 -0
  93. data/utils/js/run.sh +3 -0
  94. data/utils/jsc/Makefile +7 -0
  95. data/utils/jsc/README +3 -0
  96. data/utils/jsc/RunScript.c +93 -0
  97. data/utils/jsc/run.sh +15 -0
  98. data/utils/yuicompressor/README +1 -0
  99. data/utils/yuicompressor/yuicompressor-2.2.5.jar +0 -0
  100. data/vendor/ParseTree-1.7.1-patched/History.txt +217 -0
  101. data/vendor/ParseTree-1.7.1-patched/Manifest.txt +22 -0
  102. data/vendor/ParseTree-1.7.1-patched/README.txt +110 -0
  103. data/vendor/ParseTree-1.7.1-patched/Rakefile +41 -0
  104. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_abc +89 -0
  105. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_audit +28 -0
  106. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_deps +62 -0
  107. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_show +49 -0
  108. data/vendor/ParseTree-1.7.1-patched/demo/printer.rb +20 -0
  109. data/vendor/ParseTree-1.7.1-patched/lib/composite_sexp_processor.rb +49 -0
  110. data/vendor/ParseTree-1.7.1-patched/lib/parse_tree.rb +1013 -0
  111. data/vendor/ParseTree-1.7.1-patched/lib/sexp.rb +235 -0
  112. data/vendor/ParseTree-1.7.1-patched/lib/sexp_processor.rb +330 -0
  113. data/vendor/ParseTree-1.7.1-patched/lib/unique.rb +15 -0
  114. data/vendor/ParseTree-1.7.1-patched/test/pt_testcase.rb +1221 -0
  115. data/vendor/ParseTree-1.7.1-patched/test/something.rb +53 -0
  116. data/vendor/ParseTree-1.7.1-patched/test/test_all.rb +13 -0
  117. data/vendor/ParseTree-1.7.1-patched/test/test_composite_sexp_processor.rb +69 -0
  118. data/vendor/ParseTree-1.7.1-patched/test/test_parse_tree.rb +216 -0
  119. data/vendor/ParseTree-1.7.1-patched/test/test_sexp.rb +291 -0
  120. data/vendor/ParseTree-1.7.1-patched/test/test_sexp_processor.rb +244 -0
  121. data/vendor/ParseTree-1.7.1-patched/validate.sh +31 -0
  122. data/vendor/ParseTree-1.7.1/History.txt +217 -0
  123. data/vendor/ParseTree-1.7.1/Manifest.txt +22 -0
  124. data/vendor/ParseTree-1.7.1/README.txt +110 -0
  125. data/vendor/ParseTree-1.7.1/Rakefile +41 -0
  126. data/vendor/ParseTree-1.7.1/bin/parse_tree_abc +89 -0
  127. data/vendor/ParseTree-1.7.1/bin/parse_tree_audit +28 -0
  128. data/vendor/ParseTree-1.7.1/bin/parse_tree_deps +62 -0
  129. data/vendor/ParseTree-1.7.1/bin/parse_tree_show +49 -0
  130. data/vendor/ParseTree-1.7.1/demo/printer.rb +20 -0
  131. data/vendor/ParseTree-1.7.1/lib/composite_sexp_processor.rb +49 -0
  132. data/vendor/ParseTree-1.7.1/lib/parse_tree.rb +1004 -0
  133. data/vendor/ParseTree-1.7.1/lib/sexp.rb +235 -0
  134. data/vendor/ParseTree-1.7.1/lib/sexp_processor.rb +330 -0
  135. data/vendor/ParseTree-1.7.1/lib/unique.rb +15 -0
  136. data/vendor/ParseTree-1.7.1/test/pt_testcase.rb +1221 -0
  137. data/vendor/ParseTree-1.7.1/test/something.rb +53 -0
  138. data/vendor/ParseTree-1.7.1/test/test_all.rb +13 -0
  139. data/vendor/ParseTree-1.7.1/test/test_composite_sexp_processor.rb +69 -0
  140. data/vendor/ParseTree-1.7.1/test/test_parse_tree.rb +216 -0
  141. data/vendor/ParseTree-1.7.1/test/test_sexp.rb +291 -0
  142. data/vendor/ParseTree-1.7.1/test/test_sexp_processor.rb +244 -0
  143. data/vendor/ParseTree-1.7.1/validate.sh +31 -0
  144. metadata +230 -0
@@ -0,0 +1,1004 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ abort "*** Sorry, ParseTree doesn't work with ruby #{RUBY_VERSION}" if
4
+ RUBY_VERSION >= "1.9"
5
+
6
+ begin require 'rubygems'; rescue LoadError; end
7
+
8
+ require 'inline'
9
+
10
+ ##
11
+ # ParseTree is a RubyInline-style extension that accesses and
12
+ # traverses the internal parse tree created by ruby.
13
+ #
14
+ # class Example
15
+ # def blah
16
+ # return 1 + 1
17
+ # end
18
+ # end
19
+ #
20
+ # ParseTree.new.parse_tree(Example)
21
+ # => [[:class, :Example, :Object,
22
+ # [:defn,
23
+ # "blah",
24
+ # [:scope,
25
+ # [:block,
26
+ # [:args],
27
+ # [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]
28
+
29
+ class ParseTree
30
+
31
+ VERSION = '1.7.1'
32
+
33
+ ##
34
+ # Front end translation method.
35
+
36
+ def self.translate(klass_or_str, method=nil)
37
+ pt = self.new(false)
38
+ case klass_or_str
39
+ when String then
40
+ sexp = pt.parse_tree_for_string(klass_or_str).first
41
+ if method then
42
+ # class, scope, block, *methods
43
+ sexp.last.last[1..-1].find do |defn|
44
+ defn[1] == method
45
+ end
46
+ else
47
+ sexp
48
+ end
49
+ else
50
+ unless method.nil? then
51
+ if method.to_s =~ /^self\./ then
52
+ method = method.to_s[5..-1].intern
53
+ pt.parse_tree_for_method(klass_or_str, method, true)
54
+ else
55
+ pt.parse_tree_for_method(klass_or_str, method)
56
+ end
57
+ else
58
+ pt.parse_tree(klass_or_str).first
59
+ end
60
+ end
61
+ end
62
+
63
+ ##
64
+ # Initializes a ParseTree instance. Includes newline nodes if
65
+ # +include_newlines+ which defaults to +$DEBUG+.
66
+
67
+ def initialize(include_newlines=$DEBUG)
68
+ if include_newlines then
69
+ warn "WARNING: include_newlines=true from #{caller[0..9].join(', ')}"
70
+ end
71
+ @include_newlines = include_newlines
72
+ end
73
+
74
+ ##
75
+ # Main driver for ParseTree. Returns an array of arrays containing
76
+ # the parse tree for +klasses+.
77
+ #
78
+ # Structure:
79
+ #
80
+ # [[:class, classname, superclassname, [:defn :method1, ...], ...], ...]
81
+ #
82
+ # NOTE: v1.0 - v1.1 had the signature (klass, meth=nil). This wasn't
83
+ # used much at all and since parse_tree_for_method already existed,
84
+ # it was deemed more useful to expand this method to do multiple
85
+ # classes.
86
+
87
+ def parse_tree(*klasses)
88
+ result = []
89
+ klasses.each do |klass|
90
+ # TODO: remove this on v 1.1
91
+ raise "You should call parse_tree_for_method(#{klasses.first}, #{klass}) instead of parse_tree" if Symbol === klass or String === klass
92
+ klassname = klass.name rescue '' # HACK klass.name should never be nil
93
+ # Tempfile's DelegateClass(File) seems to
94
+ # cause this
95
+ klassname = "UnnamedClass_#{klass.object_id}" if klassname.empty?
96
+ klassname = klassname.to_sym
97
+
98
+ code = if Class === klass then
99
+ sc = klass.superclass
100
+ sc_name = ((sc.nil? or sc.name.empty?) ? "nil" : sc.name).intern
101
+ [:class, klassname, [:const, sc_name]]
102
+ else
103
+ [:module, klassname]
104
+ end
105
+
106
+ method_names = []
107
+ method_names += klass.instance_methods false
108
+ method_names += klass.private_instance_methods false
109
+ # protected methods are included in instance_methods, go figure!
110
+
111
+ method_names.sort.each do |m|
112
+ code << parse_tree_for_method(klass, m.to_sym)
113
+ end
114
+
115
+ klass.singleton_methods(false).sort.each do |m|
116
+ code << parse_tree_for_method(klass, m.to_sym, true)
117
+ end
118
+
119
+ result << code
120
+ end
121
+ return result
122
+ end
123
+
124
+ ##
125
+ # Returns the parse tree for just one +method+ of a class +klass+.
126
+ #
127
+ # Format:
128
+ #
129
+ # [:defn, :name, :body]
130
+
131
+ def parse_tree_for_method(klass, method, is_cls_meth=false)
132
+ $stderr.puts "** parse_tree_for_method(#{klass}, #{method}):" if $DEBUG
133
+ r = parse_tree_for_meth(klass, method.to_sym, @include_newlines, is_cls_meth)
134
+ r[1] = :"self.#{r[1]}" if is_cls_meth
135
+ r
136
+ end
137
+
138
+ ##
139
+ # Returns the parse tree for a string +source+.
140
+ #
141
+ # Format:
142
+ #
143
+ # [[sexps] ... ]
144
+
145
+ def parse_tree_for_string(source, filename = nil, line = nil,
146
+ newlines = false)
147
+ filename ||= '(string)'
148
+ line ||= 1
149
+ return parse_tree_for_str(source, filename, line, newlines)
150
+ end
151
+
152
+ if RUBY_VERSION < "1.8.4" then
153
+ inline do |builder|
154
+ builder.add_type_converter("bool", '', '')
155
+ builder.c_singleton "
156
+ bool has_alloca() {
157
+ (void)self;
158
+ #ifdef C_ALLOCA
159
+ return Qtrue;
160
+ #else
161
+ return Qfalse;
162
+ #endif
163
+ }"
164
+ end
165
+ else
166
+ def self.has_alloca
167
+ true
168
+ end
169
+ end
170
+
171
+
172
+ NODE_NAMES = [
173
+ # 00
174
+ :method, :fbody, :cfunc, :scope, :block,
175
+ :if, :case, :when, :opt_n, :while,
176
+ # 10
177
+ :until, :iter, :for, :break, :next,
178
+ :redo, :retry, :begin, :rescue, :resbody,
179
+ # 20
180
+ :ensure, :and, :or, :not, :masgn,
181
+ :lasgn, :dasgn, :dasgn_curr, :gasgn, :iasgn,
182
+ # 30
183
+ :cdecl, :cvasgn, :cvdecl, :op_asgn1, :op_asgn2,
184
+ :op_asgn_and, :op_asgn_or, :call, :fcall, :vcall,
185
+ # 40
186
+ :super, :zsuper, :array, :zarray, :hash,
187
+ :return, :yield, :lvar, :dvar, :gvar,
188
+ # 50
189
+ :ivar, :const, :cvar, :nth_ref, :back_ref,
190
+ :match, :match2, :match3, :lit, :str,
191
+ # 60
192
+ :dstr, :xstr, :dxstr, :evstr, :dregx,
193
+ :dregx_once, :args, :argscat, :argspush, :splat,
194
+ # 70
195
+ :to_ary, :svalue, :block_arg, :block_pass, :defn,
196
+ :defs, :alias, :valias, :undef, :class,
197
+ # 80
198
+ :module, :sclass, :colon2, :colon3, :cref,
199
+ :dot2, :dot3, :flip2, :flip3, :attrset,
200
+ # 90
201
+ :self, :nil, :true, :false, :defined,
202
+ # 95
203
+ :newline, :postexe, :alloca, :dmethod, :bmethod,
204
+ # 100
205
+ :memo, :ifunc, :dsym, :attrasgn,
206
+ :last
207
+ ]
208
+
209
+ if RUBY_VERSION < "1.8.4" then
210
+ NODE_NAMES.delete :alloca unless has_alloca
211
+ end
212
+
213
+ if RUBY_VERSION > "1.9" then
214
+ NODE_NAMES.insert NODE_NAMES.index(:hash), :values
215
+ NODE_NAMES.insert NODE_NAMES.index(:defined), :errinfo
216
+ NODE_NAMES.insert NODE_NAMES.index(:last), :prelude, :lambda
217
+ NODE_NAMES.delete :dmethod
218
+ NODE_NAMES[128] = NODE_NAMES.delete :newline
219
+ end
220
+
221
+ ############################################################
222
+ # END of rdoc methods
223
+ ############################################################
224
+
225
+ inline do |builder|
226
+ builder.add_type_converter("bool", '', '')
227
+ builder.add_type_converter("ID *", '', '')
228
+ builder.add_type_converter("NODE *", '(NODE *)', '(VALUE)')
229
+ builder.include '"intern.h"'
230
+ builder.include '"version.h"'
231
+ builder.include '"rubysig.h"'
232
+ builder.include '"node.h"'
233
+ builder.include '"st.h"'
234
+ builder.include '"env.h"'
235
+ builder.add_compile_flags "-Wall"
236
+ builder.add_compile_flags "-W"
237
+ builder.add_compile_flags "-Wpointer-arith"
238
+ builder.add_compile_flags "-Wcast-qual"
239
+ builder.add_compile_flags "-Wcast-align"
240
+ builder.add_compile_flags "-Wwrite-strings"
241
+ builder.add_compile_flags "-Wmissing-noreturn"
242
+ # NOTE: If you get weird compiler errors like:
243
+ # dereferencing type-punned pointer will break strict-aliasing rules
244
+ # PLEASE do one of the following:
245
+ # 1) Get me a login on your box so I can repro this and get it fixed.
246
+ # 2) Fix it and send me the patch
247
+ # 3) (quick, but dirty and bad), comment out the following line:
248
+ builder.add_compile_flags "-Werror"
249
+ # NOTE: this flag doesn't work w/ gcc 2.95.x - the FreeBSD default
250
+ # builder.add_compile_flags "-Wno-strict-aliasing"
251
+ # ruby.h screws these up hardcore:
252
+ # builder.add_compile_flags "-Wundef"
253
+ # builder.add_compile_flags "-Wconversion"
254
+ # builder.add_compile_flags "-Wstrict-prototypes"
255
+ # builder.add_compile_flags "-Wmissing-prototypes"
256
+ # builder.add_compile_flags "-Wsign-compare"
257
+
258
+ def self.if_version(test, version, str)
259
+ RUBY_VERSION.send(test, version) ? str : ""
260
+ end
261
+
262
+ builder.prefix %{
263
+ #define nd_3rd u3.node
264
+ static unsigned case_level = 0;
265
+ }
266
+
267
+ builder.prefix %{
268
+ static VALUE wrap_into_node(const char * name, VALUE val) {
269
+ VALUE n = rb_ary_new();
270
+ rb_ary_push(n, ID2SYM(rb_intern(name)));
271
+ rb_ary_push(n, val);
272
+ return n;
273
+ }
274
+ }
275
+
276
+ builder.prefix %{
277
+ struct METHOD {
278
+ VALUE klass, rklass;
279
+ VALUE recv;
280
+ ID id, oid;
281
+ #{if_version :>, "1.8.2", "int safe_level;"}
282
+ NODE *body;
283
+ };
284
+
285
+ struct BLOCK {
286
+ NODE *var;
287
+ NODE *body;
288
+ VALUE self;
289
+ struct FRAME frame;
290
+ struct SCOPE *scope;
291
+ VALUE klass;
292
+ NODE *cref;
293
+ int iter;
294
+ int vmode;
295
+ int flags;
296
+ int uniq;
297
+ struct RVarmap *dyna_vars;
298
+ VALUE orig_thread;
299
+ VALUE wrapper;
300
+ VALUE block_obj;
301
+ struct BLOCK *outer;
302
+ struct BLOCK *prev;
303
+ };
304
+ } unless RUBY_VERSION >= "1.9" # we got matz to add this to env.h
305
+
306
+ ##
307
+ # add_to_parse_tree(ary, node, include_newlines, local_variables)
308
+
309
+ builder.c_raw %Q@
310
+ static void add_to_parse_tree(VALUE ary,
311
+ NODE * n,
312
+ VALUE newlines,
313
+ ID * locals) {
314
+ NODE * volatile node = n;
315
+ NODE * volatile contnode = NULL;
316
+ VALUE old_ary = Qnil;
317
+ VALUE current;
318
+ VALUE node_name;
319
+ static VALUE node_names = Qnil;
320
+
321
+ if (NIL_P(node_names)) {
322
+ node_names = rb_const_get_at(rb_path2class("ParseTree"),rb_intern("NODE_NAMES"));
323
+ }
324
+
325
+ if (!node) return;
326
+
327
+ again:
328
+
329
+ if (node) {
330
+ node_name = rb_ary_entry(node_names, nd_type(node));
331
+ if (RTEST(ruby_debug)) {
332
+ fprintf(stderr, "%15s: %s%s%s\\n",
333
+ rb_id2name(SYM2ID(node_name)),
334
+ (RNODE(node)->u1.node != NULL ? "u1 " : " "),
335
+ (RNODE(node)->u2.node != NULL ? "u2 " : " "),
336
+ (RNODE(node)->u3.node != NULL ? "u3 " : " "));
337
+ }
338
+ } else {
339
+ node_name = ID2SYM(rb_intern("ICKY"));
340
+ }
341
+
342
+ current = rb_ary_new();
343
+ rb_ary_push(ary, current);
344
+ rb_ary_push(current, node_name);
345
+
346
+ again_no_block:
347
+
348
+ switch (nd_type(node)) {
349
+
350
+ case NODE_BLOCK:
351
+ if (contnode) {
352
+ add_to_parse_tree(current, node, newlines, locals);
353
+ break;
354
+ }
355
+ contnode = node->nd_next;
356
+
357
+ // FIX: this will break the moment there is a block w/in a block
358
+ old_ary = ary;
359
+ ary = current;
360
+ node = node->nd_head;
361
+ if (nd_type(node) == NODE_DASGN_CURR
362
+ && (!node->nd_value || nd_type(node->nd_value) == NODE_DASGN_CURR)) {
363
+ goto finish;
364
+ }
365
+ goto again;
366
+ break;
367
+
368
+ case NODE_FBODY:
369
+ case NODE_DEFINED:
370
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
371
+ break;
372
+
373
+ case NODE_COLON2:
374
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
375
+ rb_ary_push(current, ID2SYM(node->nd_mid));
376
+ break;
377
+
378
+ case NODE_MATCH2:
379
+ case NODE_MATCH3:
380
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
381
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
382
+ break;
383
+
384
+ case NODE_BEGIN:
385
+ case NODE_OPT_N:
386
+ case NODE_NOT:
387
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
388
+ break;
389
+
390
+ case NODE_IF:
391
+ add_to_parse_tree(current, node->nd_cond, newlines, locals);
392
+ if (node->nd_body) {
393
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
394
+ } else {
395
+ rb_ary_push(current, Qnil);
396
+ }
397
+ if (node->nd_else) {
398
+ add_to_parse_tree(current, node->nd_else, newlines, locals);
399
+ } else {
400
+ rb_ary_push(current, Qnil);
401
+ }
402
+ break;
403
+
404
+ case NODE_CASE:
405
+ case_level++;
406
+ if (node->nd_head != NULL) {
407
+ add_to_parse_tree(current, node->nd_head, newlines, locals); /* expr */
408
+ } else {
409
+ rb_ary_push(current, Qnil);
410
+ }
411
+ node = node->nd_body;
412
+ while (node) {
413
+ add_to_parse_tree(current, node, newlines, locals);
414
+ if (nd_type(node) == NODE_WHEN) { /* when */
415
+ node = node->nd_next;
416
+ } else {
417
+ break; /* else */
418
+ }
419
+ if (! node) {
420
+ rb_ary_push(current, Qnil); /* no else */
421
+ }
422
+ }
423
+ case_level--;
424
+ break;
425
+
426
+ case NODE_WHEN:
427
+ if (!case_level) { /* when without case, ie, no expr in case */
428
+ rb_ary_pop(ary); /* reset what current is pointing at */
429
+ node = NEW_CASE(0, node);
430
+ goto again;
431
+ }
432
+ add_to_parse_tree(current, node->nd_head, newlines, locals); /* args */
433
+ if (node->nd_body) {
434
+ add_to_parse_tree(current, node->nd_body, newlines, locals); /* body */
435
+ } else {
436
+ rb_ary_push(current, Qnil);
437
+ }
438
+ break;
439
+
440
+ case NODE_WHILE:
441
+ case NODE_UNTIL:
442
+ add_to_parse_tree(current, node->nd_cond, newlines, locals);
443
+ if (node->nd_body) {
444
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
445
+ } else {
446
+ rb_ary_push(current, Qnil);
447
+ }
448
+ rb_ary_push(current, node->nd_3rd == 0 ? Qfalse : Qtrue);
449
+ break;
450
+
451
+ case NODE_BLOCK_PASS:
452
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
453
+ add_to_parse_tree(current, node->nd_iter, newlines, locals);
454
+ break;
455
+
456
+ case NODE_ITER:
457
+ case NODE_FOR:
458
+ add_to_parse_tree(current, node->nd_iter, newlines, locals);
459
+ if (node->nd_var != (NODE *)1
460
+ && node->nd_var != (NODE *)2
461
+ && node->nd_var != NULL) {
462
+ add_to_parse_tree(current, node->nd_var, newlines, locals);
463
+ } else {
464
+ rb_ary_push(current, Qnil);
465
+ }
466
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
467
+ break;
468
+
469
+ case NODE_BREAK:
470
+ case NODE_NEXT:
471
+ case NODE_YIELD:
472
+ if (node->nd_stts)
473
+ add_to_parse_tree(current, node->nd_stts, newlines, locals);
474
+ break;
475
+
476
+ case NODE_RESCUE:
477
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
478
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
479
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
480
+ break;
481
+
482
+ // rescue body:
483
+ // begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
484
+ // stmt rescue stmt
485
+ // a = b rescue c
486
+
487
+ case NODE_RESBODY:
488
+ if (node->nd_3rd) {
489
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
490
+ } else {
491
+ rb_ary_push(current, Qnil);
492
+ }
493
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
494
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
495
+ break;
496
+
497
+ case NODE_ENSURE:
498
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
499
+ if (node->nd_ensr) {
500
+ add_to_parse_tree(current, node->nd_ensr, newlines, locals);
501
+ }
502
+ break;
503
+
504
+ case NODE_AND:
505
+ case NODE_OR:
506
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
507
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
508
+ break;
509
+
510
+ case NODE_DOT2:
511
+ case NODE_DOT3:
512
+ case NODE_FLIP2:
513
+ case NODE_FLIP3:
514
+ add_to_parse_tree(current, node->nd_beg, newlines, locals);
515
+ add_to_parse_tree(current, node->nd_end, newlines, locals);
516
+ break;
517
+
518
+ case NODE_RETURN:
519
+ if (node->nd_stts)
520
+ add_to_parse_tree(current, node->nd_stts, newlines, locals);
521
+ break;
522
+
523
+ case NODE_ARGSCAT:
524
+ case NODE_ARGSPUSH:
525
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
526
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
527
+ break;
528
+
529
+ case NODE_CALL:
530
+ case NODE_FCALL:
531
+ case NODE_VCALL:
532
+ if (nd_type(node) != NODE_FCALL)
533
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
534
+ rb_ary_push(current, ID2SYM(node->nd_mid));
535
+ if (node->nd_args || nd_type(node) != NODE_FCALL)
536
+ add_to_parse_tree(current, node->nd_args, newlines, locals);
537
+ break;
538
+
539
+ case NODE_SUPER:
540
+ add_to_parse_tree(current, node->nd_args, newlines, locals);
541
+ break;
542
+
543
+ case NODE_BMETHOD:
544
+ {
545
+ struct BLOCK *data;
546
+ Data_Get_Struct(node->nd_cval, struct BLOCK, data);
547
+ add_to_parse_tree(current, data->var, newlines, locals);
548
+ add_to_parse_tree(current, data->body, newlines, locals);
549
+ break;
550
+ }
551
+ break;
552
+
553
+ #{if_version :>, "1.9", '#if 0'}
554
+ case NODE_DMETHOD:
555
+ {
556
+ struct METHOD *data;
557
+ Data_Get_Struct(node->nd_cval, struct METHOD, data);
558
+ rb_ary_push(current, ID2SYM(data->id));
559
+ add_to_parse_tree(current, data->body, newlines, locals);
560
+ break;
561
+ }
562
+ #{if_version :>, "1.9", '#endif'}
563
+
564
+ case NODE_METHOD:
565
+ fprintf(stderr, "u1 = %p u2 = %p u3 = %p\\n", node->nd_1st, node->nd_2nd, node->nd_3rd);
566
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
567
+ break;
568
+
569
+ case NODE_SCOPE:
570
+ add_to_parse_tree(current, node->nd_next, newlines, node->nd_tbl);
571
+ break;
572
+
573
+ case NODE_OP_ASGN1:
574
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
575
+ #{if_version :>, "1.8.4", "#if 0"}
576
+ #{if_version :<=, "1.8.4", "#if 1"}
577
+ add_to_parse_tree(current, node->nd_args->nd_next, newlines, locals);
578
+ rb_ary_pop(rb_ary_entry(current, -1)); // no idea why I need this
579
+ #else
580
+ add_to_parse_tree(current, node->nd_args->nd_2nd, newlines, locals);
581
+ #endif
582
+ switch (node->nd_mid) {
583
+ case 0:
584
+ rb_ary_push(current, ID2SYM(rb_intern("||")));
585
+ break;
586
+ case 1:
587
+ rb_ary_push(current, ID2SYM(rb_intern("&&")));
588
+ break;
589
+ default:
590
+ rb_ary_push(current, ID2SYM(node->nd_mid));
591
+ break;
592
+ }
593
+ add_to_parse_tree(current, node->nd_args->nd_head, newlines, locals);
594
+ break;
595
+
596
+ case NODE_OP_ASGN2:
597
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
598
+ rb_ary_push(current, ID2SYM(node->nd_next->nd_aid));
599
+
600
+ switch (node->nd_next->nd_mid) {
601
+ case 0:
602
+ rb_ary_push(current, ID2SYM(rb_intern("||")));
603
+ break;
604
+ case 1:
605
+ rb_ary_push(current, ID2SYM(rb_intern("&&")));
606
+ break;
607
+ default:
608
+ rb_ary_push(current, ID2SYM(node->nd_next->nd_mid));
609
+ break;
610
+ }
611
+
612
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
613
+ break;
614
+
615
+ case NODE_OP_ASGN_AND:
616
+ case NODE_OP_ASGN_OR:
617
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
618
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
619
+ break;
620
+
621
+ case NODE_MASGN:
622
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
623
+ if (node->nd_args && node->nd_args != (NODE *)-1) {
624
+ add_to_parse_tree(current, node->nd_args, newlines, locals);
625
+ }
626
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
627
+ break;
628
+
629
+ case NODE_LASGN:
630
+ case NODE_IASGN:
631
+ case NODE_DASGN:
632
+ case NODE_DASGN_CURR:
633
+ case NODE_CDECL:
634
+ case NODE_CVASGN:
635
+ case NODE_CVDECL:
636
+ case NODE_GASGN:
637
+ rb_ary_push(current, ID2SYM(node->nd_vid));
638
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
639
+ break;
640
+
641
+ case NODE_VALIAS: // u1 u2 (alias $global $global2)
642
+ #{if_version :>, "1.8.4", "#if 0"}
643
+ #{if_version :<=, "1.8.4", "#if 1"}
644
+ rb_ary_push(current, ID2SYM(node->u2.id));
645
+ rb_ary_push(current, ID2SYM(node->u1.id));
646
+ #else
647
+ rb_ary_push(current, ID2SYM(node->u1.id));
648
+ rb_ary_push(current, ID2SYM(node->u2.id));
649
+ #endif
650
+ break;
651
+ case NODE_ALIAS: // u1 u2 (alias :blah :blah2)
652
+ #{if_version :>, "1.8.4", "#if 0"}
653
+ #{if_version :<=, "1.8.4", "#if 1"}
654
+ rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u2.id)));
655
+ rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u1.id)));
656
+ #else
657
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
658
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
659
+ #endif
660
+ break;
661
+
662
+ case NODE_UNDEF: // u2 (undef name, ...)
663
+ #{if_version :>, "1.8.4", "#if 0"}
664
+ #{if_version :<=, "1.8.4", "#if 1"}
665
+ rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u2.id)));
666
+ #else
667
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
668
+ #endif
669
+ break;
670
+
671
+ case NODE_COLON3: // u2 (::OUTER_CONST)
672
+ rb_ary_push(current, ID2SYM(node->u2.id));
673
+ break;
674
+
675
+ case NODE_HASH:
676
+ {
677
+ NODE *list;
678
+
679
+ list = node->nd_head;
680
+ while (list) {
681
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
682
+ list = list->nd_next;
683
+ if (list == 0)
684
+ rb_bug("odd number list for Hash");
685
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
686
+ list = list->nd_next;
687
+ }
688
+ }
689
+ break;
690
+
691
+ case NODE_ARRAY:
692
+ while (node) {
693
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
694
+ node = node->nd_next;
695
+ }
696
+ break;
697
+
698
+ case NODE_DSTR:
699
+ case NODE_DSYM:
700
+ case NODE_DXSTR:
701
+ case NODE_DREGX:
702
+ case NODE_DREGX_ONCE:
703
+ {
704
+ NODE *list = node->nd_next;
705
+ rb_ary_push(current, rb_str_new3(node->nd_lit));
706
+ while (list) {
707
+ if (list->nd_head) {
708
+ switch (nd_type(list->nd_head)) {
709
+ case NODE_STR:
710
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
711
+ break;
712
+ case NODE_EVSTR:
713
+ add_to_parse_tree(current, list->nd_head->nd_body, newlines, locals);
714
+ break;
715
+ default:
716
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
717
+ break;
718
+ }
719
+ }
720
+ list = list->nd_next;
721
+ }
722
+ }
723
+ break;
724
+
725
+ case NODE_DEFN:
726
+ case NODE_DEFS:
727
+ if (node->nd_defn) {
728
+ if (nd_type(node) == NODE_DEFS)
729
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
730
+ rb_ary_push(current, ID2SYM(node->nd_mid));
731
+ add_to_parse_tree(current, node->nd_defn, newlines, locals);
732
+ }
733
+ break;
734
+
735
+ case NODE_CLASS:
736
+ case NODE_MODULE:
737
+ rb_ary_push(current, ID2SYM((ID)node->nd_cpath->nd_mid));
738
+ if (nd_type(node) == NODE_CLASS) {
739
+ if (node->nd_super) {
740
+ add_to_parse_tree(current, node->nd_super, newlines, locals);
741
+ } else {
742
+ rb_ary_push(current, Qnil);
743
+ }
744
+ }
745
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
746
+ break;
747
+
748
+ case NODE_SCLASS:
749
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
750
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
751
+ break;
752
+
753
+ case NODE_ARGS: {
754
+ long arg_count = (long)node->nd_rest;
755
+ if (locals && (node->nd_cnt || node->nd_opt || arg_count != -1)) {
756
+ int i;
757
+ int max_args;
758
+ NODE *optnode;
759
+
760
+ max_args = node->nd_cnt;
761
+ for (i = 0; i < max_args; i++) {
762
+ // regular arg names
763
+ rb_ary_push(current, ID2SYM(locals[i + 3]));
764
+ }
765
+
766
+ optnode = node->nd_opt;
767
+ while (optnode) {
768
+ // optional arg names
769
+ rb_ary_push(current, ID2SYM(locals[i + 3]));
770
+ i++;
771
+ optnode = optnode->nd_next;
772
+ }
773
+
774
+ if (arg_count > 0) {
775
+ // *arg name
776
+ VALUE sym = rb_str_intern(rb_str_plus(rb_str_new2("*"), rb_str_new2(rb_id2name(locals[i + 3]))));
777
+ rb_ary_push(current, sym);
778
+ } else if (arg_count == 0) {
779
+ // nothing to do in this case, empty list
780
+ } else if (arg_count == -1) {
781
+ // nothing to do in this case, handled above
782
+ } else if (arg_count == -2) {
783
+ // nothing to do in this case, no name == no use
784
+ } else {
785
+ rb_raise(rb_eArgError,
786
+ "not a clue what this arg value is: %ld", arg_count);
787
+ }
788
+
789
+ optnode = node->nd_opt;
790
+ // block?
791
+ if (optnode) {
792
+ add_to_parse_tree(current, node->nd_opt, newlines, locals);
793
+ }
794
+ }
795
+ } break;
796
+
797
+ case NODE_LVAR:
798
+ case NODE_DVAR:
799
+ case NODE_IVAR:
800
+ case NODE_CVAR:
801
+ case NODE_GVAR:
802
+ case NODE_CONST:
803
+ case NODE_ATTRSET:
804
+ rb_ary_push(current, ID2SYM(node->nd_vid));
805
+ break;
806
+
807
+ case NODE_XSTR: // u1 (%x{ls})
808
+ case NODE_STR: // u1
809
+ case NODE_LIT:
810
+ rb_ary_push(current, node->nd_lit);
811
+ break;
812
+
813
+ case NODE_MATCH: // u1 -> [:lit, u1]
814
+ {
815
+ rb_ary_push(current, wrap_into_node("lit", node->nd_lit));
816
+ }
817
+ break;
818
+
819
+ case NODE_NEWLINE:
820
+ rb_ary_push(current, INT2FIX(nd_line(node)));
821
+ rb_ary_push(current, rb_str_new2(node->nd_file));
822
+
823
+ if (! RTEST(newlines)) rb_ary_pop(ary); // nuke it
824
+
825
+ node = node->nd_next;
826
+ goto again;
827
+ break;
828
+
829
+ case NODE_NTH_REF: // u2 u3 ($1) - u3 is local_cnt('~') ignorable?
830
+ rb_ary_push(current, INT2FIX(node->nd_nth));
831
+ break;
832
+
833
+ case NODE_BACK_REF: // u2 u3 ($& etc)
834
+ {
835
+ char c = node->nd_nth;
836
+ rb_ary_push(current, rb_str_intern(rb_str_new(&c, 1)));
837
+ }
838
+ break;
839
+
840
+ case NODE_BLOCK_ARG: // u1 u3 (def x(&b)
841
+ rb_ary_push(current, ID2SYM(node->u1.id));
842
+ break;
843
+
844
+ // these nodes are empty and do not require extra work:
845
+ case NODE_RETRY:
846
+ case NODE_FALSE:
847
+ case NODE_NIL:
848
+ case NODE_SELF:
849
+ case NODE_TRUE:
850
+ case NODE_ZARRAY:
851
+ case NODE_ZSUPER:
852
+ case NODE_REDO:
853
+ break;
854
+
855
+ case NODE_SPLAT:
856
+ case NODE_TO_ARY:
857
+ case NODE_SVALUE: // a = b, c
858
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
859
+ break;
860
+
861
+ case NODE_ATTRASGN: // literal.meth = y u1 u2 u3
862
+ // node id node
863
+ if (node->nd_1st == RNODE(1)) {
864
+ add_to_parse_tree(current, NEW_SELF(), newlines, locals);
865
+ } else {
866
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
867
+ }
868
+ rb_ary_push(current, ID2SYM(node->u2.id));
869
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
870
+ break;
871
+
872
+ case NODE_EVSTR:
873
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
874
+ break;
875
+
876
+ case NODE_POSTEXE: // END { ... }
877
+ // Nothing to do here... we are in an iter block
878
+ break;
879
+
880
+ case NODE_CFUNC:
881
+ rb_ary_push(current, INT2FIX(node->nd_cfnc));
882
+ rb_ary_push(current, INT2FIX(node->nd_argc));
883
+ break;
884
+
885
+ #{if_version :<, "1.9", "#if 0"}
886
+ case NODE_ERRINFO:
887
+ case NODE_VALUES:
888
+ case NODE_PRELUDE:
889
+ case NODE_LAMBDA:
890
+ puts("no worky in 1.9 yet");
891
+ break;
892
+ #{if_version :<, "1.9", "#endif"}
893
+
894
+ // Nodes we found but have yet to decypher
895
+ // I think these are all runtime only... not positive but...
896
+ case NODE_MEMO: // enum.c zip
897
+ case NODE_CREF:
898
+ case NODE_IFUNC:
899
+ // #defines:
900
+ // case NODE_LMASK:
901
+ // case NODE_LSHIFT:
902
+ default:
903
+ rb_warn("Unhandled node #%d type '%s'", nd_type(node), rb_id2name(SYM2ID(rb_ary_entry(node_names, nd_type(node)))));
904
+ if (RNODE(node)->u1.node != NULL) rb_warning("unhandled u1 value");
905
+ if (RNODE(node)->u2.node != NULL) rb_warning("unhandled u2 value");
906
+ if (RNODE(node)->u3.node != NULL) rb_warning("unhandled u3 value");
907
+ if (RTEST(ruby_debug)) fprintf(stderr, "u1 = %p u2 = %p u3 = %p\\n", node->nd_1st, node->nd_2nd, node->nd_3rd);
908
+ rb_ary_push(current, INT2FIX(-99));
909
+ rb_ary_push(current, INT2FIX(nd_type(node)));
910
+ break;
911
+ }
912
+
913
+ finish:
914
+ if (contnode) {
915
+ node = contnode;
916
+ contnode = NULL;
917
+ current = ary;
918
+ ary = old_ary;
919
+ old_ary = Qnil;
920
+ goto again_no_block;
921
+ }
922
+ }
923
+ @ # end of add_to_parse_tree block
924
+
925
+ builder.c %Q{
926
+ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines, VALUE is_cls_meth) {
927
+ VALUE n;
928
+ NODE *node = NULL;
929
+ ID id;
930
+ VALUE result = rb_ary_new();
931
+ VALUE version = rb_const_get_at(rb_cObject,rb_intern("RUBY_VERSION"));
932
+
933
+ (void) self; // quell warnings
934
+
935
+ if (strcmp(StringValuePtr(version), #{RUBY_VERSION.inspect})) {
936
+ rb_fatal("bad version, %s != #{RUBY_VERSION}\\n", StringValuePtr(version));
937
+ }
938
+
939
+ id = rb_to_id(method);
940
+ if (RTEST(is_cls_meth)) { // singleton method
941
+ klass = CLASS_OF(klass);
942
+ }
943
+ if (st_lookup(RCLASS(klass)->m_tbl, id, &n)) {
944
+ node = (NODE*)n;
945
+ rb_ary_push(result, ID2SYM(rb_intern("defn")));
946
+ rb_ary_push(result, ID2SYM(id));
947
+ add_to_parse_tree(result, node->nd_body, newlines, NULL);
948
+ } else {
949
+ rb_ary_push(result, Qnil);
950
+ }
951
+
952
+ return result;
953
+ }
954
+ }
955
+
956
+ builder.prefix " extern NODE *ruby_eval_tree_begin; " \
957
+ if RUBY_VERSION < '1.9.0'
958
+
959
+ builder.c %Q{
960
+ static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line,
961
+ VALUE newlines) {
962
+ VALUE tmp;
963
+ VALUE result = rb_ary_new();
964
+ NODE *node = NULL;
965
+ int critical;
966
+
967
+ (void) self; // quell warnings
968
+
969
+ tmp = rb_check_string_type(filename);
970
+ if (NIL_P(tmp)) {
971
+ filename = rb_str_new2("(string)");
972
+ }
973
+
974
+ if (NIL_P(line)) {
975
+ line = LONG2FIX(1);
976
+ }
977
+
978
+ newlines = RTEST(newlines);
979
+
980
+ ruby_nerrs = 0;
981
+ StringValue(source);
982
+ critical = rb_thread_critical;
983
+ rb_thread_critical = Qtrue;
984
+ ruby_in_eval++;
985
+ node = rb_compile_string(StringValuePtr(filename), source, NUM2INT(line));
986
+ ruby_in_eval--;
987
+ rb_thread_critical = critical;
988
+
989
+ if (ruby_nerrs > 0) {
990
+ ruby_nerrs = 0;
991
+ #if RUBY_VERSION_CODE < 190
992
+ ruby_eval_tree_begin = 0;
993
+ #endif
994
+ rb_exc_raise(ruby_errinfo);
995
+ }
996
+
997
+ add_to_parse_tree(result, node, newlines, NULL);
998
+
999
+ return result;
1000
+ }
1001
+ }
1002
+
1003
+ end # inline call
1004
+ end # ParseTree class