Class: Cplus2Ruby::WrapperCodeGenerator

Inherits:
CodeGenerator show all
Defined in:
lib/cplus2ruby/wrapper_code_generator.rb

Instance Method Summary collapse

Methods inherited from CodeGenerator

#all_methods_of, #all_properties_of, #args_convertable?, #arity, #initialize, #no_wrap?, #wrap?, #write_out

Constructor Details

This class inherits a constructor from Cplus2Ruby::CodeGenerator

Instance Method Details

#gen_allocator(klass) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 4

def gen_allocator(klass)
  %[
    static VALUE
    #{klass.name}_alloc__(VALUE klass)
    {
      #{klass.name} *__cobj__;
      __cobj__ = new #{klass.name}();
      __cobj__->__obj__ = Data_Wrap_Struct(klass, RubyObject::__mark, RubyObject::__free, __cobj__);
      return __cobj__->__obj__;
    }
  ]
end

#gen_init(mod_name) ⇒ Object



100
101
102
103
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
136
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 100

def gen_init(mod_name)
  out = ""
  out << %[extern "C" void Init_#{mod_name}()\n]
  out << "{\n"
  out << "  VALUE klass;\n"

  @model.entities_ordered.each do |klass| 
    next if no_wrap?(klass)
    n = klass.name
    out << %{  klass = rb_eval_string("#{n}");\n}
    out << %{  rb_define_alloc_func(klass, #{n}_alloc__);\n}

    all_methods_of(klass) do |name, options|
      args = options[:arguments]
      next unless args_convertable?(args)
      next if options[:stub]
      out << %{  rb_define_method(klass, "#{name}", } 
      out << %{(VALUE(*)(...))#{n}_wrap__#{name}, #{arity(args)});\n}
    end

    all_properties_of(klass) do |name, options|
      next unless @model.typing.can_convert?(options[:type])

      # getter
      out << %{  rb_define_method(klass, "#{name}", } 
      out << %{(VALUE(*)(...))#{n}_get__#{name}, 0);\n}

      # setter
      out << %{rb_define_method(klass, "#{name}=", } 
      out << %{(VALUE(*)(...))#{n}_set__#{name}, 1);\n}
    end
  end

  out << "}\n"

  return out
end

#gen_method_wrapper(klass, name, options) ⇒ Object



17
18
19
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 17

def gen_method_wrapper(klass, name, options)
  gen_wrapper(klass, name, options, :wrap)
end

#gen_property_accessor(klass, name, options) ⇒ Object



33
34
35
36
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 33

def gen_property_accessor(klass, name, options)
  [gen_property_getter(klass, name, options),
   gen_property_setter(klass, name, options)].join
end

#gen_property_getter(klass, name, options) ⇒ Object



21
22
23
24
25
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 21

def gen_property_getter(klass, name, options)
  opts = options.dup
  opts[:arguments] = {:returns => options[:type]}
  gen_wrapper(klass, name, opts, :get)
end

#gen_property_setter(klass, name, options) ⇒ Object



27
28
29
30
31
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 27

def gen_property_setter(klass, name, options)
  opts = options.dup
  opts[:arguments] = {:__val__ => options[:type]}
  gen_wrapper(klass, name, opts, :set)
end

#gen_wrapper(klass, name, options, kind) ⇒ Object

kind is one of :set, :get, :wrap



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 41

def gen_wrapper(klass, name, options, kind)
  args = options[:arguments].dup
  return nil if options[:stub]
  unless args_convertable?(args)
    STDERR.puts "WARN: cannot wrap method #{klass.name}::#{name} (#{kind})"
    return nil
  end

  returns = args.delete(:returns) || "void"

  s = ([["__self__", "VALUE"]] + args.to_a).map {|n,_| "VALUE #{n}"}.join(", ")

  out = ""
  out << "static VALUE\n"
  out << "#{klass.name}_#{kind}__#{name}(#{s})\n"
  out << "{\n"

  # declare C++ return value
  if returns != 'void'
    out << @model.typing.var_decl(returns, '__res__') + ";\n"
  end
  
  # declare C++ object reference
  out << "#{klass.name} *__cobj__;\n"
  #out << @model.var_decl(klass, '__cobj__') + ";\n"

  # convert __self__ to C++ object reference (FIXME: can remove?)
  out << "Check_Type(__self__, T_DATA);\n"
  out << "__cobj__ = (#{klass.name}*) DATA_PTR(__self__);\n"

  # check argument types
  out << args.map {|n, t| @model.typing.convert(t, n.to_s, :ruby2c_checktype) + ";\n" }.join

  # call arguments
  call_args = args.map {|n, t| @model.typing.convert(t, n.to_s, :ruby2c)}

  # build method call
  out << "__res__ = " if returns != 'void'
  case kind
  when :wrap
    out << "__cobj__->#{name}(#{call_args.join(', ')});\n"
  when :get
    out << "__cobj__->#{name};\n"
  when :set
    raise ArgumentError if call_args.size != 1
    out << "__cobj__->#{name} = #{call_args.first};\n"
  else
    raise ArgumentError
  end

  # convert return value
  retval = @model.typing.convert(returns, '__res__', :c2ruby)

  out << "return #{retval};\n"
  out << "}\n"

  return out
end

#gen_wrapper_file(mod_name) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 138

def gen_wrapper_file(mod_name)
  out = ""
  out << %{#include "#{mod_name}.h"\n\n}

  @model.entities_ordered.each do |klass| 
    next if no_wrap?(klass)

    out << gen_allocator(klass)

    all_methods_of(klass) do |name, options|
      out << (gen_method_wrapper(klass, name, options) || "")
    end

    all_properties_of(klass) do |name, options|
      out << gen_property_accessor(klass, name, options)
    end
  end

  out << gen_init(mod_name)

  return out
end

#write_files(mod_name) ⇒ Object



161
162
163
# File 'lib/cplus2ruby/wrapper_code_generator.rb', line 161

def write_files(mod_name)
  write_out(mod_name + "_wrap.cc", gen_wrapper_file(mod_name))
end