RubyToC 1.0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+