class FFI::Exporter

def attach(mname, fname, result_type, param_types)

def attach(mname, fname, result_type, param_types)
  @functions << { mname: mname, fname: fname, result_type: result_type, params: param_types.dup }
end

def callback(name, cb)

def callback(name, cb)
  @callbacks[name] = cb
end

def dump(out_file)

def dump(out_file)
  File.open(out_file, 'w') do |f|
    guard = File.basename(out_file).upcase.gsub('.', '_').gsub('/', '_')
    f.puts <<-HEADER
def #{guard}
ine #{guard} 1
def RBFFI_EXPORT
def __cplusplus
efine RBFFI_EXPORT extern "C"
se
efine RBFFI_EXPORT
dif
if
    HEADER
    @callbacks.each do |name, cb|
      f.puts "typedef #{cb.name(name)};"
    end
    @structs.each do |s|
      f.puts "struct #{s[:name].gsub('::', '_')} {"
      s[:fields].each do |field|
        if field[:type].is_a?(CallbackInfo)
          type = field[:type].name(field[:name].to_s)
        else
          type = "#{field[:type].name} #{field[:name].to_s}"
        end
        f.puts "#{' ' * 4}#{type};"
      end
      f.puts '};'
      f.puts
    end
    @functions.each do |fn|
      param_string = fn[:params].empty? ? 'void' : fn[:params].map(&:name).join(', ')
      f.puts "RBFFI_EXPORT #{fn[:result_type].name} #{fn[:fname]}(#{param_string});"
    end
    f.puts <<-EPILOG
if /* #{guard} */
    EPILOG
  end
end

def initialize(mod)

def initialize(mod)
  @mod = mod
  @functions = []
  @callbacks = {}
  @structs = []
end

def struct(name, fields)

def struct(name, fields)
  @structs << { name: name, fields: fields.dup }
end