Class: RubyToRubyC

Inherits:
RubyToAnsiC show all
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

#env, #prototypes

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from RubyToAnsiC

#no, #preamble, #process_and, #process_arglist, #process_args, #process_array, #process_block, #process_class, #process_const, #process_cvar, #process_dasgn_curr, #process_defn, #process_dummy, #process_dvar, #process_error, #process_hash, #process_iasgn, #process_if, #process_ivar, #process_lvar, #process_not, #process_op_asgn_or, #process_or, #process_return, #process_scope, #process_while, translate, translate_all_of

Constructor Details

#initializeRubyToRubyC

:nodoc:



40
41
42
# File 'lib/ruby_to_ruby_c.rb', line 40

def initialize # :nodoc:
  super
end

Class Method Details

.c_type(x) ⇒ Object



36
37
38
# File 'lib/ruby_to_ruby_c.rb', line 36

def self.c_type(x)
  "VALUE"
end

.translatorObject

Lazy initializer for the composite RubytoC translator chain.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ruby_to_ruby_c.rb', line 12

def self.translator
  # TODO: FIX, but write a test first
  unless defined? @translator then
    @translator = CompositeSexpProcessor.new
    @translator << Rewriter.new
    @translator << TypeChecker.new
    @translator << R2CRewriter.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

#process_call(exp) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/ruby_to_ruby_c.rb', line 44

def process_call(exp)
  receiver = process(exp.shift) || "self"
  name = exp.shift.to_s
  args = [process(exp.shift)].flatten.compact

  name = '===' if name =~ /^case_equal_/ # undo the evils of TypeChecker

  if args.empty?
    args = "0"
  else
    args = "#{args.size}, #{args.join(", ")}"
  end

  "rb_funcall(#{receiver}, rb_intern(#{name.inspect}), #{args})"
end

#process_false(exp) ⇒ Object



60
61
62
# File 'lib/ruby_to_ruby_c.rb', line 60

def process_false(exp)
  "Qfalse"
end

#process_gvar(exp) ⇒ Object



64
65
66
67
# File 'lib/ruby_to_ruby_c.rb', line 64

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.

Raises:

  • (UnsupportedNodeError)


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/ruby_to_ruby_c.rb', line 74

def process_iter(exp)
  out = []
  # Only support enums in C-land
  raise UnsupportedNodeError if exp[0][1].nil? # HACK ugly
  @env.scope do
    enum = exp[0][1][1] # HACK ugly t(:iter, t(:call, lhs <-- get lhs
    call = process exp.shift
    var  = process(exp.shift).intern # semi-HACK-y
    body = process exp.shift
    index = "index_#{var}"

    body += ";" unless body =~ /[;}]\Z/
    body.gsub!(/\n\n+/, "\n")

    out << "unsigned long #{index};"
    out << "unsigned long arrays_max = FIX2LONG(rb_funcall(arrays, rb_intern(\"size\"), 0));"
    out << "for (#{index} = 0; #{index} < arrays_max; ++#{index}) {"
    out << "VALUE x = rb_funcall(arrays, rb_intern(\"at\"), 1, LONG2FIX(index_x));"
    out << body
    out << "}"
  end

  return out.join("\n")
end

#process_lasgn(exp) ⇒ Object

Assignment to a local variable.

TODO: figure out array issues and clean up.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/ruby_to_ruby_c.rb', line 104

def process_lasgn(exp)
  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.sexp_type
  @env.add var.to_sym, exp_type
  var_type = self.class.c_type exp_type

  if exp_type.list? then
    assert_type args, :array

    raise "array must be of one type" unless args.sexp_type == Type.homo

    args.shift # :arglist
    out << "#{var} = rb_ary_new2(#{args.length});\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.sub!(/;\n\Z/, '')

  return out
end

#process_lit(exp) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/ruby_to_ruby_c.rb', line 137

def process_lit(exp)
  value = exp.shift

  case value
  when Fixnum then
    "LONG2NUM(#{value})"
  when Float then
    "DBL2NUM(#{value})"
  when Symbol then
    "rb_intern(#{value.to_s.inspect})"
  else
    raise "Bug! no: Unknown literal #{value}:#{value.class}"
  end
end

#process_nil(exp) ⇒ Object

Nil, currently ruby nil, not C NULL (0).



155
156
157
# File 'lib/ruby_to_ruby_c.rb', line 155

def process_nil(exp)
  return "Qnil"
end

#process_str(exp) ⇒ Object



159
160
161
162
# File 'lib/ruby_to_ruby_c.rb', line 159

def process_str(exp)
  value = exp.shift
  "rb_str_new2(#{value.inspect})"
end

#process_true(exp) ⇒ Object



164
165
166
# File 'lib/ruby_to_ruby_c.rb', line 164

def process_true(exp)
  "Qtrue"
end