Class: RubyToRubyC
- Inherits:
-
RubyToAnsiC
- Object
- SexpProcessor
- RubyToAnsiC
- RubyToRubyC
- Defined in:
- lib/ruby_to_ruby_c.rb
Constant Summary
Constants inherited from RubyToAnsiC
RubyToAnsiC::METHOD_MAP, RubyToAnsiC::VERSION
Instance Attribute Summary
Attributes inherited from RubyToAnsiC
Class Method Summary collapse
- .c_type(x) ⇒ Object
-
.translator ⇒ Object
Lazy initializer for the composite RubytoC translator chain.
Instance Method Summary collapse
-
#check_args(args, add_self = true) ⇒ Object
Checks
args
for unsupported variable types. -
#initialize ⇒ RubyToRubyC
constructor
A new instance of RubyToRubyC.
-
#make_function(exp, register = true) ⇒ Object
Makes a new function from
exp
. -
#map_name(name) ⇒ Object
HACK merge with normal_to_C (?).
-
#normal_to_C(name) ⇒ Object
DOC TODO: get mappings from zentest.
- #process_call(exp) ⇒ Object
-
#process_defn(exp) ⇒ Object
Function definition.
- #process_defx(exp) ⇒ Object
-
#process_dstr(exp) ⇒ Object
String interpolation.
-
#process_dxstr(exp) ⇒ Object
Backtick interpolation.
-
#process_false(exp) ⇒ Object
False.
-
#process_gvar(exp) ⇒ Object
Global variables, evil but necessary.
-
#process_iter(exp) ⇒ Object
Iterators for loops.
-
#process_lasgn(exp) ⇒ Object
Assignment to a local variable.
-
#process_lit(exp) ⇒ Object
Literals, numbers for the most part.
-
#process_nil(exp) ⇒ Object
Nil, currently ruby nil, not C NULL (0).
-
#process_str(exp) ⇒ Object
Strings.
-
#process_true(exp) ⇒ Object
Truth…
-
#process_xstr(exp) ⇒ Object
Backtick.
Methods inherited from RubyToAnsiC
#no, #preamble, #process, #process_and, #process_arglist, #process_args, #process_array, #process_block, #process_class, #process_const, #process_cvar, #process_dasgn_curr, #process_dummy, #process_dvar, #process_error, #process_iasgn, #process_if, #process_ivar, #process_lvar, #process_not, #process_or, #process_return, #process_scope, #process_static, #process_while, #with_scope
Constructor Details
#initialize ⇒ RubyToRubyC
Returns a new instance of RubyToRubyC.
39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ruby_to_ruby_c.rb', line 39 def initialize super self.unsupported -= [:dstr, :dxstr, :xstr] @c_klass_name = nil @current_klass = nil @klass_name = nil @methods = {} end |
Class Method Details
.c_type(x) ⇒ Object
35 36 37 |
# File 'lib/ruby_to_ruby_c.rb', line 35 def self.c_type(x) "VALUE" end |
.translator ⇒ Object
Lazy initializer for the composite RubytoC translator chain.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/ruby_to_ruby_c.rb', line 11 def self.translator # TODO: FIX, but write a test first unless defined? @translator then @translator = CompositeSexpProcessor.new @translator << Rewriter.new @translator << TypeChecker.new @translator << CRewriter.new @translator << RubyToRubyC.new @translator.on_error_in(:defn) do |processor, exp, err| result = processor.expected.new case result when Array then result << :error end msg = "// ERROR: #{err.class}: #{err}" msg += " in #{exp.inspect}" unless exp.nil? or $TESTING msg += " from #{caller.join(', ')}" unless $TESTING result << msg result end end @translator end |
Instance Method Details
#check_args(args, add_self = true) ⇒ Object
Checks args
for unsupported variable types. Adds self when add_self
is true.
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/ruby_to_ruby_c.rb', line 304 def check_args(args, add_self = true) c_args = process args # HACK # c_args.each do |arg| # raise UnsupportedNodeError, # "'#{arg}' is not a supported variable type" if arg.to_s =~ /^\*/ # end if add_self then if c_args == '()' then c_args = '(VALUE self)' else c_args = c_args.sub '(', '(VALUE self, ' end end return c_args end |
#make_function(exp, register = true) ⇒ Object
Makes a new function from exp
. Registers the function in the method list and adds self to the signature when register
is true.
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/ruby_to_ruby_c.rb', line 277 def make_function(exp, register = true) name = map_name exp.shift args = exp.shift ruby_args = args.deep_clone ruby_args.shift # :args @method_name = name @c_method_name = "rrc_c#{@c_klass_name}_#{normal_to_C name}" @env.scope do c_args = check_args args, register # registered methods get self @methods[name] = ruby_args if register body = process exp.shift if name == :initialize then body[-1] = "return self;\n}" end return "static VALUE\n#{@c_method_name}#{c_args} #{body}" end end |
#map_name(name) ⇒ Object
HACK merge with normal_to_C (?)
327 328 329 330 331 |
# File 'lib/ruby_to_ruby_c.rb', line 327 def map_name(name) # HACK: get from zentest name = METHOD_MAP[name] if METHOD_MAP.has_key? name name.to_s.sub(/(.*)\?$/, 'is_\1').intern end |
#normal_to_C(name) ⇒ Object
DOC TODO: get mappings from zentest
337 338 339 340 341 342 343 344 345 346 |
# File 'lib/ruby_to_ruby_c.rb', line 337 def normal_to_C(name) name = name.to_s.dup name.sub!(/==$/, '_equals2') name.sub!(/=$/, '_equals') name.sub!(/\?$/, '_p') name.sub!(/\!$/, '_bang') return name end |
#process_call(exp) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/ruby_to_ruby_c.rb', line 50 def process_call(exp) receiver = process(exp.shift) || "self" name = exp.shift.to_s arg_count = exp.first.size - 1 rescue 0 args = process(exp.shift) # TODO: we never ever test multiple arguments! # TODO: eric is a big boner return "NIL_P(#{receiver})" if name == "nil?" name = '===' if name =~ /^case_equal_/ # undo the evils of TypeChecker if args.empty? || args == "rb_ary_new()" then # HACK args = "0" else args = "#{arg_count}, #{args}" end "rb_funcall(#{receiver}, rb_intern(#{name.inspect}), #{args})" end |
#process_defn(exp) ⇒ Object
Function definition
78 79 80 |
# File 'lib/ruby_to_ruby_c.rb', line 78 def process_defn(exp) make_function exp end |
#process_defx(exp) ⇒ Object
82 83 84 |
# File 'lib/ruby_to_ruby_c.rb', line 82 def process_defx(exp) make_function exp, false end |
#process_dstr(exp) ⇒ Object
String interpolation
89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/ruby_to_ruby_c.rb', line 89 def process_dstr(exp) parts = [] parts << process(s(:str, exp.shift)) until exp.empty? do parts << process(exp.shift) end pattern = process(s(:str, "%s" * parts.length)) parts.unshift pattern return %{rb_funcall(rb_mKernel, rb_intern("sprintf"), #{parts.length}, #{parts.join(", ")})} end |
#process_dxstr(exp) ⇒ Object
Backtick interpolation.
105 106 107 108 |
# File 'lib/ruby_to_ruby_c.rb', line 105 def process_dxstr(exp) dstr = process_dstr exp return "rb_funcall(rb_mKernel, rb_intern(\"`\"), 1, #{dstr})" end |
#process_false(exp) ⇒ Object
False. Pretty straightforward.
113 114 115 |
# File 'lib/ruby_to_ruby_c.rb', line 113 def process_false(exp) "Qfalse" end |
#process_gvar(exp) ⇒ Object
Global variables, evil but necessary.
122 123 124 125 |
# File 'lib/ruby_to_ruby_c.rb', line 122 def process_gvar(exp) var = exp.shift "rb_gv_get(#{var.to_s.inspect})" end |
#process_iter(exp) ⇒ Object
Iterators for loops. After rewriter nearly all iter nodes should be able to be interpreted as a for loop. If not, then you are doing something not supported by C in the first place. – TODO have CRewriter handle generating lasgns for statics
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/ruby_to_ruby_c.rb', line 138 def process_iter(exp) call = exp.shift args = exp.shift block_method = exp.shift iterable = process call[1] # t(:call, lhs, :iterable, rhs) # t(:args, t(:array, of frees), t(:array, of statics)) free_arg_exps = args[1] static_arg_exps = args[2] free_arg_exps.shift # :array static_arg_exps.shift # :array free_args = free_arg_exps.zip(static_arg_exps).map { |f,s| [process(f), process(s)] } out = [] # save out.push(*free_args.map { |free,static| "#{static} = #{free};" }) out << "rb_iterate(rb_each, #{iterable}, #{block_method}, Qnil);" # restore free_args.each do |free, static| out << "#{free} = #{static};" statics << "static VALUE #{static};" end return out.join("\n") end |
#process_lasgn(exp) ⇒ Object
Assignment to a local variable.
TODO: figure out array issues and clean up.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/ruby_to_ruby_c.rb', line 174 def process_lasgn(exp) # TODO: audit against obfuscator out = [] var = exp.shift value = exp.shift # grab the size of the args, if any, before process converts to a string arg_count = 0 arg_count = value.length - 1 if value.first == :array args = value exp_type = exp.c_type @env.add var.to_sym, exp_type if exp_type.list? then assert_type args, :array raise "array must be of one type" unless args.c_type == CType.homo args.shift # :arglist # REFACTOR: this (here down) is the only diff w/ super out << "#{var} = rb_ary_new2(#{arg_count});\n" args.each_with_index do |o,i| out << "rb_ary_store(#{var}, #{i}, #{process o});\n" end else out << "#{var} = #{process args}" end out.join.sub(/;\n\Z/, '') end |
#process_lit(exp) ⇒ Object
Literals, numbers for the most part. Will probably cause compilation errors if you try to translate bignums and other values that don’t have analogs in the C world. Sensing a pattern?
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/ruby_to_ruby_c.rb', line 210 def process_lit(exp) # TODO: audit against obfuscator value = exp.shift case value when Integer then return "LONG2NUM(#{value})" when Float then return "rb_float_new(#{value})" when Symbol return "ID2SYM(rb_intern(#{value.to_s.inspect}))" when Range f = process_lit [ value.first ] l = process_lit [ value.last ] x = 0 x = 1 if value.exclude_end? return "rb_range_new(#{f}, #{l}, #{x})" when Regexp src = value.source return "rb_reg_new(#{src.inspect}, #{src.size}, #{value.})" else raise "Bug! no: Unknown literal #{value}:#{value.class}" end return nil end |
#process_nil(exp) ⇒ Object
Nil, currently ruby nil, not C NULL (0).
244 245 246 |
# File 'lib/ruby_to_ruby_c.rb', line 244 def process_nil(exp) return "Qnil" end |
#process_str(exp) ⇒ Object
Strings. woot.
251 252 253 |
# File 'lib/ruby_to_ruby_c.rb', line 251 def process_str(exp) return "rb_str_new2(#{exp.shift.inspect})" end |
#process_true(exp) ⇒ Object
Truth… what is truth? In this case, Qtrue.
258 259 260 |
# File 'lib/ruby_to_ruby_c.rb', line 258 def process_true(exp) "Qtrue" end |
#process_xstr(exp) ⇒ Object
Backtick. Maps directly to Kernel#‘, no overriding.
265 266 267 268 |
# File 'lib/ruby_to_ruby_c.rb', line 265 def process_xstr(exp) command = exp.shift return "rb_funcall(rb_mKernel, rb_intern(\"`\"), 1, rb_str_new2(#{command.inspect}))" end |