RubyToC 1.0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,69 @@
1
+ *** 1.0.0-beta-4 / 2005-07-13
2
+
3
+ + 1 minor enhancements
4
+ + Added gemspec (hastily).
5
+ + 2 bug fixes
6
+ + Translates bool type to VALUE since we were using Qtrue/Qfalse.
7
+ + Fixed rubygems for non-gem systems.
8
+
9
+ *** 1.0.0-beta-3 / 2005-06-08
10
+
11
+ + 16 minor enhancements
12
+ + Added ivar and iasgn support. Needs more work.
13
+ + Added limited support for self.
14
+ + Added pipeline tests for bools, call_arglist, call_attrasgn, fbody.
15
+ + Added process_not to RubyToC.
16
+ + Added support for float and symbol literals.
17
+ + Added support for gasgn, cvasgn, const (class consts, not classes).
18
+ + Improved error handling/reporting, esp in RubyToC.
19
+ + In TypeChecker.boostrap, pre-registered all base classes.
20
+ + Modified process_class test to include a class const.
21
+ + Processing :class now adds class constants to the local var scope.
22
+ + Processing :const checks both genv and env now.
23
+ + Rearchitected all tests into a pipeline test class.
24
+ + Rewrite attrasgn into regular calls.
25
+ + Rewrite fbody into a regular defn.
26
+ + Rewrote :array inside call to :arglist.
27
+ + Rewrote :or nodes in process_case to correctly be binary.
28
+ + 1 bug fix:
29
+ + Fixed a bug where single line while bodies were missing a semicolon.
30
+
31
+ *** 1.0.0-beta-2 / 2005-02-15
32
+
33
+ + 1 minor enhancement
34
+ + Added post-condition while/until support and tests.
35
+ + 4 bug fixes
36
+ + Fixed bug:1422: Escape newlines to prevent multi-line strings in C.
37
+ + Fixed bug:1429: Arrays of strings are not being properly.
38
+ + Fixed bug:1447/1448: Readme file's website and added ParseTree dependency.
39
+
40
+ *** 1.0.0-beta-1 / 2005-02-01
41
+
42
+ + 1 major enhancements
43
+ + Hit 80% non-error conversion threshold for public beta release.
44
+ + 3 minor enhancements
45
+ + (Mostly) Filled out functionality in Rewriter and TypeChecker.
46
+ + Flushed out what we don't do in RubyToC.
47
+ + Wrote a ton of rdoc
48
+
49
+ *** 1.0.0-a2 / 2004-12-31
50
+
51
+ + 7 major enhancements
52
+ + Alpha 2 released to private group for critique.
53
+ + Refactored and split out ParseTree package.
54
+ + Gemified dependency on ParseTree.
55
+ + Added iter rewriting
56
+ + Added post type inference rewriting specific to C library.
57
+ + Massive increase to the base we can translate.
58
+ + We have stabilized the architecture but still have a ways to go.
59
+ + 2 minor enhancements
60
+ + Added propaganda (presentations).
61
+ + Much better test coverage, now with ZenTest compliant naming.
62
+ + 2+ bug fixes
63
+ + Gem-proofed makefile.
64
+ + Tons of little fixes we didn't bother to track.
65
+
66
+ *** 1.0.0-a1 / 2004-09-24
67
+
68
+ + 1 major enhancement
69
+ + Birthday! Alpha 1 released to private group for critique.
data/Makefile ADDED
@@ -0,0 +1,49 @@
1
+ RUBY?=ruby
2
+ RUBY_FLAGS?=-w -I.:../../ParseTree/dev/lib:../../ParseTree/dev/test:../../RubyInline/dev
3
+ TEST?=
4
+
5
+ all test:
6
+ $(RUBY) $(RUBY_FLAGS) test_all.rb $(TEST)
7
+
8
+ docs:
9
+ rdoc -d -I png --main RubyToC -x test_\* -x something.rb
10
+
11
+ VAL=./validate.sh
12
+ FILE?=../../ZenTest/dev/TestOrderedHash.rb
13
+
14
+ valx:
15
+ $(VAL) $(FILE) > x
16
+
17
+ val:
18
+ $(VAL) -q $(FILE) | head -20
19
+
20
+ valno:
21
+ $(VAL) $(FILE) | grep no:
22
+
23
+ valstat:
24
+ BAD=$$(wc -l rb.bad.txt | perl -pe 's/\s*(\d+)\s+.*/$$1/'); GOOD=$$(wc -l rb.good.txt | perl -pe 's/\s*(\d+)\s+.*/$$1/'); echo "1 - $$BAD / ($$GOOD + $$BAD)" | bc -l
25
+
26
+ valoccur:
27
+ egrep "ERROR|no:" rb.err.txt | perl -pe 's/ in .*//; s/(translating \S+):/$$1/; s/(is not an Array \w+):.*/$$1/; s/.* (is not a supported node type)/blah $$1/; s/(Unable to unify).*/$$1/; s/(Unknown literal) \S+/$$1/;' | occur
28
+
29
+ trouble: trouble.o
30
+ @exit 0
31
+
32
+ trouble.o: trouble.c
33
+ gcc -I/usr/local/lib/ruby/1.8/powerpc-darwin/ -c trouble.c -o trouble.o
34
+
35
+ trouble.c: zcomparable.rb translate.rb ruby_to_c.rb type_checker.rb
36
+ $(RUBY) $(RUBY_FLAGS) translate.rb zcomparable.rb > trouble.c
37
+
38
+ FORCE:
39
+ demos: FORCE
40
+ for rf in demo/*.rb; do f=$$(basename $$rf .rb); echo $$f; ./translate.rb demo/$$f > demo/$$f.c && gcc -Iinc -o demo/$$f demo/$$f.c; done
41
+
42
+ interp: FORCE
43
+ for rf in demo/*.rb; do f=$$(basename $$rf .rb); echo $$f; ./interp.rb demo/$$f; done
44
+
45
+ clean:
46
+ rm -f *~ trouble.* diff.txt demo/*~
47
+ rm -rf ~/.ruby_inline
48
+ for rf in demo/*.rb; do f=$$(basename $$rf .rb); rm -f demo/$$f.c demo/$$f; done
49
+
data/Manifest.txt ADDED
@@ -0,0 +1,98 @@
1
+ History.txt
2
+ Makefile
3
+ Manifest.txt
4
+ README.txt
5
+ demo/char.rb
6
+ demo/factorial.rb
7
+ demo/hello.rb
8
+ demo/misc.rb
9
+ demo/newarray.rb
10
+ demo/strcat.rb
11
+ propaganda/Ruby2C.key/.typeAttributes.dict
12
+ propaganda/Ruby2C.key/Contents/PkgInfo
13
+ propaganda/Ruby2C.key/pasted.pdf
14
+ propaganda/Ruby2C.key/pasted1.pdf
15
+ propaganda/Ruby2C.key/pasted10.pdf
16
+ propaganda/Ruby2C.key/pasted2.pdf
17
+ propaganda/Ruby2C.key/pasted3.pdf
18
+ propaganda/Ruby2C.key/pasted4.pdf
19
+ propaganda/Ruby2C.key/pasted5.pdf
20
+ propaganda/Ruby2C.key/pasted6.pdf
21
+ propaganda/Ruby2C.key/pasted7.pdf
22
+ propaganda/Ruby2C.key/pasted8.pdf
23
+ propaganda/Ruby2C.key/pasted9.pdf
24
+ propaganda/Ruby2C.key/presentation.apxl
25
+ propaganda/Ruby2C.key/thumbs/.rjsf
26
+ propaganda/Ruby2C.key/thumbs/mt0.tiff
27
+ propaganda/Ruby2C.key/thumbs/mt1.tiff
28
+ propaganda/Ruby2C.key/thumbs/mt10.tiff
29
+ propaganda/Ruby2C.key/thumbs/mt11.tiff
30
+ propaganda/Ruby2C.key/thumbs/mt12.tiff
31
+ propaganda/Ruby2C.key/thumbs/mt13.tiff
32
+ propaganda/Ruby2C.key/thumbs/mt14.tiff
33
+ propaganda/Ruby2C.key/thumbs/mt15.tiff
34
+ propaganda/Ruby2C.key/thumbs/mt2.tiff
35
+ propaganda/Ruby2C.key/thumbs/mt3.tiff
36
+ propaganda/Ruby2C.key/thumbs/mt4.tiff
37
+ propaganda/Ruby2C.key/thumbs/mt5.tiff
38
+ propaganda/Ruby2C.key/thumbs/mt6.tiff
39
+ propaganda/Ruby2C.key/thumbs/mt7.tiff
40
+ propaganda/Ruby2C.key/thumbs/mt8.tiff
41
+ propaganda/Ruby2C.key/thumbs/mt9.tiff
42
+ propaganda/Ruby2C.key/thumbs/st0.tiff
43
+ propaganda/Ruby2C.key/thumbs/st1.tiff
44
+ propaganda/Ruby2C.key/thumbs/st10.tiff
45
+ propaganda/Ruby2C.key/thumbs/st11.tiff
46
+ propaganda/Ruby2C.key/thumbs/st13.tiff
47
+ propaganda/Ruby2C.key/thumbs/st131.tiff
48
+ propaganda/Ruby2C.key/thumbs/st15.tiff
49
+ propaganda/Ruby2C.key/thumbs/st16.tiff
50
+ propaganda/Ruby2C.key/thumbs/st161.tiff
51
+ propaganda/Ruby2C.key/thumbs/st17.tiff
52
+ propaganda/Ruby2C.key/thumbs/st18.tiff
53
+ propaganda/Ruby2C.key/thumbs/st19.tiff
54
+ propaganda/Ruby2C.key/thumbs/st2.tiff
55
+ propaganda/Ruby2C.key/thumbs/st20.tiff
56
+ propaganda/Ruby2C.key/thumbs/st201.tiff
57
+ propaganda/Ruby2C.key/thumbs/st21.tiff
58
+ propaganda/Ruby2C.key/thumbs/st22.tiff
59
+ propaganda/Ruby2C.key/thumbs/st23.tiff
60
+ propaganda/Ruby2C.key/thumbs/st231.tiff
61
+ propaganda/Ruby2C.key/thumbs/st24.tiff
62
+ propaganda/Ruby2C.key/thumbs/st25.tiff
63
+ propaganda/Ruby2C.key/thumbs/st3.tiff
64
+ propaganda/Ruby2C.key/thumbs/st31.tiff
65
+ propaganda/Ruby2C.key/thumbs/st4.tiff
66
+ propaganda/Ruby2C.key/thumbs/st5.tiff
67
+ propaganda/Ruby2C.key/thumbs/st7.tiff
68
+ propaganda/Ruby2C.key/thumbs/st8.tiff
69
+ propaganda/Ruby2C.key/thumbs/st9.tiff
70
+ propaganda/Ruby2C.key/tile_paper_blue.jpg
71
+ propaganda/Ruby2C.key/tile_paper_gray.jpg
72
+ propaganda/Ruby2C.key/tile_paper_green.jpg
73
+ propaganda/Ruby2C.key/tile_paper_purple.jpg
74
+ propaganda/Ruby2C.key/tile_paper_red.jpg
75
+ propaganda/Ruby2C.key/tile_paper_yellow.jpg
76
+ propaganda/Ruby2C.key/tiny/.jrsf
77
+ propaganda/Ruby2C.key/tiny/tile_paper_blue.jpg
78
+ propaganda/Ruby2C.pdf
79
+ propaganda/class diagram.graffle
80
+ propaganda/processors.graffle
81
+ propaganda/ruby2c architecture.graffle
82
+ rewrite.rb
83
+ rewriter.rb
84
+ ruby_to_c.rb
85
+ support.rb
86
+ test_all.rb
87
+ test_extras.rb
88
+ test_rewriter.rb
89
+ test_ruby_to_c.rb
90
+ test_support.rb
91
+ test_type_checker.rb
92
+ test_typed_sexp_processor.rb
93
+ translate.rb
94
+ type.rb
95
+ type_checker.rb
96
+ typed_sexp_processor.rb
97
+ validate.sh
98
+ zcomparable.rb
data/README.txt ADDED
@@ -0,0 +1,75 @@
1
+ ruby_to_c
2
+ http://rubyforge.org/projects/ruby2c/
3
+ ryand-ruby@zenspider.com
4
+ ruby2c@zenspider.com - mailing list
5
+
6
+ DESCRIPTION:
7
+
8
+ ruby_to_c translates a static ruby subset to C. Hopefully it works.
9
+
10
+ NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE
11
+
12
+ THIS IS BETA SOFTWARE!
13
+
14
+ NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE ! NOTE
15
+
16
+ RubyToC has the following modules:
17
+
18
+ Rewriter - massages the sexp into a more consistent form.
19
+ TypeChecker - type inferencer for the above sexps.
20
+ RubyToC - converts a ruby (subset) sexp to C.
21
+
22
+ and the following tools:
23
+
24
+ translate.rb - Translates a given file to C.
25
+
26
+ FEATURES/PROBLEMS:
27
+
28
+ + This is a preview release! BETA BETA BETA! Do NOT use this!
29
+ + Please contact me or Eric (drbrain of segment7 dot net) if you:
30
+ + have any feedback!
31
+ + have any changes!
32
+ + want to work on this!
33
+
34
+ SYNOPSYS:
35
+
36
+ ./translate.rb blah.rb > blah.c; gcc -c -I /rubylib/1.8/platform blah.c
37
+
38
+ TODO:
39
+
40
+ + Numerous, but we are trying to get them in here... sorry...
41
+ + Want to move to a gem directory structure (lib/ test/ bin/ etc)
42
+
43
+ REQUIREMENTS:
44
+
45
+ + ParseTree - http://rubyforge.org/projects/parsetree/
46
+ + RubyInline - http://rubyforge.org/projects/rubyinline/
47
+
48
+ INSTALL:
49
+
50
+ + Um. Please don't install this crap yet...
51
+
52
+ LICENSE:
53
+
54
+ (The MIT License)
55
+
56
+ Copyright (c) 2001-2002 Ryan Davis, Zen Spider Software
57
+
58
+ Permission is hereby granted, free of charge, to any person obtaining
59
+ a copy of this software and associated documentation files (the
60
+ "Software"), to deal in the Software without restriction, including
61
+ without limitation the rights to use, copy, modify, merge, publish,
62
+ distribute, sublicense, and/or sell copies of the Software, and to
63
+ permit persons to whom the Software is furnished to do so, subject to
64
+ the following conditions:
65
+
66
+ The above copyright notice and this permission notice shall be
67
+ included in all copies or substantial portions of the Software.
68
+
69
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
70
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
71
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
72
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
73
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
74
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
75
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/demo/char.rb ADDED
@@ -0,0 +1,13 @@
1
+
2
+ class CharDemo
3
+ def chardemo
4
+ s = "hello"
5
+ c = s[2]
6
+ return c
7
+ end
8
+
9
+ def main
10
+ chardemo
11
+ return 0
12
+ end
13
+ end
data/demo/factorial.rb ADDED
@@ -0,0 +1,11 @@
1
+ class F
2
+ def factorial(n)
3
+ f = 1
4
+ n.downto(2) { |x| f *= x }
5
+ return f
6
+ end
7
+
8
+ def main # horrid but funny hack
9
+ return factorial(5)
10
+ end
11
+ end
data/demo/hello.rb ADDED
@@ -0,0 +1,11 @@
1
+
2
+ class Hello
3
+ def hello
4
+ puts "hello world"
5
+ end
6
+
7
+ def main # silly hack
8
+ hello
9
+ return 0
10
+ end
11
+ end
data/demo/misc.rb ADDED
@@ -0,0 +1,25 @@
1
+
2
+ class Misc
3
+ def assert(cond, n)
4
+ if (!cond) then
5
+ puts("-- SymTab fatal error ")
6
+ case (n)
7
+ when 3
8
+ puts("-- too many nodes in graph")
9
+ when 4
10
+ puts("-- too many sets")
11
+ when 6
12
+ puts("-- too many symbols")
13
+ when 7
14
+ puts("-- too many character classes")
15
+ end
16
+ # puts("Stack Trace = #{caller.join "\n"}")
17
+ exit(n)
18
+ end
19
+ end
20
+
21
+ def main
22
+ assert(1 == 1, 3)
23
+ return 0
24
+ end
25
+ end
data/demo/newarray.rb ADDED
@@ -0,0 +1,11 @@
1
+
2
+ class NewArray
3
+ def newarray
4
+ a = [1, 2, 3]
5
+ return a[0]
6
+ end
7
+
8
+ def main
9
+ return newarray
10
+ end
11
+ end
data/demo/strcat.rb ADDED
@@ -0,0 +1,12 @@
1
+ class Blah
2
+ def blah
3
+ a = "this"
4
+ b = a + "that"
5
+ puts(b)
6
+ end
7
+
8
+ def main
9
+ blah
10
+ return 0
11
+ end
12
+ end
data/rewrite.rb ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'pp'
4
+ require 'rewriter'
5
+
6
+ old_classes = []
7
+ ObjectSpace.each_object(Class) do |klass|
8
+ old_classes << klass
9
+ end
10
+
11
+ ARGV.each do |name|
12
+ require name
13
+ end
14
+
15
+ new_classes = []
16
+ ObjectSpace.each_object(Class) do |klass|
17
+ new_classes << klass
18
+ end
19
+
20
+ new_classes -= old_classes
21
+
22
+ parser = ParseTree.new
23
+ rewriter = Rewriter.new
24
+
25
+ new_classes.each do |klass|
26
+ sexp = parser.parse_tree klass
27
+ sexp.each do |exp|
28
+ exp = rewriter.process(exp)
29
+ pp exp
30
+ end
31
+ end
32
+
data/rewriter.rb ADDED
@@ -0,0 +1,356 @@
1
+
2
+ begin require 'rubygems' rescue LoadError end
3
+ require 'parse_tree'
4
+ require 'typed_sexp_processor'
5
+
6
+ class Sexp
7
+ # add arglist because we introduce the new array type in this file
8
+ @@array_types << :arglist
9
+ end
10
+
11
+ ##
12
+ # Rewriter (probably should be renamed) is a first-pass filter that
13
+ # normalizes some of ruby's ASTs to make them more processable later
14
+ # in the pipeline. It only has processors for what it is interested
15
+ # in, so real the individual methods for a better understanding of
16
+ # what it does.
17
+
18
+ class Rewriter < SexpProcessor
19
+
20
+ def initialize # :nodoc:
21
+ super
22
+ self.auto_shift_type = true
23
+ self.unsupported = [ :cfunc, ]
24
+ # self.debug[:defn] = /method/ # coolest debugging feature ever
25
+ end
26
+
27
+ ##
28
+ # Rewrites :attrasgn nodes to the unified :call format:
29
+ #
30
+ # [:attrasgn, lhs, :name=, args],
31
+ #
32
+ # becomes:
33
+ #
34
+ # [:call, lhs, :name=, args]
35
+
36
+ def process_attrasgn(exp)
37
+ lhs = process exp.shift
38
+ name = exp.shift
39
+ args = process exp.shift
40
+ args[0] = :arglist unless args.nil?
41
+
42
+ s(:call, lhs, name, args)
43
+ end
44
+
45
+ ##
46
+ # Rewrites :call nodes to the unified :call format:
47
+ # [:call, lhs, :name, args]
48
+
49
+ def process_call(exp)
50
+ lhs = process exp.shift
51
+ name = exp.shift
52
+ args = process exp.shift
53
+ args[0] = :arglist unless args.nil?
54
+
55
+ s(:call, lhs, name, args)
56
+ end
57
+
58
+ ##
59
+ # Rewrites :case/:when nodes as nested :if nodes.
60
+
61
+ def process_case(exp)
62
+ result = s()
63
+ var = process exp.shift
64
+ else_stmt = process exp.pop
65
+
66
+ new_exp = result
67
+
68
+ until exp.empty? do
69
+ c = exp.shift
70
+ # start a new scope and move to it
71
+ new_exp << s(:if)
72
+ new_exp = new_exp.last
73
+
74
+ assert_type c, :when
75
+ ignored_type, vars, stmts = process(c)
76
+
77
+ vars = vars.map { |v| s(:call,
78
+ var.deep_clone,
79
+ :===,
80
+ s(:arglist, process(v)))}
81
+ if vars.size > 1 then
82
+
83
+ # building from the bottom up, so everything is bizarro-sexp
84
+ # BIZARRO-SEXP NO LIKE OR!
85
+ or_sexp = vars.inject(s(:or, *vars.slice!(-2,2))) do |lhs, rhs|
86
+ s(:or, rhs, lhs)
87
+ end
88
+
89
+ new_exp << or_sexp
90
+ else
91
+ new_exp << vars.first
92
+ end
93
+ new_exp << stmts
94
+ end
95
+ new_exp << else_stmt
96
+
97
+ result.first
98
+ end
99
+
100
+ ##
101
+ # Rewrites :defn nodes to pull the functions arguments to the top:
102
+ #
103
+ # Input:
104
+ #
105
+ # [:defn, name, [:scope, [:block, [:args, ...]]]]
106
+ # [:defn, name, [:fbody, [:scope, [:block, [:args, ...]]]]]
107
+ # [:defn, name, [:ivar, name]]
108
+ # [:defn, name, [:attrset, name]]
109
+ #
110
+ # Output:
111
+ #
112
+ # [:defn, name, args, body]
113
+
114
+ def process_defn(exp)
115
+ name = exp.shift
116
+ args = s(:args)
117
+ body = process exp.shift
118
+
119
+ case body.first
120
+ when :scope, :fbody then
121
+ body = body[1] if body.first == :fbody
122
+ args = body.last[1]
123
+ assert_type args, :args
124
+ assert_type body, :scope
125
+ assert_type body[1], :block
126
+ body.last.delete_at 1
127
+ when :bmethod then
128
+ # BEFORE: [:defn, :bmethod_added, [:bmethod, [:dasgn_curr, :x], ...]]
129
+ # AFTER: [:defn, :bmethod_added, [:args, :x], [:scope, [:block, ...]]]
130
+ body.shift # :bmethod
131
+ # [:dasgn_curr, :x],
132
+ # [:call, [:dvar, :x], :+, [:arglist, [:lit, 1]]]]]
133
+ dasgn = body.shift
134
+ assert_type dasgn, :dasgn_curr
135
+ dasgn.shift # type
136
+ args.push(*dasgn)
137
+ body.find_and_replace_all(:dvar, :lvar)
138
+ if body.first.first == :block then
139
+ body = s(:scope, body.shift)
140
+ else
141
+ body = s(:scope, s(:block, body.shift)) # single statement
142
+ end
143
+ when :dmethod
144
+ # BEFORE: [:defn, :dmethod_added, [:dmethod, :bmethod_maker, ...]]
145
+ # AFTER: [:defn, :dmethod_added, ...]
146
+ body = body[2][1][2] # UGH! FIX
147
+ args = body[1]
148
+ body.delete_at 1
149
+ body = s(:scope, body)
150
+ when :ivar then
151
+ body = s(:scope, s(:block, s(:return, body)))
152
+ when :attrset then
153
+ argname = body.last
154
+ args << :arg
155
+ body = s(:scope, s(:block, s(:return, s(:iasgn, argname, s(:lvar, :arg)))))
156
+ else
157
+ raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"
158
+ end
159
+
160
+ return s(:defn, name, args, body)
161
+ end
162
+
163
+ ##
164
+ # Rewrites :fcall nodes to the unified :call format:
165
+ # [:call, lhs, :name, args]
166
+
167
+ def process_fcall(exp)
168
+ name = exp.shift
169
+ args = process exp.shift
170
+ args[0] = :arglist
171
+
172
+ return s(:call, nil, name, args)
173
+ end
174
+
175
+ ##
176
+ # I'm not really sure what this is for, other than to guarantee that
177
+ # there are 4 elements in the sexp.
178
+
179
+ def process_if(exp)
180
+ cond = process exp.shift
181
+ t = process(exp.shift) || nil # FIX: nil is bad, we need to switch to dummy
182
+ f = process(exp.shift) || nil
183
+ return s(:if, cond, t, f)
184
+ end
185
+
186
+ ##
187
+ # Rewrites specific :iter nodes into while loops:
188
+ # [DOC]
189
+
190
+ def process_iter(exp)
191
+ call = process exp.shift
192
+ var = process exp.shift
193
+ body = process exp.shift
194
+
195
+ if var.nil? then
196
+ var = s(:lvar, :temp_var1) # HACK Use Unique
197
+ end
198
+
199
+ assert_type call, :call
200
+
201
+ if call[2] != :each then # TODO: fix call[n] (api)
202
+ call.shift # :call
203
+ lhs = call.shift
204
+ method_name = call.shift
205
+
206
+ case method_name
207
+ when :downto then
208
+ var.shift #
209
+ start_value = lhs
210
+ finish_value = call.pop.pop # not sure about this
211
+ var_name = var.shift
212
+ body.find_and_replace_all(:dvar, :lvar)
213
+ result = s(:dummy,
214
+ s(:lasgn, var_name, start_value),
215
+ s(:while,
216
+ s(:call, s(:lvar, var_name), :>=,
217
+ s(:arglist, finish_value)),
218
+ s(:block,
219
+ body,
220
+ s(:lasgn, var_name,
221
+ s(:call, s(:lvar, var_name), :-,
222
+ s(:arglist, s(:lit, 1))))), true))
223
+ when :upto then
224
+ # REFACTOR: completely duped from above and direction changed
225
+ var.shift #
226
+ start_value = lhs
227
+ finish_value = call.pop.pop # not sure about this
228
+ var_name = var.shift
229
+ body.find_and_replace_all(:dvar, :lvar)
230
+ result = s(:dummy,
231
+ s(:lasgn, var_name, start_value),
232
+ s(:while,
233
+ s(:call, s(:lvar, var_name), :<=,
234
+ s(:arglist, finish_value)),
235
+ s(:block,
236
+ body,
237
+ s(:lasgn, var_name,
238
+ s(:call, s(:lvar, var_name), :+,
239
+ s(:arglist, s(:lit, 1))))), true))
240
+ when :define_method then
241
+ # BEFORE: [:iter, [:call, nil, :define_method, [:array, [:lit, :bmethod_added]]], [:dasgn_curr, :x], [:call, [:dvar, :x], :+, [:array, [:lit, 1]]]]
242
+ # we want to get it rewritten for the scope/block context, so:
243
+ # - throw call away
244
+ # - rewrite to args
245
+ # - plop body into a scope
246
+ # AFTER: [:block, [:args, :x], [:call, [:lvar, :x], :+, [:arglist, [:lit, 1]]]]
247
+ var.find_and_replace_all(:dasgn_curr, :args)
248
+ body.find_and_replace_all(:dvar, :lvar)
249
+ result = s(:block, var, body)
250
+ else
251
+ raise "unknown iter method #{method_name}"
252
+ end
253
+ else
254
+ s(:iter, call, var, body)
255
+ end
256
+ end
257
+
258
+ ##
259
+ # Rewrites self into lvars
260
+
261
+ def process_self(exp)
262
+ s(:lvar, :self)
263
+ end
264
+
265
+ ##
266
+ # Rewrites until nodes into while nodes.
267
+
268
+ def process_until(exp)
269
+ cond = process s(:not, exp.shift)
270
+ body = process exp.shift
271
+ raise "boo" if exp.empty?
272
+ is_precondition = exp.shift
273
+ s(:while, cond, body, is_precondition)
274
+ end
275
+
276
+ ##
277
+ # Rewrites :vcall nodes to the unified :call format:
278
+ # [:call, lhs, :name, args]
279
+
280
+ def process_vcall(exp)
281
+ name = exp.shift
282
+
283
+ s(:call, nil, name, nil) # TODO: never has any args?
284
+ end
285
+
286
+ ##
287
+ # Rewrites :when nodes so :case can digest it into if/else structure
288
+ # [:when, [args], body]
289
+
290
+ def process_when(exp)
291
+ vars = exp.shift
292
+ assert_type vars, :array
293
+ vars.shift # nuke vars type
294
+ stmts = process(exp)
295
+ return s(:when, vars, stmts.first)
296
+ end
297
+
298
+ ##
299
+ # Rewrites :zarray nodes to :array with no args.
300
+
301
+ def process_zarray(exp)
302
+ return s(:array)
303
+ end
304
+
305
+ end
306
+
307
+ ##
308
+ # R2CRewriter (should probably move this out to its own file) does
309
+ # rewritings that are language specific to C.
310
+
311
+ class R2CRewriter < SexpProcessor
312
+
313
+ ##
314
+ # REWRITES maps a function signature to a proc responsible for
315
+ # generating the appropriate sexp for that rewriting.
316
+
317
+ REWRITES = {
318
+ [Type.str, :+, Type.str] => proc { |l,n,r|
319
+ t(:call, nil, :strcat, r.unshift(r.shift, l), Type.str)
320
+ },
321
+ [Type.file, :puts, Type.str] => proc { |l,n,r|
322
+ t(:call, nil, :fputs, r.push(l))
323
+ },
324
+ }
325
+
326
+ def initialize # :nodoc:
327
+ super
328
+ self.auto_shift_type = true
329
+ self.expected = TypedSexp
330
+ end
331
+
332
+ ##
333
+ # Rewrites function calls by looking them up in the REWRITES map. If
334
+ # a match exists, it invokes the block passing in the lhs, rhs, and
335
+ # function name. If one does not exist, it simply repacks the sexp
336
+ # and sends it along.
337
+
338
+ def process_call(exp)
339
+ lhs = process exp.shift
340
+ name = exp.shift
341
+ rhs = process exp.shift
342
+
343
+ lhs_type = lhs.sexp_type rescue nil
344
+ type_signature = [lhs_type, name]
345
+ type_signature += rhs[1..-1].map { |sexp| sexp.sexp_type } unless rhs.nil?
346
+
347
+ result = if REWRITES.has_key? type_signature then
348
+ REWRITES[type_signature].call(lhs, name, rhs)
349
+ else
350
+ t(:call, lhs, name, rhs, exp.sexp_type)
351
+ end
352
+
353
+ return result
354
+ end
355
+ end
356
+