ParseTree 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,19 @@
1
+ *** 1.5.0 / 2006-09-24
2
+
3
+ + 5 minor enhancements:
4
+ Added parse_tree_audit.
5
+ Added reporting of unsupported nodes that have processors.
6
+ YAY! class method support! generated as :"self.blah"
7
+ Add parse_tree_for_string.
8
+ Converted Rakefile+gemspec to Hoe-based Rakefile.
9
+ + 6 bug fixes:
10
+ Did some preliminary work on 1.9 compatibility.
11
+ Fixed tests for some changes/clarifications.
12
+ Fixed resbody: should have nil exceptions list when no exception rescued.
13
+ Fixed op_asgn1 and op_asgn2.
14
+ Fixed incompatibility with new inline changes.
15
+ Fixed VALUE decl in parse_tree.rb
16
+
1
17
  *** 1.4.1 / 2006-04-10
2
18
 
3
19
  + 4 minor enhancements:
@@ -1,9 +1,9 @@
1
1
  History.txt
2
2
  Rakefile
3
3
  Manifest.txt
4
- ParseTree.gemspec
5
4
  README.txt
6
5
  bin/parse_tree_abc
6
+ bin/parse_tree_audit
7
7
  bin/parse_tree_deps
8
8
  bin/parse_tree_show
9
9
  demo/printer.rb
@@ -11,6 +11,7 @@ lib/composite_sexp_processor.rb
11
11
  lib/parse_tree.rb
12
12
  lib/sexp.rb
13
13
  lib/sexp_processor.rb
14
+ test/pt_testcase.rb
14
15
  test/something.rb
15
16
  test/test_all.rb
16
17
  test/test_composite_sexp_processor.rb
data/Rakefile CHANGED
@@ -1,80 +1,30 @@
1
1
  # -*- ruby -*-
2
2
 
3
- require 'rbconfig'
4
- require 'rake/rdoctask'
3
+ require 'rubygems'
4
+ require 'hoe'
5
5
 
6
- PREFIX = ENV['PREFIX'] || Config::CONFIG['prefix']
7
- RUBYLIB = Config::CONFIG['sitelibdir']
8
- RUBY_DEBUG = ENV['RUBY_DEBUG']
9
- RUBY_FLAGS = ENV['RUBY_FLAGS'] || "-w -Ilib#{File::PATH_SEPARATOR}bin#{File::PATH_SEPARATOR}../../RubyInline/dev"
10
- FILTER = ENV['FILTER']
6
+ $: << "../../RubyInline/dev"
7
+ require './lib/parse_tree.rb'
11
8
 
12
- LIB_FILES = %w(composite_sexp_processor.rb parse_tree.rb sexp.rb sexp_processor.rb)
13
- TEST_FILES = %w(test_sexp_processor.rb)
14
- BIN_FILES = %w(parse_tree_abc parse_tree_show parse_tree_deps)
15
-
16
- task :default => :test
17
-
18
- task :test do
19
- ruby "#{RUBY_FLAGS} test/test_all.rb #{FILTER}"
20
- end
21
-
22
- task :multi do
23
- sh "multiruby #{RUBY_FLAGS} test/test_all.rb #{FILTER}"
24
- end
25
-
26
- # we only install test_sexp_processor.rb to help make ruby_to_c's
27
- # subclass tests work.
28
-
29
- Rake::RDocTask.new(:docs) do |rd|
30
- rd.main = "SexpProcessor"
31
- rd.rdoc_files.include('./**/*').exclude('something.rb').exclude('test_*')
32
- rd.options << '-d'
33
- rd.options << '-Ipng'
9
+ Hoe.new("ParseTree", ParseTree::VERSION) do |p|
10
+ p.summary = "Extract and enumerate ruby parse trees."
11
+ p.description = File.read("README.txt").split(/\n\n+/)[2]
12
+ p.clean_globs << File.expand_path("~/.ruby_inline")
13
+ p.extra_deps << ['RubyInline', '>= 3.2.0']
34
14
  end
35
15
 
36
- task :install do
37
- [
38
- ['lib', LIB_FILES, RUBYLIB, 0444],
39
- ['test', TEST_FILES, RUBYLIB, 0444],
40
- ['bin', BIN_FILES, File.join(PREFIX, 'bin'), 0555]
41
- ].each do |dir, list, dest, mode|
42
- Dir.chdir dir do
43
- list.each do |f|
44
- install f, dest, :mode => mode
45
- end
46
- end
47
- end
16
+ desc 'Run against ruby 1.9 (from a multiruby install) with -d.'
17
+ task :test19 do
18
+ sh "~/.multiruby/install/1_9/bin/ruby -d #{Hoe::RUBY_FLAGS} test/test_all.rb #{Hoe::FILTER}"
48
19
  end
49
20
 
50
- task :uninstall do
51
- Dir.chdir RUBYLIB do
52
- rm_f LIB_FILES
53
- rm_f TEST_FILES
54
- end
55
- Dir.chdir File.join(PREFIX, 'bin') do
56
- rm_f BIN_FILES
57
- end
58
- end
59
-
60
- task :audit do
61
- sh "ZenTest -Ilib#{File::PATH_SEPARATOR}test #{LIB_FILES.collect{|e| File.join('lib', e)}.join(' ')} test/test_all.rb"
62
- # test_composite_sexp_processor.rb test_sexp_processor.rb
63
- end
64
-
65
- task :clean do
66
- inline_dir = File.expand_path("~/.ruby_inline")
67
- rm_rf inline_dir if test ?d, inline_dir
68
- %w(diff diff.txt demo.rb *.gem **/*~).each do |pattern|
69
- files = Dir[pattern]
70
- rm_rf files unless files.empty?
71
- end
21
+ desc 'Run in gdb'
22
+ task :debug do
23
+ puts "RUN: r -d #{Hoe::RUBY_FLAGS} test/test_all.rb #{Hoe::FILTER}"
24
+ sh "gdb ~/.multiruby/install/19/bin/ruby"
72
25
  end
73
26
 
27
+ desc 'Run a very basic demo'
74
28
  task :demo do
75
- verbose(false){sh "echo 1+1 | ruby #{RUBY_FLAGS} ./bin/parse_tree_show -f"}
76
- end
77
-
78
- task :gem do
79
- ruby "ParseTree.gemspec"
29
+ sh "echo 1+1 | ruby #{Hoe::RUBY_FLAGS} ./bin/parse_tree_show -f"
80
30
  end
@@ -0,0 +1,28 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'parse_tree'
4
+
5
+ all_nodes = ParseTree::NODE_NAMES
6
+
7
+ ARGV.each do |processor|
8
+ require processor
9
+ end
10
+
11
+ ObjectSpace.each_object(Class) do |klass|
12
+ if klass < SexpProcessor then
13
+
14
+ processor = klass.new
15
+ processors = klass.public_instance_methods(true).grep(/process_/)
16
+
17
+ if processor.strict then
18
+ puts "#{klass.name}:"
19
+ puts
20
+
21
+ # TODO: check unsupported against supported
22
+ processors = processors.map { |m| m[8..-1].intern } + processor.unsupported
23
+ unsupported = all_nodes - processors
24
+ p unsupported.sort_by { |sym| sym.to_s }
25
+ puts
26
+ end
27
+ end
28
+ end
@@ -25,7 +25,7 @@ require 'inline'
25
25
 
26
26
  class ParseTree
27
27
 
28
- VERSION = '1.4.1'
28
+ VERSION = '1.5.0'
29
29
 
30
30
  ##
31
31
  # Initializes a ParseTree instance. Includes newline nodes if
@@ -76,9 +76,13 @@ class ParseTree
76
76
  # protected methods are included in instance_methods, go figure!
77
77
 
78
78
  method_names.sort.each do |m|
79
- $stderr.puts "parse_tree_for_method(#{klass}, #{m}):" if $DEBUG
80
79
  code << parse_tree_for_method(klass, m.to_sym)
81
80
  end
81
+
82
+ klass.singleton_methods.sort.each do |m|
83
+ code << parse_tree_for_method(klass, m.to_sym, true)
84
+ end
85
+
82
86
  result << code
83
87
  end
84
88
  return result
@@ -91,8 +95,25 @@ class ParseTree
91
95
  #
92
96
  # [:defn, :name, :body]
93
97
 
94
- def parse_tree_for_method(klass, method)
95
- parse_tree_for_meth(klass, method.to_sym, @include_newlines)
98
+ def parse_tree_for_method(klass, method, is_cls_meth=false)
99
+ $stderr.puts "** parse_tree_for_method(#{klass}, #{method}):" if $DEBUG
100
+ r = parse_tree_for_meth(klass, method.to_sym, @include_newlines, is_cls_meth)
101
+ r[1] = :"self.#{r[1]}" if is_cls_meth
102
+ r
103
+ end
104
+
105
+ ##
106
+ # Returns the parse tree for a string +source+.
107
+ #
108
+ # Format:
109
+ #
110
+ # [[sexps] ... ]
111
+
112
+ def parse_tree_for_string(source, filename = nil, line = nil,
113
+ newlines = false)
114
+ filename ||= '(string)'
115
+ line ||= 1
116
+ return parse_tree_for_str(source, filename, line, newlines)
96
117
  end
97
118
 
98
119
  if RUBY_VERSION < "1.8.4" then
@@ -149,7 +170,6 @@ class ParseTree
149
170
  :newline, :postexe, :alloca, :dmethod, :bmethod,
150
171
  # 100
151
172
  :memo, :ifunc, :dsym, :attrasgn,
152
- # 104
153
173
  :last
154
174
  ]
155
175
 
@@ -171,11 +191,11 @@ class ParseTree
171
191
 
172
192
  inline do |builder|
173
193
  builder.add_type_converter("bool", '', '')
174
- builder.add_type_converter("VALUE", '', '')
175
194
  builder.add_type_converter("ID *", '', '')
176
195
  builder.add_type_converter("NODE *", '(NODE *)', '(VALUE)')
177
196
  builder.include '"intern.h"'
178
197
  builder.include '"version.h"'
198
+ builder.include '"rubysig.h"'
179
199
  builder.include '"node.h"'
180
200
  builder.include '"st.h"'
181
201
  builder.include '"env.h"'
@@ -238,7 +258,10 @@ class ParseTree
238
258
  struct BLOCK *outer;
239
259
  struct BLOCK *prev;
240
260
  };
241
- } unless RUBY_VERSION >= "1.9"
261
+ } unless RUBY_VERSION >= "1.9" # we got matz to add this to env.h
262
+
263
+ ##
264
+ # add_to_parse_tree(ary, node, include_newlines, local_variables)
242
265
 
243
266
  builder.c_raw %Q@
244
267
  static void add_to_parse_tree(VALUE ary,
@@ -400,7 +423,11 @@ again_no_block:
400
423
  // a = b rescue c
401
424
 
402
425
  case NODE_RESBODY:
403
- add_to_parse_tree(current, node->nd_3rd, newlines, locals);
426
+ if (node->nd_3rd) {
427
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
428
+ } else {
429
+ rb_ary_push(current, Qnil);
430
+ }
404
431
  add_to_parse_tree(current, node->nd_2nd, newlines, locals);
405
432
  add_to_parse_tree(current, node->nd_1st, newlines, locals);
406
433
  break;
@@ -484,11 +511,36 @@ again_no_block:
484
511
  case NODE_OP_ASGN1:
485
512
  add_to_parse_tree(current, node->nd_recv, newlines, locals);
486
513
  add_to_parse_tree(current, node->nd_args->nd_next, newlines, locals);
514
+ switch (node->nd_mid) {
515
+ case 0:
516
+ rb_ary_push(current, ID2SYM(rb_intern("||")));
517
+ break;
518
+ case 1:
519
+ rb_ary_push(current, ID2SYM(rb_intern("&&")));
520
+ break;
521
+ default:
522
+ rb_ary_push(current, ID2SYM(node->nd_mid));
523
+ break;
524
+ }
487
525
  add_to_parse_tree(current, node->nd_args->nd_head, newlines, locals);
488
526
  break;
489
527
 
490
528
  case NODE_OP_ASGN2:
491
529
  add_to_parse_tree(current, node->nd_recv, newlines, locals);
530
+ rb_ary_push(current, ID2SYM(node->nd_next->nd_aid));
531
+
532
+ switch (node->nd_next->nd_mid) {
533
+ case 0:
534
+ rb_ary_push(current, ID2SYM(rb_intern("||")));
535
+ break;
536
+ case 1:
537
+ rb_ary_push(current, ID2SYM(rb_intern("&&")));
538
+ break;
539
+ default:
540
+ rb_ary_push(current, ID2SYM(node->nd_next->nd_mid));
541
+ break;
542
+ }
543
+
492
544
  add_to_parse_tree(current, node->nd_value, newlines, locals);
493
545
  break;
494
546
 
@@ -611,9 +663,11 @@ again_no_block:
611
663
  long arg_count = (long)node->nd_rest;
612
664
  if (locals && (node->nd_cnt || node->nd_opt || arg_count != -1)) {
613
665
  int i;
666
+ int max_args;
614
667
  NODE *optnode;
615
668
 
616
- for (i = 0; i < node->nd_cnt; i++) {
669
+ max_args = node->nd_cnt;
670
+ for (i = 0; i < max_args; i++) {
617
671
  // regular arg names
618
672
  rb_ary_push(current, ID2SYM(locals[i + 3]));
619
673
  }
@@ -736,6 +790,15 @@ again_no_block:
736
790
  rb_ary_push(current, INT2FIX(node->nd_argc));
737
791
  break;
738
792
 
793
+ #{if_version :<, "1.9", "#if 0"}
794
+ case NODE_ERRINFO:
795
+ case NODE_VALUES:
796
+ case NODE_PRELUDE:
797
+ case NODE_LAMBDA:
798
+ puts("no worky in 1.9 yet");
799
+ break;
800
+ #{if_version :<, "1.9", "#endif"}
801
+
739
802
  // Nodes we found but have yet to decypher
740
803
  // I think these are all runtime only... not positive but...
741
804
  case NODE_MEMO: // enum.c zip
@@ -768,14 +831,13 @@ again_no_block:
768
831
  @ # end of add_to_parse_tree block
769
832
 
770
833
  builder.c %Q{
771
- static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines) {
834
+ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines, VALUE is_cls_meth) {
772
835
  VALUE n;
773
836
  NODE *node = NULL;
774
837
  ID id;
775
838
  VALUE result = rb_ary_new();
776
839
 
777
840
  (void) self; // quell warnings
778
- (void) argc; // quell warnings
779
841
 
780
842
  VALUE version = rb_const_get_at(rb_cObject,rb_intern("RUBY_VERSION"));
781
843
  if (strcmp(StringValuePtr(version), #{RUBY_VERSION.inspect})) {
@@ -783,6 +845,9 @@ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines) {
783
845
  }
784
846
 
785
847
  id = rb_to_id(method);
848
+ if (RTEST(is_cls_meth)) { // singleton method
849
+ klass = CLASS_OF(klass);
850
+ }
786
851
  if (st_lookup(RCLASS(klass)->m_tbl, id, &n)) {
787
852
  node = (NODE*)n;
788
853
  rb_ary_push(result, ID2SYM(rb_intern("defn")));
@@ -795,5 +860,53 @@ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines) {
795
860
  return result;
796
861
  }
797
862
  }
863
+
864
+ builder.prefix " extern NODE *ruby_eval_tree_begin; " \
865
+ if RUBY_VERSION < '1.9.0'
866
+
867
+ builder.c %Q{
868
+ static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line,
869
+ VALUE newlines) {
870
+ VALUE tmp;
871
+ VALUE result = rb_ary_new();
872
+ NODE *node = NULL;
873
+ int critical;
874
+
875
+ (void) self; // quell warnings
876
+
877
+ tmp = rb_check_string_type(filename);
878
+ if (NIL_P(tmp)) {
879
+ filename = rb_str_new2("(string)");
880
+ }
881
+
882
+ if (NIL_P(line)) {
883
+ line = LONG2FIX(1);
884
+ }
885
+
886
+ newlines = RTEST(newlines);
887
+
888
+ ruby_nerrs = 0;
889
+ StringValue(source);
890
+ critical = rb_thread_critical;
891
+ rb_thread_critical = Qtrue;
892
+ ruby_in_eval++;
893
+ node = rb_compile_string(StringValuePtr(filename), source, NUM2INT(line));
894
+ ruby_in_eval--;
895
+ rb_thread_critical = critical;
896
+
897
+ if (ruby_nerrs > 0) {
898
+ ruby_nerrs = 0;
899
+ #if RUBY_VERSION_CODE < 190
900
+ ruby_eval_tree_begin = 0;
901
+ #endif
902
+ rb_exc_raise(ruby_errinfo);
903
+ }
904
+
905
+ add_to_parse_tree(result, node, newlines, NULL);
906
+
907
+ return result;
908
+ }
909
+ }
910
+
798
911
  end # inline call
799
912
  end # ParseTree class
@@ -138,6 +138,7 @@ class SexpProcessor
138
138
  @auto_shift_type = false
139
139
  @strict = false
140
140
  @unsupported = []
141
+ @unsupported_checked = false
141
142
  @debug = {}
142
143
  @expected = Sexp
143
144
  @require_empty = true
@@ -167,6 +168,15 @@ class SexpProcessor
167
168
  def process(exp)
168
169
  return nil if exp.nil?
169
170
 
171
+ unless @unsupported_checked then
172
+ m = public_methods.grep(/^process_/) { |o| o.sub(/^process_/, '').intern }
173
+ supported = m - (m - @unsupported)
174
+
175
+ raise UnsupportedNodeError, "#{supported.inspect} shouldn't be in @unsupported" unless supported.empty?
176
+
177
+ @unsupported_checked = true
178
+ end
179
+
170
180
  result = self.expected.new
171
181
 
172
182
  type = exp.first
@@ -307,7 +317,7 @@ class SexpProcessor
307
317
  # end
308
318
 
309
319
  def process_dummy(exp)
310
- result = @expected.new(:dummy)
320
+ result = @expected.new(:dummy) rescue @expected.new
311
321
  until exp.empty? do
312
322
  result << self.process(exp.shift)
313
323
  end
@@ -0,0 +1,1378 @@
1
+ require 'test/unit/testcase'
2
+ require 'sexp_processor' # for deep_clone FIX
3
+ require 'typed_sexp'
4
+ require 'unique'
5
+
6
+ # TODO: str -> char * in ansi c
7
+ # TODO: add tests that mix types up to fuck up RubyC type checker
8
+
9
+ class R2CTestCase < Test::Unit::TestCase
10
+
11
+ attr_accessor :processor # to be defined by subclass
12
+
13
+ def self.testcase_order; @@testcase_order; end
14
+ def self.testcases; @@testcases; end
15
+
16
+ def setup
17
+ super
18
+ @processor = nil
19
+ Unique.reset
20
+ end
21
+
22
+ @@testcase_order = %w(Ruby ParseTree Rewriter TypeChecker CRewriter RubyToAnsiC RubyToRubyC)
23
+
24
+ @@testcases = {
25
+
26
+ "accessor" => {
27
+ "Ruby" => "attr_reader :accessor",
28
+ "ParseTree" => [:defn, :accessor, [:ivar, :@accessor]],
29
+ "Rewriter" => s(:defn, :accessor, s(:args),
30
+ s(:scope,
31
+ s(:block, s(:return, s(:ivar, :@accessor))))),
32
+ "TypeChecker" => :skip,
33
+ "CRewriter" => :skip,
34
+ "RubyToAnsiC" => :skip,
35
+ "RubyToRubyC" => :skip,
36
+ },
37
+
38
+ "accessor_equals" => {
39
+ "Ruby" => "attr_writer :accessor",
40
+ "ParseTree" => [:defn, :accessor=, [:attrset, :@accessor]],
41
+ "Rewriter" => s(:defn,
42
+ :accessor=,
43
+ s(:args, :arg),
44
+ s(:scope,
45
+ s(:block,
46
+ s(:return,
47
+ s(:iasgn, :@accessor, s(:lvar, :arg)))))),
48
+ "TypeChecker" => :skip,
49
+ "CRewriter" => :skip,
50
+ "RubyToRubyC" => :skip,
51
+ "RubyToAnsiC" => :skip,
52
+ },
53
+
54
+ "defn_bbegin" => {
55
+ "Ruby" => "def bbegin()
56
+ begin
57
+ 1 + 1
58
+ rescue SyntaxError
59
+ e1 = $!
60
+ 2
61
+ rescue Exception
62
+ e2 = $!
63
+ 3
64
+ else
65
+ 4end
66
+ ensure
67
+ 5
68
+ end",
69
+ "ParseTree" => [:defn, :bbegin,
70
+ [:scope,
71
+ [:block,
72
+ [:args],
73
+ [:begin,
74
+ [:ensure,
75
+ [:rescue,
76
+ [:call, [:lit, 1], :+, [:array, [:lit, 1]]],
77
+ [:resbody,
78
+ [:array, [:const, :SyntaxError]],
79
+ [:block, [:lasgn, :e1, [:gvar, :$!]], [:lit, 2]],
80
+ [:resbody,
81
+ [:array, [:const, :Exception]],
82
+ [:block, [:lasgn, :e2, [:gvar, :$!]], [:lit, 3]]]],
83
+ [:lit, 4]],
84
+ [:lit, 5]]]]]],
85
+ "Rewriter" => s(:defn, :bbegin,
86
+ s(:args),
87
+ s(:scope,
88
+ s(:block,
89
+ s(:begin,
90
+ s(:ensure,
91
+ s(:rescue,
92
+ s(:call, s(:lit, 1), :+, s(:arglist, s(:lit, 1))),
93
+ s(:resbody,
94
+ s(:array, s(:const, :SyntaxError)),
95
+ s(:block, s(:lasgn, :e1, s(:gvar, :$!)),
96
+ s(:lit, 2)),
97
+ s(:resbody,
98
+ s(:array, s(:const, :Exception)),
99
+ s(:block, s(:lasgn, :e2, s(:gvar, :$!)),
100
+ s(:lit, 3)))),
101
+ s(:lit, 4)),
102
+ s(:lit, 5)))))),
103
+ "TypeChecker" => t(:defn, :bbegin,
104
+ t(:args),
105
+ t(:scope,
106
+ t(:block,
107
+ t(:begin,
108
+ t(:ensure,
109
+ t(:rescue,
110
+ t(:call,
111
+ t(:lit, 1, Type.long),
112
+ :+,
113
+ t(:arglist, t(:lit, 1, Type.long)), Type.long),
114
+ t(:resbody,
115
+ t(:array, t(:const, :SyntaxError, Type.fucked)),
116
+ t(:block,
117
+ t(:lasgn, :e1, t(:gvar, :$!, Type.unknown),
118
+ Type.unknown),
119
+ t(:lit, 2, Type.long), Type.unknown),
120
+ t(:resbody,
121
+ t(:array, t(:const, :Exception, Type.fucked)),
122
+ t(:block,
123
+ t(:lasgn, :e2, t(:gvar, :$!, Type.unknown),
124
+ Type.unknown),
125
+ t(:lit, 3, Type.long), Type.unknown),
126
+ Type.unknown), Type.long),
127
+ t(:lit, 4, Type.long), Type.long),
128
+ t(:lit, 5, Type.long))), Type.unknown),
129
+ Type.void),
130
+ Type.function(Type.unknown, [], Type.void)),
131
+ "CRewriter" => :same,
132
+ "RubyToRubyC" => :unsupported,
133
+ "RubyToAnsiC" => :unsupported,
134
+ },
135
+
136
+ "bools" => {
137
+ "Ruby" => "def bools(arg1)
138
+ if (arg1.nil?)
139
+ return false
140
+ else
141
+ return true
142
+ end
143
+ end",
144
+ "ParseTree" => [:defn, :bools,
145
+ [:scope,
146
+ [:block,
147
+ [:args, :arg1],
148
+ [:if,
149
+ [:call, [:lvar, :arg1], "nil?".intern], # emacs is freakin'
150
+ [:return, [:false]],
151
+ [:return, [:true]]]]]],
152
+ "Rewriter" => s(:defn, :bools,
153
+ s(:args, :arg1),
154
+ s(:scope,
155
+ s(:block,
156
+ s(:if,
157
+ s(:call,
158
+ s(:lvar, :arg1),
159
+ :nil?,
160
+ nil),
161
+ s(:return, s(:false)),
162
+ s(:return, s(:true)))))),
163
+ # TODO: why does return false have type void?
164
+ "TypeChecker" => t(:defn, :bools,
165
+ t(:args, t(:arg1, Type.value)),
166
+ t(:scope,
167
+ t(:block,
168
+ t(:if,
169
+ t(:call,
170
+ t(:lvar, :arg1, Type.value),
171
+ :nil?,
172
+ nil,
173
+ Type.bool),
174
+ t(:return,
175
+ t(:false, Type.bool),
176
+ Type.void),
177
+ t(:return,
178
+ t(:true, Type.bool),
179
+ Type.void),
180
+ Type.void),
181
+ Type.unknown),
182
+ Type.void),
183
+ Type.function(Type.unknown, [Type.value], Type.bool)),
184
+ "CRewriter" => :same,
185
+ "RubyToRubyC" => "static VALUE\nrrc_c_bools(VALUE self, VALUE arg1) {\nif (NIL_P(arg1)) {\nreturn Qfalse;\n} else {\nreturn Qtrue;\n}\n}",
186
+ "RubyToAnsiC" => "bool\nbools(void * arg1) {\nif (arg1) {\nreturn 0;\n} else {\nreturn 1;\n}\n}",
187
+ },
188
+
189
+ # TODO: move all call tests here
190
+ "call_arglist" => {
191
+ "Ruby" => "puts(42)",
192
+ "ParseTree" => [:fcall, :puts, [:array, [:lit, 42]]],
193
+ "Rewriter" => s(:call, nil, :puts, s(:arglist, s(:lit, 42))),
194
+ "TypeChecker" => :skip,
195
+ "CRewriter" => :skip,
196
+ "RubyToRubyC" => :skip,
197
+ "RubyToAnsiC" => :skip,
198
+ },
199
+
200
+ "call_attrasgn" => {
201
+ "Ruby" => "42.method=(y)",
202
+ "ParseTree" => [:attrasgn, [:lit, 42], :method=, [:array, [:lvar, :y]]],
203
+ "Rewriter" => s(:call, s(:lit, 42), :method=, s(:arglist, s(:lvar, :y))),
204
+ "TypeChecker" => :skip,
205
+ "CRewriter" => :skip,
206
+ "RubyToRubyC" => :skip,
207
+ "RubyToAnsiC" => :skip,
208
+ },
209
+
210
+ "call_self" => {
211
+ "Ruby" => "self.method",
212
+ "ParseTree" => [:call, [:self], :method],
213
+ "Rewriter" => s(:call, s(:lvar, :self), :method, nil),
214
+ "TypeChecker" => :skip,
215
+ "CRewriter" => :skip,
216
+ "RubyToRubyC" => :skip,
217
+ "RubyToAnsiC" => :skip,
218
+ },
219
+
220
+ "case_stmt" => {
221
+ "Ruby" => "
222
+ def case_stmt()
223
+ var = 2
224
+ result = \"\"
225
+ case var
226
+ when 1
227
+ puts(\"something\")
228
+ result = \"red\"
229
+ when 2, 3
230
+ result = \"yellow\"
231
+ when 4
232
+ else
233
+ result = \"green\"
234
+ end
235
+ case result
236
+ when \"red\"
237
+ var = 1
238
+ when \"yellow\"
239
+ var = 2
240
+ when \"green\"
241
+ var = 3
242
+ else
243
+ end
244
+ return result
245
+ end",
246
+ "ParseTree" => [:defn, :case_stmt,
247
+ [:scope,
248
+ [:block,
249
+ [:args],
250
+ [:lasgn, :var, [:lit, 2]],
251
+ [:lasgn, :result, [:str, ""]],
252
+ [:case,
253
+ [:lvar, :var],
254
+ [:when,
255
+ [:array, [:lit, 1]],
256
+ [:block,
257
+ [:fcall, :puts, [:array, [:str, "something"]]],
258
+ [:lasgn, :result, [:str, "red"]]]],
259
+ [:when,
260
+ [:array, [:lit, 2], [:lit, 3]],
261
+ [:lasgn, :result, [:str, "yellow"]]],
262
+ [:when, [:array, [:lit, 4]], nil],
263
+ [:lasgn, :result, [:str, "green"]]],
264
+ [:case,
265
+ [:lvar, :result],
266
+ [:when, [:array, [:str, "red"]], [:lasgn, :var, [:lit, 1]]],
267
+ [:when, [:array, [:str, "yellow"]], [:lasgn, :var, [:lit, 2]]],
268
+ [:when, [:array, [:str, "green"]], [:lasgn, :var, [:lit, 3]]],
269
+ nil],
270
+ [:return, [:lvar, :result]]]]],
271
+ "Rewriter" => s(:defn, :case_stmt,
272
+ s(:args),
273
+ s(:scope,
274
+ s(:block,
275
+ s(:lasgn, :var, s(:lit, 2)),
276
+ s(:lasgn, :result, s(:str, "")),
277
+ s(:if,
278
+ s(:call,
279
+ s(:lvar, :var),
280
+ :===,
281
+ s(:arglist, s(:lit, 1))),
282
+ s(:block,
283
+ s(:call,
284
+ nil,
285
+ :puts,
286
+ s(:arglist, s(:str, "something"))),
287
+ s(:lasgn, :result, s(:str, "red"))),
288
+ s(:if,
289
+ s(:or,
290
+ s(:call,
291
+ s(:lvar, :var),
292
+ :===,
293
+ s(:arglist, s(:lit, 2))),
294
+ s(:call,
295
+ s(:lvar, :var),
296
+ :===,
297
+ s(:arglist, s(:lit, 3)))),
298
+ s(:lasgn, :result, s(:str, "yellow")),
299
+ s(:if,
300
+ s(:call,
301
+ s(:lvar, :var),
302
+ :===,
303
+ s(:arglist, s(:lit, 4))),
304
+ nil,
305
+ s(:lasgn, :result, s(:str, "green"))))),
306
+ s(:if,
307
+ s(:call,
308
+ s(:lvar, :result),
309
+ :===,
310
+ s(:arglist, s(:str, "red"))),
311
+ s(:lasgn, :var, s(:lit, 1)),
312
+ s(:if,
313
+ s(:call,
314
+ s(:lvar, :result),
315
+ :===,
316
+ s(:arglist, s(:str, "yellow"))),
317
+ s(:lasgn, :var, s(:lit, 2)),
318
+ s(:if,
319
+ s(:call,
320
+ s(:lvar, :result),
321
+ :===,
322
+ s(:arglist, s(:str, "green"))),
323
+ s(:lasgn, :var, s(:lit, 3)),
324
+ nil))),
325
+ s(:return, s(:lvar, :result))))),
326
+ "TypeChecker" => t(:defn, :case_stmt,
327
+ t(:args),
328
+ t(:scope,
329
+ t(:block,
330
+ t(:lasgn,
331
+ :var,
332
+ t(:lit, 2, Type.long),
333
+ Type.long),
334
+ t(:lasgn,
335
+ :result,
336
+ t(:str, "", Type.str),
337
+ Type.str),
338
+ t(:if,
339
+ t(:call,
340
+ t(:lvar, :var, Type.long),
341
+ :case_equal_long,
342
+ t(:arglist, t(:lit, 1, Type.long)),
343
+ Type.bool),
344
+ t(:block,
345
+ t(:call,
346
+ nil,
347
+ :puts,
348
+ t(:arglist,
349
+ t(:str, "something", Type.str)),
350
+ Type.void),
351
+ t(:lasgn,
352
+ :result,
353
+ t(:str, "red", Type.str),
354
+ Type.str),
355
+ Type.str),
356
+ t(:if,
357
+ t(:or,
358
+ t(:call,
359
+ t(:lvar, :var, Type.long),
360
+ :case_equal_long,
361
+ t(:arglist, t(:lit, 2, Type.long)),
362
+ Type.bool),
363
+ t(:call,
364
+ t(:lvar, :var, Type.long),
365
+ :case_equal_long,
366
+ t(:arglist, t(:lit, 3, Type.long)),
367
+ Type.bool),
368
+ Type.bool),
369
+ t(:lasgn,
370
+ :result,
371
+ t(:str, "yellow", Type.str),
372
+ Type.str),
373
+ t(:if,
374
+ t(:call,
375
+ t(:lvar, :var, Type.long),
376
+ :case_equal_long,
377
+ t(:arglist, t(:lit, 4, Type.long)),
378
+ Type.bool),
379
+ nil,
380
+ t(:lasgn,
381
+ :result,
382
+ t(:str, "green", Type.str),
383
+ Type.str),
384
+ Type.str),
385
+ Type.str),
386
+ Type.str),
387
+ t(:if,
388
+ t(:call,
389
+ t(:lvar, :result, Type.str),
390
+ :case_equal_str,
391
+ t(:arglist, t(:str, "red", Type.str)),
392
+ Type.bool),
393
+ t(:lasgn, :var, t(:lit, 1, Type.long), Type.long),
394
+ t(:if,
395
+ t(:call,
396
+ t(:lvar, :result, Type.str),
397
+ :case_equal_str,
398
+ t(:arglist, t(:str, "yellow", Type.str)),
399
+ Type.bool),
400
+ t(:lasgn, :var, t(:lit, 2, Type.long), Type.long),
401
+ t(:if,
402
+ t(:call,
403
+ t(:lvar, :result, Type.str),
404
+ :case_equal_str,
405
+ t(:arglist,
406
+ t(:str, "green", Type.str)),
407
+ Type.bool),
408
+ t(:lasgn,
409
+ :var,
410
+ t(:lit, 3, Type.long),
411
+ Type.long),
412
+ nil,
413
+ Type.long),
414
+ Type.long),
415
+ Type.long),
416
+ t(:return,
417
+ t(:lvar, :result, Type.str),
418
+ Type.void),
419
+ Type.unknown),
420
+ Type.void),
421
+ Type.function(Type.unknown, [], Type.str)),
422
+ "CRewriter" => :same,
423
+ # HACK: I don't like the semis after the if blocks, but it is a compromise right now
424
+ "RubyToRubyC" => "static VALUE
425
+ rrc_c_case_stmt(VALUE self) {
426
+ VALUE result;
427
+ VALUE var;
428
+ var = LONG2NUM(2);
429
+ result = rb_str_new2(\"\");
430
+ if (rb_funcall(var, rb_intern(\"===\"), 1, LONG2NUM(1))) {
431
+ rb_funcall(self, rb_intern(\"puts\"), 1, rb_str_new2(\"something\"));
432
+ result = rb_str_new2(\"red\");
433
+ } else {
434
+ if (rb_funcall(var, rb_intern(\"===\"), 1, LONG2NUM(2)) || rb_funcall(var, rb_intern(\"===\"), 1, LONG2NUM(3))) {
435
+ result = rb_str_new2(\"yellow\");
436
+ } else {
437
+ if (rb_funcall(var, rb_intern(\"===\"), 1, LONG2NUM(4))) {
438
+ ;
439
+ } else {
440
+ result = rb_str_new2(\"green\");
441
+ }
442
+ }
443
+ };
444
+ if (rb_funcall(result, rb_intern(\"===\"), 1, rb_str_new2(\"red\"))) {
445
+ var = LONG2NUM(1);
446
+ } else {
447
+ if (rb_funcall(result, rb_intern(\"===\"), 1, rb_str_new2(\"yellow\"))) {
448
+ var = LONG2NUM(2);
449
+ } else {
450
+ if (rb_funcall(result, rb_intern(\"===\"), 1, rb_str_new2(\"green\"))) {
451
+ var = LONG2NUM(3);
452
+ }
453
+ }
454
+ };
455
+ return result;
456
+ }",
457
+ "RubyToAnsiC" => "str
458
+ case_stmt() {
459
+ str result;
460
+ long var;
461
+ var = 2;
462
+ result = \"\";
463
+ if (case_equal_long(var, 1)) {
464
+ puts(\"something\");
465
+ result = \"red\";
466
+ } else {
467
+ if (case_equal_long(var, 2) || case_equal_long(var, 3)) {
468
+ result = \"yellow\";
469
+ } else {
470
+ if (case_equal_long(var, 4)) {
471
+ ;
472
+ } else {
473
+ result = \"green\";
474
+ }
475
+ }
476
+ };
477
+ if (case_equal_str(result, \"red\")) {
478
+ var = 1;
479
+ } else {
480
+ if (case_equal_str(result, \"yellow\")) {
481
+ var = 2;
482
+ } else {
483
+ if (case_equal_str(result, \"green\")) {
484
+ var = 3;
485
+ }
486
+ }
487
+ };
488
+ return result;
489
+ }",
490
+ },
491
+
492
+ "conditional1" => {
493
+ "Ruby" => "if (42 == 0)\n return 1\n\nend",
494
+ "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]], [:return, [:lit, 1]], nil],
495
+ "Rewriter" => s(:if, s(:call, s(:lit, 42), :==, s(:arglist, s(:lit, 0))), s(:return, s(:lit, 1)), nil),
496
+ "TypeChecker" => t(:if,
497
+ t(:call, t(:lit, 42, Type.long), :==,
498
+ t(:arglist, t(:lit, 0, Type.long)),
499
+ Type.bool),
500
+ t(:return, t(:lit, 1, Type.long), Type.void),
501
+ nil,
502
+ Type.void),
503
+ "CRewriter" => t(:if,
504
+ t(:call, t(:lit, 42, Type.long), :==,
505
+ t(:arglist, t(:lit, 0, Type.long)),
506
+ Type.bool),
507
+ t(:return, t(:lit, 1, Type.long), Type.void),
508
+ nil,
509
+ Type.void),
510
+ "RubyToRubyC" => "if (rb_funcall(LONG2NUM(42), rb_intern(\"==\"), 1, LONG2NUM(0))) {\nreturn LONG2NUM(1);\n}",
511
+ "RubyToAnsiC" => "if (42 == 0) {\nreturn 1;\n}",
512
+ },
513
+
514
+ "conditional2" => {
515
+ "Ruby" => "unless (42 == 0)\n return 2\nend",
516
+ "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]], nil, [:return, [:lit, 2]]],
517
+ "Rewriter" => s(:if,
518
+ s(:call, s(:lit, 42),
519
+ :==, s(:arglist, s(:lit, 0))),
520
+ nil,
521
+ s(:return, s(:lit, 2))),
522
+ "TypeChecker" => t(:if,
523
+ t(:call,
524
+ t(:lit, 42, Type.long),
525
+ :==,
526
+ t(:arglist,
527
+ t(:lit, 0, Type.long)),
528
+ Type.bool),
529
+ nil,
530
+ t(:return, t(:lit, 2, Type.long), Type.void),
531
+ Type.void),
532
+ "CRewriter" => :same,
533
+ "RubyToRubyC" => "if (rb_funcall(LONG2NUM(42), rb_intern(\"==\"), 1, LONG2NUM(0))) {\n;\n} else {\nreturn LONG2NUM(2);\n}",
534
+ "RubyToAnsiC" => "if (42 == 0) {\n;\n} else {\nreturn 2;\n}",
535
+ },
536
+
537
+ "conditional3" => {
538
+ "Ruby" => "if (42 == 0)\n return 3\nelse\n return 4\nend",
539
+ "ParseTree" => [:if, [:call, [:lit, 42], :==, [:array, [:lit, 0]]],
540
+ [:return, [:lit, 3]],
541
+ [:return, [:lit, 4]]],
542
+ "Rewriter" => s(:if,
543
+ s(:call,
544
+ s(:lit, 42),
545
+ :==,
546
+ s(:arglist, s(:lit, 0))),
547
+ s(:return, s(:lit, 3)),
548
+ s(:return, s(:lit, 4))),
549
+ "TypeChecker" => t(:if,
550
+ t(:call,
551
+ t(:lit, 42, Type.long),
552
+ :==,
553
+ t(:arglist,
554
+ t(:lit, 0, Type.long)),
555
+ Type.bool),
556
+ t(:return,
557
+ t(:lit, 3, Type.long),
558
+
559
+ Type.void),
560
+ t(:return,
561
+ t(:lit, 4, Type.long),
562
+ Type.void),
563
+ Type.void),
564
+ "CRewriter" => :same,
565
+ "RubyToRubyC" => "if (rb_funcall(LONG2NUM(42), rb_intern(\"==\"), 1, LONG2NUM(0))) {\nreturn LONG2NUM(3);\n} else {\nreturn LONG2NUM(4);\n}",
566
+ "RubyToAnsiC" => "if (42 == 0) {\nreturn 3;\n} else {\nreturn 4;\n}",
567
+ },
568
+
569
+ "conditional4" => {
570
+ "Ruby" => "if (42 == 0)
571
+ return 2
572
+ else
573
+ if (42 < 0)
574
+ return 3
575
+ else
576
+ return 4
577
+ end
578
+ end",
579
+ "ParseTree" => [:if,
580
+ [:call, [:lit, 42], :==, [:array, [:lit, 0]]],
581
+ [:return, [:lit, 2]],
582
+ [:if,
583
+ [:call, [:lit, 42], :<, [:array, [:lit, 0]]],
584
+ [:return, [:lit, 3]],
585
+ [:return, [:lit, 4]]]],
586
+ "Rewriter" => s(:if,
587
+ s(:call,
588
+ s(:lit, 42),
589
+ :==,
590
+ s(:arglist, s(:lit, 0))),
591
+ s(:return, s(:lit, 2)),
592
+ s(:if,
593
+ s(:call,
594
+ s(:lit, 42),
595
+ :<,
596
+ s(:arglist, s(:lit, 0))),
597
+ s(:return, s(:lit, 3)),
598
+ s(:return, s(:lit, 4)))),
599
+ "TypeChecker" => t(:if,
600
+ t(:call,
601
+ t(:lit, 42, Type.long),
602
+ :==,
603
+ t(:arglist,
604
+ t(:lit, 0, Type.long)),
605
+ Type.bool),
606
+ t(:return,
607
+ t(:lit, 2, Type.long),
608
+ Type.void),
609
+ t(:if,
610
+ t(:call,
611
+ t(:lit, 42, Type.long),
612
+ :<,
613
+ t(:arglist,
614
+ t(:lit, 0, Type.long)),
615
+ Type.bool),
616
+ t(:return,
617
+ t(:lit, 3, Type.long),
618
+ Type.void),
619
+ t(:return,
620
+ t(:lit, 4, Type.long),
621
+ Type.void),
622
+ Type.void),
623
+ Type.void),
624
+ "CRewriter" => :same,
625
+ "RubyToRubyC" => "if (rb_funcall(LONG2NUM(42), rb_intern(\"==\"), 1, LONG2NUM(0))) {\nreturn LONG2NUM(2);\n} else {\nif (rb_funcall(LONG2NUM(42), rb_intern(\"<\"), 1, LONG2NUM(0))) {\nreturn LONG2NUM(3);\n} else {\nreturn LONG2NUM(4);\n}\n}",
626
+ "RubyToAnsiC" => "if (42 == 0) {\nreturn 2;\n} else {\nif (42 < 0) {\nreturn 3;\n} else {\nreturn 4;\n}\n}",
627
+ },
628
+
629
+ "defn_bmethod_added" => {
630
+ "Ruby" => "def bmethod_added(x)\n x + 1\nend",
631
+ "ParseTree" => [:defn, :bmethod_added,
632
+ [:bmethod,
633
+ [:dasgn_curr, :x],
634
+ [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]]],
635
+ "Rewriter" => s(:defn,
636
+ :bmethod_added,
637
+ s(:args, :x),
638
+ s(:scope,
639
+ s(:block,
640
+ s(:call, s(:lvar, :x), :+, s(:arglist, s(:lit, 1)))))),
641
+ "TypeChecker" => :skip,
642
+ "CRewriter" => :skip,
643
+ "RubyToRubyC" => :skip,
644
+ "RubyToAnsiC" => :skip,
645
+ },
646
+
647
+ "defn_empty" => {
648
+ "Ruby" => "def empty()\n nil\nend",
649
+ "ParseTree" => [:defn, :empty, [:scope, [:block, [:args], [:nil]]]],
650
+ "Rewriter" => s(:defn, :empty,
651
+ s(:args), s(:scope, s(:block, s(:nil)))),
652
+ "TypeChecker" => t(:defn, :empty,
653
+ t(:args),
654
+ t(:scope,
655
+ t(:block,
656
+ t(:nil, Type.value),
657
+ Type.unknown),
658
+ Type.void),
659
+ Type.function(Type.unknown, [], Type.void)),
660
+ "CRewriter" => :same,
661
+ "RubyToRubyC" => "static VALUE\nrrc_c_empty(VALUE self) {\nQnil;\n}",
662
+ "RubyToAnsiC" => "void\nempty() {\nNULL;\n}",
663
+ },
664
+
665
+ "defn_zarray" => {
666
+ "Ruby" => "def empty()\n a = []\n return a\nend",
667
+ "ParseTree" => [:defn, :empty, [:scope, [:block, [:args], [:lasgn, :a, [:zarray]], [:return, [:lvar, :a]]]]],
668
+ "Rewriter" => s(:defn,
669
+ :empty,
670
+ s(:args),
671
+ s(:scope, s(:block, s(:lasgn, :a, s(:array)), s(:return, s(:lvar, :a))))),
672
+ "TypeChecker" => t(:defn,
673
+ :empty,
674
+ t(:args),
675
+ t(:scope,
676
+ t(:block,
677
+ t(:lasgn, :a, t(:array), Type.unknown_list),
678
+ t(:return,
679
+ t(:lvar,
680
+ :a, Type.unknown_list), Type.void),
681
+ Type.unknown), Type.void),
682
+ Type.function(Type.unknown, [], Type.unknown_list)),
683
+ "CRewriter" => :same,
684
+ "RubyToRubyC" => "static VALUE\nrrc_c_empty(VALUE self) {\nVALUE a;\na = rb_ary_new2(0);\nreturn a;\n}",
685
+ "RubyToAnsiC" => "void *\nempty() {\nvoid * a;\na = (void *) malloc(sizeof(void *) * 0);\nreturn a;\n}",
686
+ },
687
+
688
+ "defn_or" => {
689
+ "Ruby" => "def |()\n nil\nend",
690
+ "ParseTree" => [:defn, :|, [:scope, [:block, [:args], [:nil]]]],
691
+ "Rewriter" => s(:defn, :|,
692
+ s(:args), s(:scope, s(:block, s(:nil)))),
693
+ "TypeChecker" => t(:defn, :|,
694
+ t(:args),
695
+ t(:scope,
696
+ t(:block,
697
+ t(:nil, Type.value),
698
+ Type.unknown),
699
+ Type.void),
700
+ Type.function(Type.unknown, [], Type.void)),
701
+ "CRewriter" => :same,
702
+ "RubyToRubyC" => "static VALUE\nrrc_c_or(VALUE self) {\nQnil;\n}",
703
+ "RubyToAnsiC" => "void\nor() {\nNULL;\n}",
704
+ },
705
+
706
+ "defn_is_something" => {
707
+ "Ruby" => "def something?()\n nil\nend",
708
+ "ParseTree" => [:defn, :something?, [:scope, [:block, [:args], [:nil]]]],
709
+ "Rewriter" => s(:defn, :something?,
710
+ s(:args), s(:scope, s(:block, s(:nil)))),
711
+ "TypeChecker" => t(:defn, :something?,
712
+ t(:args),
713
+ t(:scope,
714
+ t(:block,
715
+ t(:nil, Type.value),
716
+ Type.unknown),
717
+ Type.void),
718
+ Type.function(Type.unknown, [], Type.void)),
719
+ "CRewriter" => :same,
720
+ "RubyToRubyC" => "static VALUE\nrrc_c_is_something(VALUE self) {\nQnil;\n}",
721
+ "RubyToAnsiC" => "void\nis_something() {\nNULL;\n}",
722
+ },
723
+
724
+ "defn_fbody" => {
725
+ "Ruby" => "def aliased()\n puts(42)\nend",
726
+ "ParseTree" => [:defn, :aliased,
727
+ [:fbody,
728
+ [:scope,
729
+ [:block,
730
+ [:args],
731
+ [:fcall, :puts, [:array, [:lit, 42]]]]]]],
732
+ "Rewriter" => s(:defn, :aliased,
733
+ s(:args),
734
+ s(:scope,
735
+ s(:block,
736
+ s(:call, nil, :puts, s(:arglist, s(:lit, 42)))))),
737
+ "TypeChecker" => :skip,
738
+ "CRewriter" => :skip,
739
+ "RubyToRubyC" => :skip,
740
+ "RubyToAnsiC" => :skip,
741
+ },
742
+
743
+ "defn_optargs" => {
744
+ "Ruby" => "def x(a, *args)\n p(a, args)\nend",
745
+ "ParseTree" => [:defn, :x,
746
+ [:scope,
747
+ [:block,
748
+ [:args, :a, :"*args"],
749
+ [:fcall, :p,
750
+ [:array, [:lvar, :a], [:lvar, :args]]]]]],
751
+ "Rewriter" => s(:defn, :x,
752
+ s(:args, :a, :"*args"),
753
+ s(:scope,
754
+ s(:block,
755
+ s(:call, nil, :p,
756
+ s(:arglist, s(:lvar, :a), s(:lvar, :args)))))),
757
+ "TypeChecker" => :skip,
758
+ "CRewriter" => :skip,
759
+ "RubyToRubyC" => :skip,
760
+ "RubyToAnsiC" => :skip,
761
+ },
762
+
763
+ "dmethod_added" => {
764
+ "Ruby" => "def dmethod_added\n define_method(:bmethod_added)\n x {|(x + 1)|\n }end",
765
+ "ParseTree" => [:defn,
766
+ :dmethod_added,
767
+ [:dmethod,
768
+ :bmethod_maker,
769
+ [:scope,
770
+ [:block,
771
+ [:args],
772
+ [:iter,
773
+ [:fcall, :define_method, [:array, [:lit, :bmethod_added]]],
774
+ [:dasgn_curr, :x],
775
+ [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]]]]]],
776
+ "Rewriter" => s(:defn,
777
+ :dmethod_added,
778
+ s(:args, :x),
779
+ s(:scope,
780
+ s(:block,
781
+ s(:call, s(:lvar, :x), :+,
782
+ s(:arglist, s(:lit, 1)))))),
783
+ "TypeChecker" => :skip,
784
+ "CRewriter" => :skip,
785
+ "RubyToRubyC" => :skip,
786
+ "RubyToAnsiC" => :skip,
787
+ },
788
+
789
+ "global" => {
790
+ "Ruby" => "$stderr",
791
+ "ParseTree" => [:gvar, :$stderr],
792
+ "Rewriter" => s(:gvar, :$stderr),
793
+ # TODO: test s(:gvar, :$stderr) != t(:gvar, $stderr, Type.file)
794
+ "TypeChecker" => t(:gvar, :$stderr, Type.file),
795
+ "CRewriter" => :same,
796
+ "RubyToRubyC" => "rb_gv_get(\"$stderr\")",
797
+ "RubyToAnsiC" => "stderr",
798
+ },
799
+
800
+ "interpolated" => {
801
+ "Ruby" => "\"var is \#{argl}. So there.\"",
802
+ "ParseTree" => [:dstr,
803
+ "var is ", [:lvar, :argl], [:str, ". So there."]],
804
+ "Rewriter" => s(:dstr,
805
+ "var is ", s(:lvar, :argl), s(:str, ". So there.")),
806
+ "TypeChecker" => t(:dstr,
807
+ "var is ",
808
+ t(:lvar, :argl, Type.long),
809
+ t(:str, ". So there.", Type.str),
810
+ Type.str),
811
+ "CRewriter" => :same,
812
+ "RubyToRubyC" => "rb_funcall(rb_mKernel, rb_intern(\"sprintf\"), 4, rb_str_new2(\"%s%s%s\"), rb_str_new2(\"var is \"), argl, rb_str_new2(\". So there.\"))",
813
+ "RubyToAnsiC" => :unsupported,
814
+ },
815
+
816
+ "iter" => {
817
+ "Ruby" => "loop do end",
818
+ "ParseTree" => [:iter, [:fcall, :loop], nil],
819
+ "Rewriter" => s(:iter,
820
+ s(:call, nil, :loop, nil),
821
+ s(:dasgn_curr, :temp_1),
822
+ nil),
823
+ "TypeChecker" => t(:iter,
824
+ t(:call, nil, :loop, nil, Type.unknown),
825
+ t(:dasgn_curr, :temp_1, Type.unknown),
826
+ nil,
827
+ Type.unknown),
828
+ "CRewriter" => [:defx,
829
+ t(:iter,
830
+ t(:call, nil, :loop, nil, Type.unknown),
831
+ t(:args,
832
+ t(:array, t(:dasgn_curr, :temp_1, Type.unknown), Type.void),
833
+ t(:array, Type.void), Type.void),
834
+ t(:call, nil,
835
+ :temp_2,
836
+ s(:arglist, s(:dasgn_curr, :temp_1, Type.unknown),
837
+ t(:nil)))),
838
+ [t(:defx,
839
+ :temp_2,
840
+ t(:args, :temp_2, :temp_3),
841
+ t(:scope, t(:block, nil)), Type.void)]],
842
+ "RubyToRubyC" => "",
843
+ "RubyToAnsiC" => "",
844
+ },
845
+
846
+ "iteration2" => {
847
+ "ParseTree" => [:iter,
848
+ [:call, [:lvar, :arrays], :each],
849
+ [:dasgn_curr, :x],
850
+ [:fcall, :puts, [:arrays, [:dvar, :x]]]],
851
+ "Rewriter" => s(:iter,
852
+ s(:call, s(:lvar, :arrays), :each, nil),
853
+ s(:dasgn_curr, :x),
854
+ s(:call, nil, :puts, s(:arglist, s(:dvar, :x)))),
855
+ "TypeChecker" => t(:iter,
856
+ t(:call,
857
+ t(:lvar, :arrays, Type.str_list),
858
+ :each,
859
+ nil, Type.unknown),
860
+ t(:dasgn_curr, :x, Type.str),
861
+ t(:call, nil, :puts,
862
+ t(:arglist, t(:dvar, :x, Type.str)),
863
+ Type.void),
864
+ Type.void),
865
+ "CRewriter" => [:defx,
866
+ t(:iter,
867
+ t(:call,
868
+ t(:lvar, :arrays, Type.str_list),
869
+ :each,
870
+ nil, Type.unknown),
871
+ t(:args,
872
+ t(:array, t(:dasgn_curr, :x, Type.str), Type.void),
873
+ t(:array, t(:lvar, :arrays, Type.value), Type.void), Type.void),
874
+ t(:call, nil, :temp_1, t(:arglist, t(:dasgn_curr, :x, Type.str), t(:nil)))),
875
+ [t(:defx,
876
+ :temp_1,
877
+ t(:args, :temp_2, :temp_3),
878
+ t(:scope,
879
+ t(:block,
880
+ t(:call,
881
+ nil,
882
+ :puts,
883
+ t(:arglist, t(:dvar, :x, Type.str)), Type.void))), Type.void)]],
884
+ "RubyToRubyC" => 'unsigned long index_temp_1;
885
+ VALUE temp_2 = rb_funcall(arrays, rb_intern("to_a"), 0);
886
+ unsigned long temp_1_max = FIX2LONG(rb_funcall(temp_2, rb_intern("size"), 0));
887
+ for (index_temp_1 = 0; index_temp_1 < temp_1_max; ++index_temp_1) {
888
+ VALUE x;
889
+ x = rb_funcall(temp_2, rb_intern("at"), 1, LONG2FIX(index_temp_1));
890
+ rb_funcall(self, rb_intern("puts"), 1, x);
891
+ }",
892
+ "RubyToAnsiC" => "unsigned long index_x;
893
+ for (index_x = 0; arrays[index_x] != NULL; ++index_x) {
894
+ str x = arrays[index_x];
895
+ puts(x);
896
+ }',
897
+ },
898
+
899
+
900
+ "iteration4" => {
901
+ "Ruby" => "1.upto(3) {|n|\n puts(n.to_s)\n}",
902
+ "ParseTree" => [:iter,
903
+ [:call, [:lit, 1], :upto, [:array, [:lit, 3]]],
904
+ [:dasgn_curr, :n],
905
+ [:fcall, :puts, [:array, [:call, [:dvar, :n], :to_s]]]],
906
+ "Rewriter" => s(:dummy,
907
+ s(:lasgn, :n, s(:lit, 1)),
908
+ s(:while,
909
+ s(:call, s(:lvar, :n), :<=, s(:arglist, s(:lit, 3))),
910
+ s(:block,
911
+ s(:call,
912
+ nil,
913
+ :puts,
914
+ s(:arglist, s(:call, s(:lvar, :n), :to_s, nil))),
915
+ s(:lasgn, :n,
916
+ s(:call, s(:lvar, :n),
917
+ :+,
918
+ s(:arglist, s(:lit, 1))))), true)),
919
+ "TypeChecker" => t(:dummy, t(:lasgn, :n, t(:lit, 1, Type.long), Type.long),
920
+ t(:while,
921
+ t(:call,
922
+ t(:lvar, :n, Type.long),
923
+ :<=,
924
+ t(:arglist, t(:lit, 3, Type.long)), Type.bool),
925
+ t(:block,
926
+ t(:call, nil, :puts,
927
+ t(:arglist,
928
+ t(:call,
929
+ t(:lvar, :n, Type.long),
930
+ :to_s,
931
+ nil, Type.str)), Type.void),
932
+ t(:lasgn, :n,
933
+ t(:call,
934
+ t(:lvar, :n, Type.long),
935
+ :+,
936
+ t(:arglist,
937
+ t(:lit,
938
+ 1, Type.long)),
939
+ Type.long), Type.long), Type.unknown), true)),
940
+ "CRewriter" => :same,
941
+ "RubyToRubyC" => '',
942
+ "RubyToAnsiC" => 'n = 1;
943
+ while (n <= 3) {
944
+ puts(to_s(n));
945
+ n = n + 1;
946
+ }',
947
+ },
948
+
949
+ "iteration5" => {
950
+ "Ruby" => "3.downto(1) {|n|\n puts(n.to_s)\n}",
951
+ "ParseTree" => [:iter,
952
+ [:call, [:lit, 3], :downto, [:array, [:lit, 1]]],
953
+ [:dasgn_curr, :n],
954
+ [:fcall, :puts, [:array, [:call, [:dvar, :n], :to_s]]]],
955
+ "Rewriter" => s(:dummy, s(:lasgn, :n, s(:lit, 3)), s(:while,
956
+ s(:call, s(:lvar, :n), :>=, s(:arglist, s(:lit, 1))),
957
+ s(:block,
958
+ s(:call, nil, :puts,
959
+ s(:arglist, s(:call, s(:lvar, :n), :to_s, nil))),
960
+ s(:lasgn, :n, s(:call, s(:lvar, :n),
961
+ :-, s(:arglist, s(:lit, 1))))), true)),
962
+ "TypeChecker" => t(:dummy,
963
+ t(:lasgn, :n, t(:lit, 3, Type.long), Type.long),
964
+ t(:while,
965
+ t(:call,
966
+ t(:lvar, :n, Type.long),
967
+ :>=,
968
+ t(:arglist, t(:lit, 1, Type.long)), Type.bool),
969
+ t(:block,
970
+ t(:call, nil, :puts,
971
+ t(:arglist,
972
+ t(:call,
973
+ t(:lvar, :n, Type.long),
974
+ :to_s,
975
+ nil, Type.str)), Type.void),
976
+ t(:lasgn, :n,
977
+ t(:call,
978
+ t(:lvar, :n, Type.long),
979
+ :-,
980
+ t(:arglist, t(:lit, 1, Type.long)),
981
+ Type.long),
982
+ Type.long),
983
+ Type.unknown), true)),
984
+ "CRewriter" => :same,
985
+ "RubyToRubyC" => '',
986
+ "RubyToAnsiC" => 'n = 3;
987
+ while (n >= 1) {
988
+ puts(to_s(n));
989
+ n = n - 1;
990
+ }',
991
+ },
992
+
993
+ "iteration6" => {
994
+ "Ruby" => "while ((argl >= (1))) do\nputs((\"hello\"))\nargl = (argl - (1))\n\nend",
995
+ "ParseTree" => [:while, [:call, [:lvar, :argl],
996
+ :>=, [:arglist, [:lit, 1]]], [:block,
997
+ [:call, nil, :puts, [:arglist, [:str, "hello"]]],
998
+ [:lasgn,
999
+ :argl,
1000
+ [:call, [:lvar, :argl],
1001
+ :-, [:arglist, [:lit, 1]]]]], true],
1002
+ "Rewriter" => s(:while,
1003
+ s(:call, s(:lvar, :argl),
1004
+ :>=, s(:arglist, s(:lit, 1))),
1005
+ s(:block,
1006
+ s(:call, nil, :puts, s(:arglist, s(:str, "hello"))),
1007
+ s(:lasgn,
1008
+ :argl,
1009
+ s(:call, s(:lvar, :argl),
1010
+ :-, s(:arglist, s(:lit, 1))))), true),
1011
+ "TypeChecker" => t(:while,
1012
+ t(:call, t(:lvar, :argl, Type.long),
1013
+ :>=,
1014
+ t(:arglist, t(:lit, 1, Type.long)), Type.bool),
1015
+ t(:block,
1016
+ t(:call, nil, :puts,
1017
+ t(:arglist, t(:str, "hello", Type.str)),
1018
+ Type.void),
1019
+ t(:lasgn,
1020
+ :argl,
1021
+ t(:call, t(:lvar, :argl, Type.long),
1022
+ :-,
1023
+ t(:arglist, t(:lit, 1, Type.long)), Type.long),
1024
+ Type.long),
1025
+ Type.unknown), true),
1026
+ "CRewriter" => :same,
1027
+ "RubyToRubyC" => '',
1028
+ "RubyToAnsiC" => 'while (argl >= 1) {
1029
+ puts("hello");
1030
+ argl = argl - 1;
1031
+ }',
1032
+ },
1033
+
1034
+ # TODO: this might still be too much
1035
+ "lasgn_call" => {
1036
+ "Ruby" => "c = 2 + 3",
1037
+ "ParseTree" => [:lasgn, :c, [:call, [:lit, 2], :+, [:arglist, [:lit, 3]]]],
1038
+ "Rewriter" => s(:lasgn, :c, s(:call, s(:lit, 2), :+, s(:arglist, s(:lit, 3)))),
1039
+ "TypeChecker" => t(:lasgn, :c,
1040
+ t(:call,
1041
+ t(:lit, 2, Type.long),
1042
+ :+,
1043
+ t(:arglist,
1044
+ t(:lit, 3, Type.long)),
1045
+ Type.long),
1046
+ Type.long),
1047
+ "CRewriter" => :same,
1048
+ "RubyToRubyC" => 'c = rb_funcall(LONG2NUM(2), rb_intern("+"), 1, LONG2NUM(3))', # FIX: probably not "c ="
1049
+ "RubyToAnsiC" => "c = 2 + 3",
1050
+ },
1051
+
1052
+ "lasgn_array" => {
1053
+ "Ruby" => "var = [\"foo\", \"bar\"]",
1054
+ "ParseTree" => [:lasgn, :var, [:array,
1055
+ [:str, "foo"],
1056
+ [:str, "bar"]]],
1057
+ "Rewriter" => s(:lasgn, :var, s(:array,
1058
+ s(:str, "foo"),
1059
+ s(:str, "bar"))),
1060
+ "TypeChecker" => t(:lasgn,
1061
+ :var,
1062
+ t(:array,
1063
+ t(:str, "foo", Type.str),
1064
+ t(:str, "bar", Type.str)),
1065
+ Type.str_list),
1066
+ "CRewriter" => :same,
1067
+ "RubyToRubyC" => 'var = rb_ary_new2(2);
1068
+ rb_ary_store(var, 0, rb_str_new2("foo"));
1069
+ rb_ary_store(var, 1, rb_str_new2("bar"))',
1070
+ "RubyToAnsiC" => 'var = (str) malloc(sizeof(str) * 2);
1071
+ var[0] = "foo";
1072
+ var[1] = "bar"'
1073
+ },
1074
+
1075
+ "lit_bool_false" => {
1076
+ "Ruby" => "false",
1077
+ "ParseTree" => [:false],
1078
+ "Rewriter" => s(:false),
1079
+ "TypeChecker" => t(:false, Type.bool),
1080
+ "CRewriter" => :same,
1081
+ "RubyToRubyC" => "Qfalse",
1082
+ "RubyToAnsiC" => "0",
1083
+ },
1084
+
1085
+ "lit_bool_true" => {
1086
+ "Ruby" => "true",
1087
+ "ParseTree" => [:true],
1088
+ "Rewriter" => s(:true),
1089
+ "TypeChecker" => t(:true, Type.bool),
1090
+ "CRewriter" => :same,
1091
+ "RubyToRubyC" => "Qtrue",
1092
+ "RubyToAnsiC" => "1",
1093
+ },
1094
+
1095
+ "lit_float" => {
1096
+ "Ruby" => "1.1",
1097
+ "ParseTree" => [:lit, 1.1],
1098
+ "Rewriter" => s(:lit, 1.1),
1099
+ "TypeChecker" => t(:lit, 1.1, Type.float),
1100
+ "CRewriter" => :same,
1101
+ "RubyToRubyC" => "rb_float_new(1.1)",
1102
+ "RubyToAnsiC" => "1.1",
1103
+ },
1104
+
1105
+ "lit_long" => {
1106
+ "Ruby" => "1",
1107
+ "ParseTree" => [:lit, 1],
1108
+ "Rewriter" => s(:lit, 1),
1109
+ "TypeChecker" => t(:lit, 1, Type.long),
1110
+ "CRewriter" => :same,
1111
+ "RubyToRubyC" => "LONG2NUM(1)",
1112
+ "RubyToAnsiC" => "1",
1113
+ },
1114
+
1115
+ "lit_sym" => {
1116
+ "Ruby" => ":x",
1117
+ "ParseTree" => [:lit, :x],
1118
+ "Rewriter" => s(:lit, :x),
1119
+ "TypeChecker" => t(:lit, :x, Type.symbol),
1120
+ "CRewriter" => :same,
1121
+ "RubyToRubyC" => 'ID2SYM(rb_intern("x"))',
1122
+ "RubyToAnsiC" => '"x"', # HACK WRONG! (or... is it?)
1123
+ },
1124
+
1125
+ "lit_str" => {
1126
+ "Ruby" => "\"x\"",
1127
+ "ParseTree" => [:str, "x"],
1128
+ "Rewriter" => s(:str, "x"),
1129
+ "TypeChecker" => t(:str, "x", Type.str),
1130
+ "CRewriter" => :same,
1131
+ "RubyToRubyC" => 'rb_str_new2("x")',
1132
+ "RubyToAnsiC" => '"x"',
1133
+ },
1134
+
1135
+ "multi_args" => {
1136
+ "Ruby" => "def multi_args(arg1, arg2)\n arg3 = ((arg1 * arg2) * 7)\n puts(arg3.to_s)\n return \"foo\"\nend",
1137
+ "ParseTree" => [:defn, :multi_args,
1138
+ [:scope,
1139
+ [:block,
1140
+ [:args, :arg1, :arg2],
1141
+ [:lasgn,
1142
+ :arg3,
1143
+ [:call,
1144
+ [:call, [:lvar, :arg1], :*, [:array, [:lvar, :arg2]]],
1145
+ :*,
1146
+ [:array, [:lit, 7]]]],
1147
+ [:fcall, :puts, [:array, [:call, [:lvar, :arg3], :to_s]]],
1148
+ [:return, [:str, "foo"]]]]],
1149
+ "Rewriter" => s(:defn, :multi_args,
1150
+ s(:args, :arg1, :arg2),
1151
+ s(:scope,
1152
+ s(:block,
1153
+ s(:lasgn, :arg3,
1154
+ s(:call,
1155
+ s(:call,
1156
+ s(:lvar, :arg1),
1157
+ :*,
1158
+ s(:arglist, s(:lvar, :arg2))),
1159
+ :*,
1160
+ s(:arglist, s(:lit, 7)))),
1161
+ s(:call,
1162
+ nil,
1163
+ :puts,
1164
+ s(:arglist,
1165
+ s(:call,
1166
+ s(:lvar, :arg3),
1167
+ :to_s,
1168
+ nil))),
1169
+ s(:return, s(:str, "foo"))))),
1170
+ "TypeChecker" => t(:defn, :multi_args,
1171
+ t(:args,
1172
+ t(:arg1, Type.long),
1173
+ t(:arg2, Type.long)),
1174
+ t(:scope,
1175
+ t(:block,
1176
+ t(:lasgn,
1177
+ :arg3,
1178
+ t(:call,
1179
+ t(:call,
1180
+ t(:lvar, :arg1, Type.long),
1181
+ :*,
1182
+ t(:arglist,
1183
+ t(:lvar,
1184
+ :arg2,
1185
+ Type.long)),
1186
+ Type.long),
1187
+ :*,
1188
+ t(:arglist,
1189
+ t(:lit, 7, Type.long)),
1190
+ Type.long),
1191
+ Type.long),
1192
+ t(:call,
1193
+ nil,
1194
+ :puts,
1195
+ t(:arglist,
1196
+ t(:call,
1197
+ t(:lvar, :arg3, Type.long),
1198
+ :to_s,
1199
+ nil,
1200
+ Type.str)),
1201
+ Type.void),
1202
+ t(:return, t(:str, "foo", Type.str),
1203
+ Type.void),
1204
+ Type.unknown),
1205
+ Type.void),
1206
+ Type.function(Type.unknown,
1207
+ [Type.long, Type.long], Type.str)),
1208
+ "CRewriter" => :same,
1209
+ "RubyToRubyC" => "static VALUE
1210
+ rrc_c_multi_args(VALUE self, VALUE arg1, VALUE arg2) {
1211
+ VALUE arg3;
1212
+ arg3 = rb_funcall(rb_funcall(arg1, rb_intern(\"*\"), 1, arg2), rb_intern(\"*\"), 1, LONG2NUM(7));
1213
+ rb_funcall(self, rb_intern(\"puts\"), 1, rb_funcall(arg3, rb_intern(\"to_s\"), 0));
1214
+ return rb_str_new2(\"foo\");
1215
+ }",
1216
+ "RubyToAnsiC" => "str
1217
+ multi_args(long arg1, long arg2) {
1218
+ long arg3;
1219
+ arg3 = arg1 * arg2 * 7;
1220
+ puts(to_s(arg3));
1221
+ return \"foo\";
1222
+ }",
1223
+ },
1224
+
1225
+ "vcall" => {
1226
+ "Ruby" => "method",
1227
+ "ParseTree" => [:vcall, :method],
1228
+ "Rewriter" => s(:call, nil, :method, nil),
1229
+ "TypeChecker" => t(:call, nil, :method, nil, Type.unknown),
1230
+ "CRewriter" => :same,
1231
+ "RubyToRubyC" => "rb_funcall(self, rb_intern(\"method\"), 0)",
1232
+ "RubyToAnsiC" => "method()",
1233
+ },
1234
+
1235
+ "whiles" => {
1236
+ "Ruby" => "def whiles()\n while (false) do\n puts(\"false\")\n end\n begin\n puts(\"true\")\n end while (false)\nend",
1237
+ "ParseTree" => [:defn,
1238
+ :whiles,
1239
+ [:scope,
1240
+ [:block,
1241
+ [:args],
1242
+ [:while, [:false],
1243
+ [:fcall, :puts, [:array, [:str, "false"]]], true],
1244
+ [:while, [:false],
1245
+ [:fcall, :puts, [:array, [:str, "true"]]], false]]]],
1246
+ "Rewriter" => s(:defn,
1247
+ :whiles,
1248
+ s(:args),
1249
+ s(:scope,
1250
+ s(:block,
1251
+ s(:while,
1252
+ s(:false),
1253
+ s(:call, nil, :puts, s(:arglist, s(:str, "false"))),
1254
+ true),
1255
+ s(:while,
1256
+ s(:false),
1257
+ s(:call, nil, :puts, s(:arglist, s(:str, "true"))),
1258
+ false)))),
1259
+ "TypeChecker" => t(:defn,
1260
+ :whiles,
1261
+ t(:args),
1262
+ t(:scope,
1263
+ t(:block,
1264
+ t(:while,
1265
+ t(:false, Type.bool),
1266
+ t(:call,
1267
+ nil,
1268
+ :puts,
1269
+ t(:arglist, t(:str, "false", Type.str)), Type.void),
1270
+ true),
1271
+ t(:while,
1272
+ t(:false, Type.bool),
1273
+ t(:call,
1274
+ nil,
1275
+ :puts,
1276
+ t(:arglist, t(:str, "true", Type.str)), Type.void),
1277
+ false),
1278
+ Type.unknown),
1279
+ Type.void),
1280
+ Type.function(Type.unknown, [], Type.void)),
1281
+ "CRewriter" => :same,
1282
+ "RubyToRubyC" => "static VALUE
1283
+ rrc_c_whiles(VALUE self) {
1284
+ while (Qfalse) {
1285
+ rb_funcall(self, rb_intern(\"puts\"), 1, rb_str_new2(\"false\"));
1286
+ };
1287
+ {
1288
+ rb_funcall(self, rb_intern(\"puts\"), 1, rb_str_new2(\"true\"));
1289
+ } while (Qfalse);
1290
+ }",
1291
+ "RubyToAnsiC" => "void
1292
+ whiles() {
1293
+ while (0) {
1294
+ puts(\"false\");
1295
+ };
1296
+ {
1297
+ puts(\"true\");
1298
+ } while (0);
1299
+ }",
1300
+ },
1301
+
1302
+ "zarray" => {
1303
+ "Ruby" => "a = []",
1304
+ "ParseTree" => [:lasgn, :a, [:zarray]],
1305
+ "Rewriter" => s(:lasgn, :a, s(:array)),
1306
+ "TypeChecker" => t(:lasgn, :a, t(:array), Type.unknown_list),
1307
+ "CRewriter" => :same,
1308
+ # TODO: need to verify that our variable decl will be correct
1309
+ "RubyToRubyC" => "a = rb_ary_new2(0)",
1310
+ "RubyToAnsiC" => "a = (void *) malloc(sizeof(void *) * 0)",
1311
+ },
1312
+ }
1313
+
1314
+ def self.previous(key)
1315
+ idx = @@testcase_order.index(key)-1
1316
+ case key
1317
+ when "RubyToRubyC" then
1318
+ idx -= 1
1319
+ end
1320
+ @@testcase_order[idx]
1321
+ end
1322
+
1323
+ # lets us used unprocessed :self outside of tests, called when subclassed
1324
+ def self.clone_same
1325
+ @@testcases.each do |node, data|
1326
+ data.each do |key, val|
1327
+ if val == :same then
1328
+ prev_key = self.previous(key)
1329
+ data[key] = data[prev_key].deep_clone
1330
+ end
1331
+ end
1332
+ end
1333
+ end
1334
+
1335
+ def self.inherited(c)
1336
+ self.clone_same
1337
+
1338
+ output_name = c.name.to_s.sub(/^Test/, '')
1339
+ raise "Unknown class #{c}" unless @@testcase_order.include? output_name
1340
+
1341
+ input_name = self.previous(output_name)
1342
+
1343
+ @@testcases.each do |node, data|
1344
+ next if data[input_name] == :skip
1345
+ next if data[output_name] == :skip
1346
+
1347
+ c.send(:define_method, "test_#{node}".intern) do
1348
+ flunk "Processor is nil" if processor.nil?
1349
+ assert data.has_key?(input_name), "Unknown input data"
1350
+ assert data.has_key?(output_name), "Unknown expected data"
1351
+ input = data[input_name].deep_clone
1352
+ expected = data[output_name].deep_clone
1353
+
1354
+ case expected
1355
+ when :unsupported then
1356
+ assert_raises(UnsupportedNodeError) do
1357
+ processor.process(input)
1358
+ end
1359
+ else
1360
+ extra_expected = []
1361
+ extra_input = []
1362
+ _, expected, extra_expected = *expected if Array === expected and expected.first == :defx
1363
+ _, input, extra_input = *input if Array === input and input.first == :defx
1364
+
1365
+ assert_equal expected, processor.process(input)
1366
+ extra_input.each do |input| processor.process(input) end
1367
+ extra = processor.extra_methods rescue []
1368
+ assert_equal extra_expected, extra
1369
+ end
1370
+ end
1371
+ end
1372
+ end
1373
+
1374
+ def test_stoopid
1375
+ # do nothing - shuts up empty test class requirement
1376
+ end
1377
+
1378
+ end