RubyToC 1.0.0.4 → 1.0.0.5
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 +15 -0
- data/Makefile +7 -2
- data/Manifest.txt +18 -88
- data/README.txt +2 -1
- data/Rakefile +52 -0
- data/bin/ruby_to_c_show +97 -0
- data/{validate.sh → bin/ruby_to_c_validate} +0 -0
- data/{rewriter.rb → lib/rewriter.rb} +19 -5
- data/{ruby_to_c.rb → lib/ruby_to_ansi_c.rb} +71 -80
- data/lib/ruby_to_ruby_c.rb +167 -0
- data/{support.rb → lib/support.rb} +20 -19
- data/{type_checker.rb → lib/type_checker.rb} +17 -11
- data/{typed_sexp_processor.rb → lib/typed_sexp_processor.rb} +30 -30
- data/test/r2ctestcase.rb +1261 -0
- data/{test_all.rb → test/test_all.rb} +0 -0
- data/{test_extras.rb → test/test_extras.rb} +59 -61
- data/{test_rewriter.rb → test/test_rewriter.rb} +38 -38
- data/{test_ruby_to_c.rb → test/test_ruby_to_ansi_c.rb} +128 -173
- data/test/test_ruby_to_ruby_c.rb +27 -0
- data/{test_support.rb → test/test_support.rb} +80 -43
- data/{test_type_checker.rb → test/test_type_checker.rb} +121 -130
- data/{test_typed_sexp_processor.rb → test/test_typed_sexp_processor.rb} +70 -65
- metadata +55 -48
- data/rewrite.rb +0 -32
- data/translate.rb +0 -31
- data/type.rb +0 -33
- data/zcomparable.rb +0 -300
data/History.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
*** 1.0.0-beta-5 / 2006-05-12
|
2
|
+
|
3
|
+
+ 6 minor enhancements:
|
4
|
+
+ Split RubyToC to RubyToRubyC and RubyToAnsiC.
|
5
|
+
+ Extended Environment to be more flexible for various situations.
|
6
|
+
+ Removed propaganda (bloat) from release.
|
7
|
+
+ Gemified and reorganized things. Support still needs splitting up.
|
8
|
+
+ Flipped a lot of internal naming to use Unique.
|
9
|
+
+ Added ruby_to_c_show (like parse_tree_show).
|
10
|
+
+ 4(ish) bug fixes:
|
11
|
+
+ Use ivars instead of cvars so inheritance won't bugger the translator.
|
12
|
+
+ Corrected unsupported node lists in pipeline.
|
13
|
+
+ Fixed bugs for splat args, iters, optional args, method name map.
|
14
|
+
+ Fixed many other bugs.
|
15
|
+
|
1
16
|
*** 1.0.0-beta-4 / 2005-07-13
|
2
17
|
|
3
18
|
+ 1 minor enhancements
|
data/Makefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
RUBY?=ruby
|
2
2
|
RUBY_FLAGS?=-w -I.:../../ParseTree/dev/lib:../../ParseTree/dev/test:../../RubyInline/dev
|
3
|
-
|
3
|
+
FILTER?=
|
4
4
|
|
5
5
|
all test:
|
6
|
-
$(RUBY) $(RUBY_FLAGS) test_all.rb $(
|
6
|
+
$(RUBY) $(RUBY_FLAGS) test_all.rb $(FILTER)
|
7
7
|
|
8
8
|
docs:
|
9
9
|
rdoc -d -I png --main RubyToC -x test_\* -x something.rb
|
@@ -42,6 +42,11 @@ demos: FORCE
|
|
42
42
|
interp: FORCE
|
43
43
|
for rf in demo/*.rb; do f=$$(basename $$rf .rb); echo $$f; ./interp.rb demo/$$f; done
|
44
44
|
|
45
|
+
sort:
|
46
|
+
for f in *.rb; do grep "def " $f > x; sort x > y; echo $f; echo; diff x y; done
|
47
|
+
for f in test_*.rb; do grep "def.test_" $f > x; sort x > y; echo $f; echo; diff x y; done
|
48
|
+
rm x y
|
49
|
+
|
45
50
|
clean:
|
46
51
|
rm -f *~ trouble.* diff.txt demo/*~
|
47
52
|
rm -rf ~/.ruby_inline
|
data/Manifest.txt
CHANGED
@@ -2,97 +2,27 @@ History.txt
|
|
2
2
|
Makefile
|
3
3
|
Manifest.txt
|
4
4
|
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/ruby_to_c_show
|
7
|
+
bin/ruby_to_c_validate
|
5
8
|
demo/char.rb
|
6
9
|
demo/factorial.rb
|
7
10
|
demo/hello.rb
|
8
11
|
demo/misc.rb
|
9
12
|
demo/newarray.rb
|
10
13
|
demo/strcat.rb
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
14
|
+
lib/rewriter.rb
|
15
|
+
lib/ruby_to_ansi_c.rb
|
16
|
+
lib/ruby_to_ruby_c.rb
|
17
|
+
lib/support.rb
|
18
|
+
lib/type_checker.rb
|
19
|
+
lib/typed_sexp_processor.rb
|
20
|
+
test/r2ctestcase.rb
|
21
|
+
test/test_all.rb
|
22
|
+
test/test_extras.rb
|
23
|
+
test/test_rewriter.rb
|
24
|
+
test/test_ruby_to_ansi_c.rb
|
25
|
+
test/test_ruby_to_ruby_c.rb
|
26
|
+
test/test_support.rb
|
27
|
+
test/test_type_checker.rb
|
28
|
+
test/test_typed_sexp_processor.rb
|
data/README.txt
CHANGED
@@ -17,7 +17,8 @@ RubyToC has the following modules:
|
|
17
17
|
|
18
18
|
Rewriter - massages the sexp into a more consistent form.
|
19
19
|
TypeChecker - type inferencer for the above sexps.
|
20
|
-
|
20
|
+
RubyToRubyC - converts a ruby (subset) sexp to ruby interals C.
|
21
|
+
RubyToAnsiC - converts a ruby (subset) sexp to ANSI C.
|
21
22
|
|
22
23
|
and the following tools:
|
23
24
|
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'rubygems'
|
8
|
+
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs.push(*%w( test ../../ParseTree/dev/lib ../../ParseTree/dev/test ../../RubyInline/dev ))
|
13
|
+
t.pattern = 'test/test_*.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
R2C_VERSION = $1 if File.read('./lib/ruby_to_ansi_c.rb') =~ /VERSION = '([^']+)'/
|
18
|
+
|
19
|
+
spec = Gem::Specification.new do |s|
|
20
|
+
s.name = 'RubyToC'
|
21
|
+
s.version = R2C_VERSION.sub(/-beta-/, '.')
|
22
|
+
s.summary = "Ruby (subset) to C translator."
|
23
|
+
|
24
|
+
paragraphs = File.read("README.txt").split(/\n\n+/)
|
25
|
+
s.description = paragraphs[2]
|
26
|
+
puts s.description
|
27
|
+
|
28
|
+
s.add_dependency('ParseTree')
|
29
|
+
s.files = IO.readlines("Manifest.txt").reject { |o| o =~ /propaganda/ }.map {|f| f.chomp }
|
30
|
+
|
31
|
+
s.require_path = 'lib'
|
32
|
+
|
33
|
+
s.has_rdoc = true
|
34
|
+
s.test_suite_file = "test/test_all.rb"
|
35
|
+
|
36
|
+
s.author = "Ryan Davis"
|
37
|
+
s.email = "ryand-ruby@zenspider.com"
|
38
|
+
s.homepage = "http://rubyforge.org/projects/ruby2c/"
|
39
|
+
s.rubyforge_project = "ruby2c"
|
40
|
+
end
|
41
|
+
|
42
|
+
Rake::GemPackageTask.new spec do |pkg|
|
43
|
+
pkg.need_tar = true
|
44
|
+
end
|
45
|
+
|
46
|
+
task :sort do
|
47
|
+
sh 'for f in lib/*.rb; do grep "^ *def " $f | grep -v "def self" > x; sort x > y; echo; echo $f; echo; diff x y; done; true'
|
48
|
+
sh 'for f in test/test_*.rb; do grep "def.test_" $f > x; sort x > y; echo; echo $f; echo; diff x y; done; true'
|
49
|
+
sh 'rm x y'
|
50
|
+
end
|
51
|
+
|
52
|
+
|
data/bin/ruby_to_c_show
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/local/bin/ruby -ws
|
2
|
+
|
3
|
+
$: << "../../ParseTree/dev/lib"
|
4
|
+
|
5
|
+
require 'pp'
|
6
|
+
require 'parse_tree'
|
7
|
+
require 'ruby_to_ansi_c'
|
8
|
+
|
9
|
+
if defined? $h then
|
10
|
+
puts "Usage:"
|
11
|
+
puts " #{File.basename $0} [options]"
|
12
|
+
puts " -h display this help"
|
13
|
+
puts " -r display rewriter output only"
|
14
|
+
puts " -t display typecherker output only"
|
15
|
+
puts " -R display r2c rewriter output only"
|
16
|
+
puts " -f fast mode, read from stdin and build class/method around it"
|
17
|
+
puts " -c <class> class to process"
|
18
|
+
puts " -q quick mode, use regular inspect instead of pp"
|
19
|
+
puts " -p print mode, just print instead of p or pp"
|
20
|
+
exit 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def discover_new_classes_from
|
24
|
+
old_classes = []
|
25
|
+
ObjectSpace.each_object(Module) do |klass|
|
26
|
+
old_classes << klass
|
27
|
+
end
|
28
|
+
|
29
|
+
yield
|
30
|
+
|
31
|
+
new_classes = []
|
32
|
+
ObjectSpace.each_object(Module) do |klass|
|
33
|
+
new_classes << klass
|
34
|
+
end
|
35
|
+
|
36
|
+
new_classes -= old_classes
|
37
|
+
new_classes = [ eval($c) ] if defined? $c
|
38
|
+
new_classes
|
39
|
+
end
|
40
|
+
|
41
|
+
$f = false unless defined? $f
|
42
|
+
|
43
|
+
new_classes = discover_new_classes_from do
|
44
|
+
ARGV.unshift "-" if ARGV.empty?
|
45
|
+
ARGV.each do |name|
|
46
|
+
if name == "-" then
|
47
|
+
code = $stdin.read
|
48
|
+
code = "class Example; def example; #{code}; end; end" if $f
|
49
|
+
eval code unless code.nil?
|
50
|
+
else
|
51
|
+
require name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
parser = ParseTree.new(false)
|
57
|
+
translator = RubyToAnsiC.translator
|
58
|
+
|
59
|
+
$r ||= false
|
60
|
+
$t ||= false
|
61
|
+
$R ||= false
|
62
|
+
|
63
|
+
if $r or $t or $R then
|
64
|
+
t = translator.processors
|
65
|
+
|
66
|
+
t.pop # r2c
|
67
|
+
if $r then
|
68
|
+
t.pop # r2c rewriter
|
69
|
+
t.pop # typechecker
|
70
|
+
end
|
71
|
+
if $t then
|
72
|
+
t.pop # r2c rewriter
|
73
|
+
end
|
74
|
+
if $R then
|
75
|
+
# nothing else to do
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
new_classes.each do |klass|
|
80
|
+
sexp = parser.parse_tree klass
|
81
|
+
sexp.each do |exp|
|
82
|
+
result = translator.process(exp)
|
83
|
+
|
84
|
+
if defined? $q then
|
85
|
+
p result
|
86
|
+
next
|
87
|
+
end
|
88
|
+
|
89
|
+
if defined? $p then
|
90
|
+
puts result
|
91
|
+
next
|
92
|
+
end
|
93
|
+
|
94
|
+
pp result
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
File without changes
|
@@ -157,6 +157,16 @@ class Rewriter < SexpProcessor
|
|
157
157
|
raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"
|
158
158
|
end
|
159
159
|
|
160
|
+
if Array === args.last and args.last.first == :block then
|
161
|
+
cond = args.pop
|
162
|
+
cond.shift # take off :block
|
163
|
+
new_code = cond.map do |t, var, val|
|
164
|
+
s(:if, s(:call, s(:lvar, var), :nil?), s(:lasgn, var, val), nil)
|
165
|
+
end
|
166
|
+
body[1].insert 1, *new_code
|
167
|
+
end
|
168
|
+
|
169
|
+
|
160
170
|
return s(:defn, name, args, body)
|
161
171
|
end
|
162
172
|
|
@@ -167,7 +177,7 @@ class Rewriter < SexpProcessor
|
|
167
177
|
def process_fcall(exp)
|
168
178
|
name = exp.shift
|
169
179
|
args = process exp.shift
|
170
|
-
args[0] = :arglist
|
180
|
+
args[0] = :arglist unless args.nil? # for :fcall with block (:iter)
|
171
181
|
|
172
182
|
return s(:call, nil, name, args)
|
173
183
|
end
|
@@ -192,9 +202,7 @@ class Rewriter < SexpProcessor
|
|
192
202
|
var = process exp.shift
|
193
203
|
body = process exp.shift
|
194
204
|
|
195
|
-
if var.nil?
|
196
|
-
var = s(:lvar, :temp_var1) # HACK Use Unique
|
197
|
-
end
|
205
|
+
var = s(:dasgn_curr, Unique.next) if var.nil?
|
198
206
|
|
199
207
|
assert_type call, :call
|
200
208
|
|
@@ -248,9 +256,14 @@ class Rewriter < SexpProcessor
|
|
248
256
|
body.find_and_replace_all(:dvar, :lvar)
|
249
257
|
result = s(:block, var, body)
|
250
258
|
else
|
251
|
-
|
259
|
+
# HACK we butchered call up top
|
260
|
+
result = s(:iter, s(:call, lhs, method_name, call.shift), var, body)
|
252
261
|
end
|
253
262
|
else
|
263
|
+
if var.nil? then
|
264
|
+
var = s(:lvar, Unique.next)
|
265
|
+
end
|
266
|
+
|
254
267
|
s(:iter, call, var, body)
|
255
268
|
end
|
256
269
|
end
|
@@ -354,3 +367,4 @@ class R2CRewriter < SexpProcessor
|
|
354
367
|
end
|
355
368
|
end
|
356
369
|
|
370
|
+
|
@@ -10,15 +10,30 @@ require 'rewriter'
|
|
10
10
|
require 'pp'
|
11
11
|
|
12
12
|
##
|
13
|
-
#
|
13
|
+
# The whole point of this project! RubyToC is an actually very simple
|
14
|
+
# SexpProcessor that does the final conversion from Sexp to C code.
|
15
|
+
# This class has more unsupported nodes than any other (on
|
16
|
+
# purpose--we'd like TypeChecker and friends to be as generally useful
|
17
|
+
# as possible), and as a result, supports a very small subset of ruby.
|
18
|
+
#
|
19
|
+
# NOT SUPPORTED: (keep in sync w/ initialize)
|
20
|
+
#
|
21
|
+
# :begin, :block_arg, :case, :dstr, :rescue, :self, :super, :when
|
22
|
+
|
23
|
+
class RubyToAnsiC < SexpProcessor
|
14
24
|
|
15
|
-
|
25
|
+
VERSION = '1.0.0-beta-5'
|
26
|
+
|
27
|
+
# TODO: remove me
|
28
|
+
def no(exp) # :nodoc:
|
29
|
+
raise "no: #{caller[0].split[1]} #{exp.inspect}"
|
30
|
+
end
|
16
31
|
|
17
32
|
##
|
18
33
|
# Returns a textual version of a C type that corresponds to a sexp
|
19
34
|
# type.
|
20
35
|
|
21
|
-
def c_type(typ)
|
36
|
+
def self.c_type(typ)
|
22
37
|
base_type =
|
23
38
|
case typ.type.contents # HACK this is breaking demeter
|
24
39
|
when :float then
|
@@ -30,13 +45,13 @@ module TypeMap
|
|
30
45
|
when :symbol then
|
31
46
|
"symbol"
|
32
47
|
when :bool then # TODO: subject to change
|
33
|
-
"
|
48
|
+
"bool"
|
34
49
|
when :void then
|
35
50
|
"void"
|
36
51
|
when :homo then
|
37
52
|
"void *" # HACK
|
38
53
|
when :value, :unknown then
|
39
|
-
"
|
54
|
+
"void *" # HACK
|
40
55
|
# HACK: uncomment this and fix the above when you want to have good tests
|
41
56
|
# when :unknown then
|
42
57
|
# raise "You should not have unknown types by now!"
|
@@ -44,37 +59,11 @@ module TypeMap
|
|
44
59
|
raise "Bug! Unknown type #{typ.inspect} in c_type"
|
45
60
|
end
|
46
61
|
|
47
|
-
base_type += "
|
62
|
+
base_type += " *" if typ.list? unless typ.unknown?
|
48
63
|
|
49
64
|
base_type
|
50
65
|
end
|
51
66
|
|
52
|
-
module_function :c_type # if $TESTING
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
##
|
57
|
-
# The whole point of this project! RubyToC is an actually very simple
|
58
|
-
# SexpProcessor that does the final conversion from Sexp to C code.
|
59
|
-
# This class has more unsupported nodes than any other (on
|
60
|
-
# purpose--we'd like TypeChecker and friends to be as generally useful
|
61
|
-
# as possible), and as a result, supports a very small subset of ruby.
|
62
|
-
#
|
63
|
-
# NOT SUPPORTED: (keep in sync w/ initialize)
|
64
|
-
#
|
65
|
-
# :begin, :block_arg, :case, :dstr, :rescue, :self, :super, :when
|
66
|
-
|
67
|
-
class RubyToC < SexpProcessor
|
68
|
-
|
69
|
-
VERSION = '1.0.0-beta-4'
|
70
|
-
|
71
|
-
# TODO: remove me
|
72
|
-
def no(exp) # :nodoc:
|
73
|
-
raise "no: #{caller[0].split[1]} #{exp.inspect}"
|
74
|
-
end
|
75
|
-
|
76
|
-
include TypeMap
|
77
|
-
|
78
67
|
##
|
79
68
|
# Provides access to the variable scope.
|
80
69
|
|
@@ -96,8 +85,6 @@ class RubyToC < SexpProcessor
|
|
96
85
|
#include <ruby.h>
|
97
86
|
#define RB_COMPARE(x, y) (x) == (y) ? 0 : (x) < (y) ? -1 : 1
|
98
87
|
typedef char * str;
|
99
|
-
typedef struct { unsigned long length; long * contents; } long_array;
|
100
|
-
typedef struct { unsigned long length; str * contents; } str_array;
|
101
88
|
#define case_equal_long(x, y) ((x) == (y))
|
102
89
|
// END METARUBY PREAMBLE
|
103
90
|
" + self.prototypes.join('')
|
@@ -107,13 +94,13 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
107
94
|
# Lazy initializer for the composite RubytoC translator chain.
|
108
95
|
|
109
96
|
def self.translator
|
110
|
-
unless defined?
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
97
|
+
unless defined? @translator then
|
98
|
+
@translator = CompositeSexpProcessor.new
|
99
|
+
@translator << Rewriter.new
|
100
|
+
@translator << TypeChecker.new
|
101
|
+
@translator << R2CRewriter.new
|
102
|
+
@translator << RubyToAnsiC.new
|
103
|
+
@translator.on_error_in(:defn) do |processor, exp, err|
|
117
104
|
result = processor.expected.new
|
118
105
|
case result
|
119
106
|
when Array then
|
@@ -126,7 +113,7 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
126
113
|
result
|
127
114
|
end
|
128
115
|
end
|
129
|
-
|
116
|
+
@translator
|
130
117
|
end
|
131
118
|
|
132
119
|
##
|
@@ -174,7 +161,8 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
174
161
|
super
|
175
162
|
@env = Environment.new
|
176
163
|
self.auto_shift_type = true
|
177
|
-
self.unsupported = [ :begin, :block_arg, :case, :dstr, :rescue, :self, :super, :when, ]
|
164
|
+
self.unsupported = [:alias, :alloca, :argscat, :argspush, :attrasgn, :attrset, :back_ref, :begin, :block_arg, :block_pass, :bmethod, :break, :case, :cdecl, :cfunc, :colon2, :colon3, :cref, :cvasgn, :cvdecl, :dasgn, :defined, :defs, :dmethod, :dot2, :dot3, :dregx, :dregx_once, :dstr, :dsym, :dxstr, :ensure, :evstr, :fbody, :fcall, :flip2, :flip3, :for, :gasgn, :ifunc, :last, :masgn, :match, :match2, :match3, :memo, :method, :module, :newline, :next, :nth_ref, :op_asgn1, :op_asgn2, :op_asgn_and, :opt_n, :postexe, :redo, :resbody, :rescue, :retry, :sclass, :self, :splat, :super, :svalue, :to_ary, :undef, :until, :valias, :vcall, :when, :xstr, :yield, :zarray, :zsuper]
|
165
|
+
|
178
166
|
self.strict = true
|
179
167
|
self.expected = String
|
180
168
|
|
@@ -191,6 +179,13 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
191
179
|
return "#{lhs} && #{rhs}"
|
192
180
|
end
|
193
181
|
|
182
|
+
##
|
183
|
+
# Arglist is used by call arg lists.
|
184
|
+
|
185
|
+
def process_arglist(exp)
|
186
|
+
return process_array(exp)
|
187
|
+
end
|
188
|
+
|
194
189
|
##
|
195
190
|
# Argument List including variable types.
|
196
191
|
|
@@ -208,19 +203,12 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
208
203
|
# p TypeMap.methods.sort
|
209
204
|
# p c_type(arg.sexp_type)
|
210
205
|
|
211
|
-
args << "#{c_type(arg.sexp_type)} #{arg.first}"
|
206
|
+
args << "#{self.class.c_type(arg.sexp_type)} #{arg.first}"
|
212
207
|
end
|
213
208
|
|
214
209
|
return "(#{args.join ', '})"
|
215
210
|
end
|
216
211
|
|
217
|
-
##
|
218
|
-
# Arglist is used by call arg lists.
|
219
|
-
|
220
|
-
def process_arglist(exp)
|
221
|
-
return process_array(exp)
|
222
|
-
end
|
223
|
-
|
224
212
|
##
|
225
213
|
# Array is used as call arg lists and as initializers for variables.
|
226
214
|
|
@@ -232,7 +220,7 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
232
220
|
end
|
233
221
|
|
234
222
|
s = code.join ', '
|
235
|
-
s = "
|
223
|
+
s = "rb_ary_new()" if s.empty? # HACK
|
236
224
|
|
237
225
|
return s
|
238
226
|
end
|
@@ -284,17 +272,13 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
284
272
|
args = process exp.shift
|
285
273
|
return "#{receiver} == #{args}" # equal? == address equality
|
286
274
|
when :[]
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
args = process exp.shift
|
293
|
-
return "#{receiver}[#{args}]"
|
294
|
-
end
|
275
|
+
args = process exp.shift
|
276
|
+
return "#{receiver}[#{args}]"
|
277
|
+
when :nil?
|
278
|
+
exp.clear
|
279
|
+
return receiver.to_s
|
295
280
|
else
|
296
281
|
args = process exp.shift
|
297
|
-
name = "NIL_P" if name == :nil?
|
298
282
|
|
299
283
|
if receiver.nil? and args.nil? then
|
300
284
|
args = ""
|
@@ -364,14 +348,21 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
364
348
|
##
|
365
349
|
# Function definition
|
366
350
|
|
367
|
-
|
351
|
+
METHOD_MAP = {
|
352
|
+
:| => "or",
|
353
|
+
:& => "and",
|
354
|
+
:^ => "xor",
|
355
|
+
}
|
368
356
|
|
357
|
+
def process_defn(exp)
|
369
358
|
name = exp.shift
|
359
|
+
name = METHOD_MAP[name] if METHOD_MAP.has_key? name
|
360
|
+
name = name.to_s.sub(/(.*)\?$/, 'is_\1').intern
|
370
361
|
args = process exp.shift
|
371
362
|
body = process exp.shift
|
372
363
|
function_type = exp.sexp_type
|
373
364
|
|
374
|
-
ret_type = c_type function_type.list_type.return_type
|
365
|
+
ret_type = self.class.c_type function_type.list_type.return_type
|
375
366
|
|
376
367
|
@prototypes << "#{ret_type} #{name}#{args};\n"
|
377
368
|
"#{ret_type}\n#{name}#{args} #{body}"
|
@@ -405,10 +396,10 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
405
396
|
end
|
406
397
|
|
407
398
|
##
|
408
|
-
# False. Pretty straightforward.
|
399
|
+
# False. Pretty straightforward.
|
409
400
|
|
410
401
|
def process_false(exp)
|
411
|
-
return "
|
402
|
+
return "0"
|
412
403
|
end
|
413
404
|
|
414
405
|
##
|
@@ -489,8 +480,10 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
489
480
|
|
490
481
|
def process_iter(exp)
|
491
482
|
out = []
|
483
|
+
# Only support enums in C-land
|
484
|
+
raise UnsupportedNodeError if exp[0][1].nil? # HACK ugly
|
492
485
|
@env.scope do
|
493
|
-
enum = exp[0][1][1] # HACK ugly
|
486
|
+
enum = exp[0][1][1] # HACK ugly t(:iter, t(:call, lhs <-- get lhs
|
494
487
|
call = process exp.shift
|
495
488
|
var = process(exp.shift).intern # semi-HACK-y
|
496
489
|
body = process exp.shift
|
@@ -500,8 +493,8 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
500
493
|
body.gsub!(/\n\n+/, "\n")
|
501
494
|
|
502
495
|
out << "unsigned long #{index};"
|
503
|
-
out << "for (#{index} = 0; #{index}
|
504
|
-
out << "#{c_type @env.lookup(var)} #{var} = #{enum}
|
496
|
+
out << "for (#{index} = 0; #{enum}[#{index}] != NULL; ++#{index}) {"
|
497
|
+
out << "#{self.class.c_type @env.lookup(var)} #{var} = #{enum}[#{index}];"
|
505
498
|
out << body
|
506
499
|
out << "}"
|
507
500
|
end
|
@@ -534,7 +527,7 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
534
527
|
|
535
528
|
exp_type = exp.sexp_type
|
536
529
|
@env.add var.to_sym, exp_type
|
537
|
-
var_type = c_type exp_type
|
530
|
+
var_type = self.class.c_type exp_type
|
538
531
|
|
539
532
|
if exp_type.list? then
|
540
533
|
assert_type args, :array
|
@@ -543,13 +536,12 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
543
536
|
|
544
537
|
# HACK: until we figure out properly what to do w/ zarray
|
545
538
|
# before we know what its type is, we will default to long.
|
546
|
-
array_type = args.sexp_types.empty? ? '
|
539
|
+
array_type = args.sexp_types.empty? ? 'void *' : self.class.c_type(args.sexp_types.first)
|
547
540
|
|
548
|
-
args.shift
|
549
|
-
out << "#{var}
|
550
|
-
out << "#{var}.contents = (#{array_type}*) malloc(sizeof(#{array_type}) * #{var}.length);\n"
|
541
|
+
args.shift # :arglist
|
542
|
+
out << "#{var} = (#{array_type}) malloc(sizeof(#{array_type}) * #{args.length});\n"
|
551
543
|
args.each_with_index do |o,i|
|
552
|
-
out << "#{var}
|
544
|
+
out << "#{var}[#{i}] = #{process o};\n"
|
553
545
|
end
|
554
546
|
else
|
555
547
|
out << "#{var} = #{process args}"
|
@@ -574,7 +566,7 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
574
566
|
when Type.long, Type.float then
|
575
567
|
return value.to_s
|
576
568
|
when Type.symbol then
|
577
|
-
return
|
569
|
+
return value.to_s.inspect
|
578
570
|
else
|
579
571
|
raise "Bug! no: Unknown literal #{value}:#{value.class}"
|
580
572
|
end
|
@@ -594,7 +586,7 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
594
586
|
# Nil, currently ruby nil, not C NULL (0).
|
595
587
|
|
596
588
|
def process_nil(exp)
|
597
|
-
return "
|
589
|
+
return "NULL"
|
598
590
|
end
|
599
591
|
|
600
592
|
##
|
@@ -642,7 +634,7 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
642
634
|
@env.scope do
|
643
635
|
body = process exp.shift unless exp.empty?
|
644
636
|
@env.current.sort_by { |v,t| v.to_s }.each do |var, var_type|
|
645
|
-
var_type = c_type var_type
|
637
|
+
var_type = self.class.c_type var_type
|
646
638
|
declarations << "#{var_type} #{var};\n"
|
647
639
|
end
|
648
640
|
end
|
@@ -658,10 +650,10 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
658
650
|
end
|
659
651
|
|
660
652
|
##
|
661
|
-
# Truth... what is truth?
|
653
|
+
# Truth... what is truth?
|
662
654
|
|
663
655
|
def process_true(exp)
|
664
|
-
return "
|
656
|
+
return "1"
|
665
657
|
end
|
666
658
|
|
667
659
|
##
|
@@ -676,5 +668,4 @@ typedef struct { unsigned long length; str * contents; } str_array;
|
|
676
668
|
code = "{\n#{body.strip}\n} while (#{cond})" unless is_precondition
|
677
669
|
return code
|
678
670
|
end
|
679
|
-
|
680
671
|
end
|