ruby2c 1.0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,382 @@
1
+
2
+ $TESTING = false unless defined? $TESTING
3
+
4
+ begin require 'rubygems'; rescue LoadError; end
5
+ require 'ruby_to_ansi_c'
6
+
7
+ class RubyToRubyC < RubyToAnsiC
8
+
9
+ ##
10
+ # Lazy initializer for the composite RubytoC translator chain.
11
+
12
+ def self.translator
13
+ # TODO: FIX, but write a test first
14
+ unless defined? @translator then
15
+ @translator = CompositeSexpProcessor.new
16
+ @translator << Rewriter.new
17
+ @translator << TypeChecker.new
18
+ @translator << CRewriter.new
19
+ @translator << RubyToRubyC.new
20
+ @translator.on_error_in(:defn) do |processor, exp, err|
21
+ result = processor.expected.new
22
+ case result
23
+ when Array then
24
+ result << :error
25
+ end
26
+ msg = "// ERROR: #{err.class}: #{err}"
27
+ msg += " in #{exp.inspect}" unless exp.nil? or $TESTING
28
+ msg += " from #{caller.join(', ')}" unless $TESTING
29
+ result << msg
30
+ result
31
+ end
32
+ end
33
+ @translator
34
+ end
35
+
36
+ def self.c_type(x)
37
+ "VALUE"
38
+ end
39
+
40
+ def initialize
41
+ super
42
+
43
+ self.unsupported -= [:dstr, :dxstr, :xstr]
44
+
45
+ @c_klass_name = nil
46
+ @current_klass = nil
47
+ @klass_name = nil
48
+ @methods = {}
49
+ end
50
+
51
+ def process_call(exp)
52
+ receiver = process(exp.shift) || "self"
53
+ name = exp.shift.to_s
54
+ arg_count = exp.first.size - 1 rescue 0
55
+ args = process(exp.shift) # TODO: we never ever test multiple arguments!
56
+
57
+ # TODO: eric is a big boner
58
+ return "NIL_P(#{receiver})" if name == "nil?"
59
+
60
+ name = '===' if name =~ /^case_equal_/ # undo the evils of TypeChecker
61
+
62
+ if args.empty? || args == "rb_ary_new()" then # HACK
63
+ args = "0"
64
+ else
65
+ args = "#{arg_count}, #{args}"
66
+ end
67
+
68
+ "rb_funcall(#{receiver}, rb_intern(#{name.inspect}), #{args})"
69
+ end
70
+
71
+ # TODO: pull process_const from obfuscator
72
+ # TODO: pull process_colon2 from obfuscator
73
+ # TODO: pull process_cvar from obfuscator
74
+ # TODO: pull process_dasgn_curr from obfuscator
75
+
76
+ ##
77
+ # Function definition
78
+
79
+ def process_defn(exp)
80
+ make_function exp
81
+ end
82
+
83
+ def process_defx(exp)
84
+ make_function exp, false
85
+ end
86
+
87
+ ##
88
+ # String interpolation
89
+
90
+ def process_dstr(exp)
91
+ parts = []
92
+ parts << process(s(:str, exp.shift))
93
+ until exp.empty? do
94
+ parts << process(exp.shift)
95
+ end
96
+
97
+ pattern = process(s(:str, "%s" * parts.length))
98
+ parts.unshift pattern
99
+
100
+ return %{rb_funcall(rb_mKernel, rb_intern("sprintf"), #{parts.length}, #{parts.join(", ")})}
101
+ end
102
+
103
+ ##
104
+ # Backtick interpolation.
105
+
106
+ def process_dxstr(exp)
107
+ dstr = process_dstr exp
108
+ return "rb_funcall(rb_mKernel, rb_intern(\"`\"), 1, #{dstr})"
109
+ end
110
+
111
+ ##
112
+ # False. Pretty straightforward.
113
+
114
+ def process_false(exp)
115
+ "Qfalse"
116
+ end
117
+
118
+ # TODO: pull up process_gasgn from obfuscator
119
+
120
+ ##
121
+ # Global variables, evil but necessary.
122
+
123
+ def process_gvar(exp)
124
+ var = exp.shift
125
+ "rb_gv_get(#{var.to_s.inspect})"
126
+ end
127
+
128
+ # TODO: pull hash from obfuscator
129
+ # TODO: pull iasgn from obfuscator
130
+ # TODO: pull ivar from obfuscator
131
+
132
+ ##
133
+ # Iterators for loops. After rewriter nearly all iter nodes
134
+ # should be able to be interpreted as a for loop. If not, then you
135
+ # are doing something not supported by C in the first place.
136
+
137
+ def process_OLD_iter(exp) # TODO/REFACTOR: audit against obfuscator
138
+ out = []
139
+ # Only support enums in C-land
140
+ raise UnsupportedNodeError if exp[0][1].nil? # HACK ugly
141
+ @env.scope do
142
+ enum = exp[0][1][1] # HACK ugly t(:iter, t(:call, lhs <-- get lhs
143
+ call = process exp.shift
144
+ var = process(exp.shift).intern # semi-HACK-y
145
+ body = process exp.shift
146
+ index = "index_#{var}"
147
+
148
+ body += ";" unless body =~ /[;}]\Z/
149
+ body.gsub!(/\n\n+/, "\n")
150
+
151
+ out << "unsigned long #{index};"
152
+ out << "unsigned long arrays_max = FIX2LONG(rb_funcall(arrays, rb_intern(\"size\"), 0));"
153
+ out << "for (#{index} = 0; #{index} < arrays_max; ++#{index}) {"
154
+ out << "VALUE x = rb_funcall(arrays, rb_intern(\"at\"), 1, LONG2FIX(index_x));"
155
+ out << body
156
+ out << "}"
157
+ end
158
+
159
+ return out.join("\n")
160
+ end
161
+
162
+ ##
163
+ # Iterators for loops. After rewriter nearly all iter nodes
164
+ # should be able to be interpreted as a for loop. If not, then you
165
+ # are doing something not supported by C in the first place.
166
+ #--
167
+ # TODO have CRewriter handle generating lasgns for statics
168
+
169
+ def process_iter(exp)
170
+ call = exp.shift
171
+ args = exp.shift
172
+ block_method = exp.shift
173
+
174
+ iterable = process call[1] # t(:call, lhs, :iterable, rhs)
175
+
176
+ # t(:args, t(:array, of frees), t(:array, of statics))
177
+ free_arg_exps = args[1]
178
+ static_arg_exps = args[2]
179
+ free_arg_exps.shift # :array
180
+ static_arg_exps.shift # :array
181
+
182
+ free_args = free_arg_exps.zip(static_arg_exps).map { |f,s| [process(f), process(s)] }
183
+
184
+ out = []
185
+
186
+ # save
187
+ out.push(*free_args.map { |free,static| "#{static} = #{free};" })
188
+
189
+ out << "rb_iterate(rb_each, #{iterable}, #{block_method}, Qnil);"
190
+
191
+ # restore
192
+ free_args.each do |free, static|
193
+ out << "#{free} = #{static};"
194
+ statics << "static VALUE #{static};"
195
+ end
196
+
197
+ return out.join("\n")
198
+ end
199
+
200
+ ##
201
+ # Assignment to a local variable.
202
+ #
203
+ # TODO: figure out array issues and clean up.
204
+
205
+ def process_lasgn(exp) # TODO: audit against obfuscator
206
+ out = ""
207
+
208
+ var = exp.shift
209
+ value = exp.shift
210
+ # grab the size of the args, if any, before process converts to a string
211
+ arg_count = 0
212
+ arg_count = value.length - 1 if value.first == :array
213
+ args = value
214
+
215
+ exp_type = exp.sexp_type
216
+ @env.add var.to_sym, exp_type
217
+ var_type = self.class.c_type exp_type
218
+
219
+ if exp_type.list? then
220
+ assert_type args, :array
221
+
222
+ raise "array must be of one type" unless args.sexp_type == Type.homo
223
+
224
+ args.shift # :arglist
225
+ # REFACTOR: this (here down) is the only diff w/ super
226
+ out << "#{var} = rb_ary_new2(#{args.length});\n"
227
+ args.each_with_index do |o,i|
228
+ out << "rb_ary_store(#{var}, #{i}, #{process o});\n"
229
+ end
230
+ else
231
+ out << "#{var} = #{process args}"
232
+ end
233
+
234
+ out.sub!(/;\n\Z/, '')
235
+
236
+ return out
237
+ end
238
+
239
+ ##
240
+ # Literals, numbers for the most part. Will probably cause
241
+ # compilation errors if you try to translate bignums and other
242
+ # values that don't have analogs in the C world. Sensing a pattern?
243
+
244
+ def process_lit(exp)
245
+ # TODO: audit against obfuscator
246
+ value = exp.shift
247
+ case value
248
+ when Integer then
249
+ return "LONG2NUM(#{value})"
250
+ when Float then
251
+ return "rb_float_new(#{value})"
252
+ when Symbol
253
+ return "ID2SYM(rb_intern(#{value.to_s.inspect}))"
254
+ when Range
255
+ f = process_lit [ value.first ]
256
+ l = process_lit [ value.last ]
257
+ x = 0
258
+ x = 1 if value.exclude_end?
259
+
260
+ return "rb_range_new(#{f}, #{l}, #{x})"
261
+ when Regexp
262
+ src = value.source
263
+ return "rb_reg_new(#{src.inspect}, #{src.size}, #{value.options})"
264
+ else
265
+ raise "Bug! no: Unknown literal #{value}:#{value.class}"
266
+ end
267
+ return nil
268
+ end
269
+
270
+ # TODO: pull match/2/3 from obfuscator
271
+ # TODO: pull next from obfuscator (and modify for iters)
272
+
273
+ # TODO: process_not?!? wtf? I don't think the ansi not works
274
+
275
+ ##
276
+ # Nil, currently ruby nil, not C NULL (0).
277
+
278
+ def process_nil(exp)
279
+ return "Qnil"
280
+ end
281
+
282
+ ##
283
+ # Strings. woot.
284
+
285
+ def process_str(exp)
286
+ return "rb_str_new2(#{exp.shift.inspect})"
287
+ end
288
+
289
+ ##
290
+ # Truth... what is truth? In this case, Qtrue.
291
+
292
+ def process_true(exp)
293
+ "Qtrue"
294
+ end
295
+
296
+ ##
297
+ # Backtick. Maps directly to Kernel#`, no overriding.
298
+
299
+ def process_xstr(exp)
300
+ command = exp.shift
301
+ return "rb_funcall(rb_mKernel, rb_intern(\"`\"), 1, rb_str_new2(#{command.inspect}))"
302
+ end
303
+
304
+ # TODO: pull while from obfuscator
305
+ # TODO: pull zsuper from obfuscator
306
+
307
+ ##
308
+ # Makes a new function from +exp+. Registers the function in the method
309
+ # list and adds self to the signature when +register+ is true.
310
+
311
+ def make_function(exp, register = true)
312
+ name = map_name exp.shift
313
+ args = exp.shift
314
+ ruby_args = args.deep_clone
315
+ ruby_args.shift # :args
316
+
317
+ @method_name = name
318
+ @c_method_name = "rrc_c#{@c_klass_name}_#{normal_to_C name}"
319
+
320
+ @env.scope do
321
+ c_args = check_args args, register # registered methods get self
322
+ @methods[name] = ruby_args if register
323
+
324
+ body = process exp.shift
325
+
326
+ if name == :initialize then
327
+ body[-1] = "return self;\n}"
328
+ end
329
+
330
+ return "static VALUE\n#{@c_method_name}#{c_args} #{body}"
331
+ end
332
+ end
333
+
334
+ ##
335
+ # Checks +args+ for unsupported variable types. Adds self when +add_self+
336
+ # is true.
337
+
338
+ def check_args(args, add_self = true)
339
+ c_args = process args
340
+
341
+ # HACK
342
+ # c_args.each do |arg|
343
+ # raise UnsupportedNodeError,
344
+ # "'#{arg}' is not a supported variable type" if arg.to_s =~ /^\*/
345
+ # end
346
+
347
+ if add_self then
348
+ if c_args == '()' then
349
+ c_args = '(VALUE self)'
350
+ else
351
+ c_args.sub! '(', '(VALUE self, '
352
+ end
353
+ end
354
+
355
+ return c_args
356
+ end
357
+
358
+ ##
359
+ # HACK merge with normal_to_C (?)
360
+
361
+ def map_name(name)
362
+ # HACK: get from zentest
363
+ name = METHOD_MAP[name] if METHOD_MAP.has_key? name
364
+ name.to_s.sub(/(.*)\?$/, 'is_\1').intern
365
+ end
366
+
367
+ ##
368
+ # DOC
369
+ # TODO: get mappings from zentest
370
+
371
+ def normal_to_C(name)
372
+ name = name.to_s.dup
373
+
374
+ name.sub!(/==$/, '_equals2')
375
+ name.sub!(/=$/, '_equals')
376
+ name.sub!(/\?$/, '_p')
377
+ name.sub!(/\!$/, '_bang')
378
+
379
+ return name
380
+ end
381
+
382
+ end
@@ -0,0 +1,148 @@
1
+
2
+ require 'handle'
3
+ require 'function_type'
4
+
5
+ class Type
6
+
7
+ # REFACTOR: nuke this
8
+ KNOWN_TYPES = {
9
+ :bool => "Bool",
10
+ :bool_list => "Bool list",
11
+ :const => "Const",
12
+ :file => "File",
13
+ :float => "Float",
14
+ :float_list => "Float list",
15
+ :function => "Function",
16
+ :long => "Integer",
17
+ :long_list => "Integer list",
18
+ :range => "Range",
19
+ :regexp => "Regular Expression",
20
+ :str => "String",
21
+ :str_list => "String list",
22
+ :symbol => "Symbol",
23
+ :value => "Value",
24
+ :value_list => "Value list",
25
+ :void => "Void",
26
+ :zclass => "Class",
27
+
28
+ :fucked => "Untranslatable type",
29
+ :hetero => "Heterogenous",
30
+ :homo => "Homogenous",
31
+ :unknown => "Unknown",
32
+ :unknown_list => "Unknown list",
33
+ }
34
+
35
+ TYPES = {}
36
+
37
+ def self.function lhs_type, arg_types, return_type = nil
38
+ unless return_type then
39
+ $stderr.puts "\nWARNING: adding Type.unknown for #{caller[0]}" if $DEBUG
40
+ # TODO: gross, maybe go back to the *args version from method_missing
41
+ return_type = arg_types
42
+ arg_types = lhs_type
43
+ lhs_type = Type.unknown
44
+ end
45
+
46
+ self.new FunctionType.new(lhs_type, arg_types, return_type)
47
+ end
48
+
49
+ def self.unknown
50
+ self.new :unknown
51
+ end
52
+
53
+ def self.method_missing(type, *args)
54
+ raise "Unknown type Type.#{type} (#{type.inspect})" unless
55
+ Type::KNOWN_TYPES.has_key?(type)
56
+
57
+ if type.to_s =~ /(.*)_list$/ then
58
+ TYPES[type] = self.new($1.intern, true) unless TYPES.has_key?(type)
59
+ return TYPES[type]
60
+ else
61
+ TYPES[type] = self.new(type) unless TYPES.has_key?(type)
62
+ return TYPES[type]
63
+ end
64
+ end
65
+
66
+ def self.unknown_list
67
+ self.new(:unknown, true)
68
+ end
69
+
70
+ attr_accessor :type
71
+ attr_accessor :list
72
+
73
+ def initialize(type, list=false)
74
+ # HACK
75
+ unless KNOWN_TYPES.has_key? type or type.class.name =~ /Type$/ then
76
+ raise "Unknown type Type.new(#{type.inspect})"
77
+ end
78
+ @type = Handle.new type
79
+ @list = list
80
+ end
81
+
82
+ def function?
83
+ not KNOWN_TYPES.has_key? self.type.contents
84
+ end
85
+
86
+ def unknown?
87
+ self.type.contents == :unknown
88
+ end
89
+
90
+ def list?
91
+ @list
92
+ end
93
+
94
+ # REFACTOR: this should be named type, but that'll break code at the moment
95
+ def list_type
96
+ @type.contents
97
+ end
98
+
99
+ def eql?(other)
100
+ return nil unless other.class == self.class
101
+
102
+ other.type == self.type && other.list? == self.list?
103
+ end
104
+
105
+ alias :== :eql?
106
+
107
+ def hash
108
+ type.contents.hash ^ @list.hash
109
+ end
110
+
111
+ def unify(other)
112
+ return other.unify(self) if Array === other
113
+ return self if other == self and (not self.unknown?)
114
+ return self if other.nil?
115
+ if self.unknown? and other.unknown? then
116
+ # link types between unknowns
117
+ self.type = other.type
118
+ self.list = other.list? or self.list? # HACK may need to be tri-state
119
+ elsif self.unknown? then
120
+ # other's type is now my type
121
+ self.type.contents = other.type.contents
122
+ self.list = other.list?
123
+ elsif other.unknown? then
124
+ # my type is now other's type
125
+ other.type.contents = self.type.contents
126
+ other.list = self.list?
127
+ elsif self.function? and other.function? then
128
+ self_fun = self.type.contents
129
+ other_fun = other.type.contents
130
+
131
+ self_fun.unify_components other_fun
132
+ else
133
+ raise TypeError, "Unable to unify #{self.inspect} with #{other.inspect}"
134
+ end
135
+ return self
136
+ end
137
+
138
+ def to_s
139
+ str = "Type.#{self.type.contents}"
140
+ str << "_list" if self.list?
141
+ str
142
+ end
143
+
144
+ def inspect
145
+ to_s
146
+ end unless $DEBUG
147
+
148
+ end