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 +69 -0
- data/Makefile +49 -0
- data/Manifest.txt +98 -0
- data/README.txt +75 -0
- data/demo/char.rb +13 -0
- data/demo/factorial.rb +11 -0
- data/demo/hello.rb +11 -0
- data/demo/misc.rb +25 -0
- data/demo/newarray.rb +11 -0
- data/demo/strcat.rb +12 -0
- data/rewrite.rb +32 -0
- data/rewriter.rb +356 -0
- data/ruby_to_c.rb +680 -0
- data/support.rb +317 -0
- data/test_all.rb +9 -0
- data/test_extras.rb +143 -0
- data/test_rewriter.rb +292 -0
- data/test_ruby_to_c.rb +533 -0
- data/test_support.rb +525 -0
- data/test_type_checker.rb +838 -0
- data/test_typed_sexp_processor.rb +134 -0
- data/translate.rb +31 -0
- data/type.rb +33 -0
- data/type_checker.rb +922 -0
- data/typed_sexp_processor.rb +88 -0
- data/validate.sh +49 -0
- data/zcomparable.rb +300 -0
- metadata +74 -0
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
data/demo/factorial.rb
ADDED
data/demo/hello.rb
ADDED
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
data/demo/strcat.rb
ADDED
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
|
+
|