Mercurial > projects > dstep
diff scripts/dgen.rb @ 2:9fd439a28ce3
Adapted the scripts for the new bridge + a lot more
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Sun, 05 Jul 2009 17:16:19 +0200 |
parents | 033d260cfc9b |
children | d0162d8ca0f2 |
line wrap: on
line diff
--- a/scripts/dgen.rb Thu Jun 18 22:00:13 2009 +0200 +++ b/scripts/dgen.rb Sun Jul 05 17:16:19 2009 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/env ruby ## -# Copyright:: Copyright (c) 2009 Jacob Carlborg. All rights reserved. +# Copyright:: Copyright (c) 2009 Jacob Carlborg. # Author:: Jacob Carlborg # Version:: Initial created: 2009 # License:: [Boost Software License 1.0]http://www.boost.org/LICENSE_1_0.txt @@ -11,6 +11,7 @@ gem "xml-simple" require "xmlsimple" require "optparse" +require "date" # Extensions to String class String @@ -180,8 +181,8 @@ end # This Struct represents a C/Objective-C header -HeaderFile = Struct.new(:name, :framework, :cftypes, :constants, :d_constants, :d_constants_static_this, :defines, - :enums, :functions, :function_wrappers, :imports, :path, :structs, :typedefs) do +HeaderFile = Struct.new(:name, :framework, :cftypes, :constants, :c_constants, :d_constants, :d_constants_static_this, :defines, + :enums, :functions, :c_functions, :function_wrappers, :imports, :path, :structs, :typedefs) do def initialize self.name = "" self.cftypes = [] @@ -190,11 +191,13 @@ self.enums = [] self.framework = "" self.functions = [] + self.c_functions = [] self.function_wrappers = [] self.imports = [] self.path = "" self.structs = [] self.typedefs = [] + self.d_constants_static_this = [] end end @@ -208,12 +211,17 @@ # Creates a new instance of the ObjcToD class def initialize @classes = {} + @interfaces = {} + @interfaces2 = [] + @templates = {} @copyright = nil + @c_constants = [] @d_constants = [] @d_constants_static_this = [] @files = [] @frameworks = [] @function_wrappers = [] + @c_functions = [] @headers = [] @package = "dstep" end @@ -234,10 +242,12 @@ header = HeaderFile.new header.name = file.name header.constants = constants(file.constant) unless file.constant.nil? + header.c_constants = c_constants unless file.constant.nil? header.d_constants = d_constants unless file.constant.nil? header.d_constants_static_this = d_constants_static_this unless file.constant.nil? header.enums = enums(file.enum) unless file.enum.nil? header.functions = functions(file.function) unless file.function.nil? + header.c_functions = c_functions unless file.function.nil? header.function_wrappers = function_wrappers unless file.function.nil? header.imports = imports(file.import, file.name, framework.name) unless file.import.nil? header.structs = structs(file.struct) unless file.struct.nil? @@ -258,10 +268,12 @@ header = HeaderFile.new header.name = file.name header.constants = constants(file.constant) unless file.constant.nil? + header.c_constants = c_constants unless file.constant.nil? header.d_constants = d_constants unless file.constant.nil? header.d_constants_static_this = d_constants_static_this unless file.constant.nil? header.enums = enums(file.enum) unless file.enum.nil? header.functions = functions(file.function) unless file.function.nil? + header.c_functions = c_functions unless file.function.nil? header.function_wrappers = function_wrappers unless file.function.nil? header.imports = imports(file.import, file.name) unless file.import.nil? header.structs = structs(file.struct) unless file.struct.nil? @@ -270,36 +282,41 @@ @headers << header end end - - unless xml["class"].nil? - classes(xml["class"]) - end + + interfaces(xml.protocol) unless xml.protocol.nil? + templates(xml.category) unless xml.category.nil? + classes(xml["class"]) unless xml["class"].nil? end end # Outputs the generate D code def output_code @frameworks.each do |framework| - framework_path = framework_path = "#{@out_dir}/#{@package}/#{framework.name}" + framework_path = framework_path = "#{@out_dir}/#{@package}/#{get_identifier(get_framework_name(framework.name.downcase))}" FileUtils.mkdir_p(framework_path) unless File.exist?(framework_path) framework.files.each do |header| - file_path = "#{framework_path}/#{header.name}.d" + file_path = "#{framework_path}/#{get_identifier(header.name)}" + bindings_file_path = file_path + "_bindings.d" + file_path << ".d" + mod = "#{@package}.#{get_identifier(get_framework_name(framework.name.downcase))}.#{get_identifier(header.name)}" File.open(file_path, "w") do |file| file << copyright - file << "module #{@package}.#{framework.name}.#{header.name};" - file << header.imports.nl(false) + file << "module #{mod};" + file << header.imports + file << "\n" unless @d_constants.length > 0 || @function_wrappers.length > 0 + file << "import bindings = #{mod}_bindings".nl.nl(false) if @d_constants.length > 0 || @function_wrappers.length > 0 file << header.defines file << header.typedefs - file << header.cftypes - file << header.constants + file << header.cftypes + file << header.c_constants file << header.d_constants file << header.enums file << header.structs - unless header.d_constants_static_this.nil? + unless header.d_constants_static_this.length == 0 file << "static this ()".nl(false) file << "{".nl(false) file << header.d_constants_static_this @@ -313,26 +330,54 @@ @classes.delete(clazz) end - file << header.functions + interfaces = get_interfaces(header.name) + + interfaces.each do |interface, value| + file << value.code.nl(false) + @interfaces.delete(interface) + end + + templates = get_templates(header.name) + + templates.each do |template, value| + file << value.code.nl(false) + @templates.delete(template) + end + file << header.function_wrappers + file << header.c_functions end + + File.open(bindings_file_path, "w") do |file| + file << "module " + file << mod + file << "_bindings;" + file << header.imports.nl(false) + file << header.constants + file << header.functions + end if @d_constants.length > 0 || @function_wrappers.length > 0 end end package_path = "#{@out_dir}/#{@package}" FileUtils.mkdir_p(package_path) unless File.exist?(package_path) - @headers.each do |header| - header_path = "#{package_path}/#{header.name}.d" + @headers.each do |header| + header_path = "#{package_path}/#{get_identifier(header.name)}" + bindings_file_path = header_path + "_bindings.d" + header_path << ".d" + mod = "#{@package}.#{get_identifier(header.name)}" File.open(header_path, "w") do |file| file << copyright - file << "module #{@package}.#{header.name};" - file << header.imports.nl(false) + file << "module #{mod};" + file << header.imports + file << "\n" unless @d_constants.length > 0 || @function_wrappers.length > 0 + file << "import bindings = #{mod}_bindings".nl.nl(false) if @d_constants.length > 0 || @function_wrappers.length > 0 file << header.defines file << header.typedefs - file << header.cftypes - file << header.constants + file << header.cftypes + file << header.c_constants file << header.d_constants file << header.enums file << header.structs @@ -350,14 +395,37 @@ file << value.code.nl(false) @classes.delete(clazz) end + + interfaces = get_interfaces(header.name) + + interfaces.each do |interface, value| + file << value.code.nl(false) + @interfaces.delete(interface) + end + + templates = get_templates(header.name) + + templates.each do |template, value| + file << value.code.nl(false) + @templates.delete(template) + end + file << header.function_wrappers + file << header.c_functions + end + + File.open(bindings_file_path, "w") do |file| + file << "module " + file << mod + file << "_bindings;" + file << header.imports.nl(false) + file << header.constants file << header.functions - file << header.function_wrappers - end + end if @d_constants.length > 0 || @function_wrappers.length > 0 end @classes.each do |clazz, value| - class_path = "#{package_path}/#{clazz}.d" + class_path = "#{package_path}/#{get_identifier(clazz)}.d" File.open(class_path, "w") do |file| file << value.code unless value.nil? @@ -395,7 +463,7 @@ def get_framework (class_name) @frameworks.each do |framework| framework.files.each do |file| - return framework.name if file.name == class_name + return get_identifier(framework.name) if file.name == class_name end end @@ -409,70 +477,194 @@ end return classes - end + end + + # Gets the interfaces that belongs to the given file + def get_interfaces (name) + interfaces = @interfaces.find_all do |interface, value| + value.file == name + end + + return interfaces + end + + # Gets the templates that belongs to the given file + def get_templates (name) + templates = @templates.find_all do |template, value| + value.file == name + end + + return templates + end # Generates the D code for the classes def classes (classes) classes.each do |clazz| str = StringIO.new + protocols = [] str << "class " if clazz == "" - str << clazz.name.nl(false) + str << get_identifier(clazz.name).nl(false) else - str << clazz.name - str << " : " - str << clazz.parent.nl(false) + str << get_identifier(clazz.name) + + unless clazz.parent == "" + str << " : " + str << get_identifier(clazz.parent) + end + + unless clazz.protocols.length == 0 + protocols = clazz.protocols.split(",") + + str2 = StringIO.new + + str2 << ", " unless clazz.parent.length == 0 + str2 << " : " if clazz.parent.length == 0 + + protocols.each do |protocol| + str2 << "I" + str2 << get_identifier(protocol) + str2 << ", " + end + + str << str2.string[0 .. -3] + end + + str << "\n" end str << "{".nl(false) + str << "mixin ObjcWrap".indent.nl + + templates_for_class(clazz.name).each do |template, value| + str << "mixin #{template}".indent.nl + end + + str << "\n" + str << methods(clazz.method, clazz.name) + str << "\n" if protocols.length > 0 + + # implement the interfaces/protocols + protocols.each_with_index do |protocol, i| + interface = interface_for_protocol(protocol) + + unless interface.nil? + str << methods(interface.method, interface.name) + str << "\n" unless i == protocols.length - 1 + end + end + str << "}".nl(false) @classes[clazz.name] ||= {} @classes[clazz.name].code = str.string framework = get_framework(clazz.file) @classes[clazz.name].framework = framework unless framework.nil? - @classes[clazz.name].file = clazz.file + @classes[clazz.name].file = get_identifier(clazz.file) + end + end + + # Generates the D code for the interfaces + def interfaces (interfaces) + interfaces.each do |interface| + str = StringIO.new + + str << "interface I" # prepend I to the interface name, because it can be the same as a class name + + if interface == "" + str << get_identifier(interface.name).nl(false) + else + str << get_identifier(interface.name) + + unless interface.parent == "" + str << " : " + str << get_identifier(interface.parent) + end + + unless interface.protocols.length == 0 + protocols = interface.protocols + protocols = protocols.split(",") + + str2 = StringIO.new + + str2 << ", " unless interface.parent.length == 0 + str2 << " : " if interface.parent.length == 0 + + protocols.each do |protocol| + str2 << "I" + str2 << get_identifier(protocol) + str2 << ", " + end + + str << str2.string[0 .. -3] + end + + str << "\n" + end + + str << "{".nl(false) + str << interface_methods(interface.method, interface.name) + str << "}".nl(false) + + @interfaces[interface.name] ||= {} + @interfaces[interface.name].code = str.string + framework = get_framework(interface.file) + @interfaces[interface.name].framework = framework unless framework.nil? + @interfaces[interface.name].file = get_identifier(interface.file) + @interfaces2 << interface + end + end + + # Generates the D code for the templates + def templates (templates) + templates.each do |template| + str = StringIO.new + + str << "template " + str << get_identifier(template.name) + str << " ()".nl(false) + str << "{".nl(false) + str << interface_methods(template.method, template.name) if template["class"] == "NSObject" + str << methods(template.method, template.name) unless template["class"] == "NSObject" + str << "}".nl(false) + + @templates[template.name] ||= {} + @templates[template.name].code = str.string + framework = get_framework(template.file) + @templates[template.name].framework = framework unless framework.nil? + @templates[template.name].file = get_identifier(template.file) + @templates[template.name][:class] = get_identifier(template["class"]) end end # Generates the D code for the constants/globals def constants (constants) + return "" if constants.length == 0 + str = StringIO.new - str << "private extern (C)".nl(false) + str << "extern (C)".nl(false) str << "{".nl(false) str << "extern".indent.nl(false) str << "{".indent.nl(false) constants.each do |constant| - type = get_type(constant.type, constant["type64"], constant["declaredType"]) - const = constant["const"] == "true" + type = get_type(constant.type, constant.type64, constant.declaredType) + const = constant.const == "true" - if constant.type == "@" + if constant.type == "@" @d_constants << { :name => constant.name.dup, :type => constant.declaredType.gsub("*", ""), :const => const } - if const - str << "const id".indent(2) - else - str << "id".indent(2) - end - + str << "private ".indent(2) + str << "const id" if const + str << "id" unless const str << " " - str << constant["name"] - str << "_".nl + str << get_identifier(constant["name"]).nl else - if const - str << "const ".indent(2) - str << type - else - str << "id".indent(2) - end - - str << " " - str << constant["name"].nl + @c_constants << { :name => constant.name.dup, :type => type, :const => const } end end @@ -482,8 +674,40 @@ str.string end + def c_constants + return "" if @c_constants.length == 0 + + str = StringIO.new + + str << "extern (C)".nl(false) + str << "{".nl(false) + str << "extern".indent.nl(false) + str << "{".indent.nl(false) + + @c_constants.each do |constant| + if constant.const + str << "const ".indent(2) + str << constant.type + else + str << constant.type.indent(2) + end + + str << " " + str << get_identifier(constant.name).nl + end + + str << "}".indent.nl(false) + str << "}".nl(false).nl(false) + + @c_constants.clear + str.string + end + + # Generates the D code for the constants that D can't handle directly, like classes def d_constants + return "" if @d_constants.length == 0 + str = StringIO.new @d_constants.each do |constant| @@ -493,9 +717,9 @@ c.type = c.type.dup str << "const " if constant.const - str << constant.type + str << get_identifier(constant.type) str << " " - str << constant.name.nl + str << get_identifier(constant.name).nl @d_constants_static_this << c end @@ -506,15 +730,18 @@ # Generates the D code for the constants the has to be in a "static this" def d_constants_static_this + return "" if @d_constants_static_this.length == 0 + str = StringIO.new @d_constants_static_this.each do |constant| str << constant.name.indent str << " = new " - str << constant.type + str << get_identifier(constant.type) str << "(" - str << constant.name - str << "_)".nl + str << "bindings." + str << get_identifier(constant.name) + str << ")".nl end @d_constants_static_this.clear @@ -523,33 +750,36 @@ # Generates the D code for the enums def enums (enums) + return "" if enums.length == 0 + str = StringIO.new enums.each do |enum| str << "enum" - if enum["name"] == "" - str << "\n{".nl + if enum.name.length == 0 + str << "\n{".nl(false) enum.member.each_with_index do |member, i| - str << member["name"].indent - str << " = " + str << get_identifier(member["name"]).indent + str << " = " if member.value.length > 0 str << member.value str << ",".nl(false) unless i == enum.member.length - 1 end else - str << enum["name"].nl - str << "{" + str << " " + str << get_identifier(enum["name"]).nl(false) + str << "{".nl(false) enum["member"].each_with_index do |member, i| - str << member["name"].indent - str << " = " + str << get_identifier(member["name"]).indent + str << " = " if member.value.length > 0 str << member.value str << ",".nl(false) unless i == enum.member.length - 1 end end - str << "\n}".nl.nl(false) + str << "\n}".nl(false).nl(false) end str.string @@ -573,7 +803,7 @@ str << type str << " " - str << arg["name"] + str << get_identifier(arg["name"]) str << ", " end @@ -590,7 +820,7 @@ # A helper function that generates the D code for the functions/methods def build_function (function, method = false, static = false) str = StringIO.new - variadic = function["variadic"] == "true" + variadic = function.variadic == "true" return_type = "" args = "" original_type = function.returnValue[0].type @@ -615,49 +845,65 @@ # Generates the D code for the functions def functions (functions) - str = StringIO.new + return "" if functions.length == 0 - str << "private extern (C)".nl(false) - str << "{".nl(false) + str = StringIO.new + wrapper_needed = false + + str << "extern (C)".nl(false) + str << "{".nl(false) functions.each do |function| - wrapper_needed = false - original_type = function["returnValue"][0].type + wrapper_needed = false + original_type = function.returnValue[0].type if original_type == "@" @function_wrappers << function wrapper_needed = true + str << functions_helper(function, wrapper_needed) else - function["arg"].each do |arg| - if (arg.type || arg["type64"]) == "@" + function.arg.each do |arg| + if (arg.type || arg.type64) == "@" @function_wrappers << function wrapper_needed = true + break end - end unless function["arg"].nil? + end unless function.arg.nil? + + str << functions_helper(function, wrapper_needed) if wrapper_needed + @c_functions << function unless wrapper_needed end - - return_type = get_type(function["returnValue"][0].type, function["returnValue"][0]["type64"], function["returnValue"][0]["declaredType"]) - variadic = function["variadic"] == "true" - - str << functions_helper(function, wrapper_needed) end - str << "}".nl(false).nl(false) + str << "}" str.string end + def c_functions + return "" if @c_functions.length == 0 + + str = StringIO.new + + str << "extern (C)".nl(false) + str << "{".nl(false) + + @c_functions.each do |function| + str << functions_helper(function, false) + end + + str << "}" + + @c_functions.clear + str.string + end + + # A helper function that generates the D code for the functions def functions_helper (function, wrapper_needed) str = StringIO.new - - if wrapper_needed - declaration = build_function(function) - index = declaration.index_of(" ") - index = declaration.index_of(" ", index) - str << (declaration[0 ... index] + "_" + declaration[index .. -1]).indent - else - str << build_function(function).indent - end + + str << ("private " + build_function(function)).indent if wrapper_needed + str << build_function(function).indent unless wrapper_needed str.string end @@ -665,113 +911,70 @@ # Generates the D code for the functions that D can't handle without wrappers, like functions that takes # objects as arguments or returns an object def function_wrappers + return "" if @function_wrappers.length == 0 + str = StringIO.new @function_wrappers.each do |function| - original_type = function["returnValue"][0].type - variadic = function["variadic"] == "true" - args = StringIO.new - out_args = [] - return_type = get_type(original_type, function.returnValue[0].type64, function.returnValue[0].declaredType) - - function["arg"].each do |arg| - args << arg["name"] - - if arg.type == "@" - args << " !is null ? " - args << arg["name"] - args << ".id : null" - elsif arg.type == "^@" - type = get_type(arg.type, arg["type64"], arg["declaredType"]) - out_args << { :type => type[4 .. -1], :name => arg["name"] } - - args << " &" - args << arg["name"] - args << "_.id" - end - - args << ", " - end unless function["arg"].nil? - + return_type = get_type(function.returnValue[0].type, function.returnValue[0].type64, function.returnValue[0].declaredType) + variadic = function.variadic == "true" + str << build_function(function, true)[0 ... -2].nl(false) str << "{".nl(false) - - out_args.each do |arg| - str << arg.type.indent - str << " " - str << arg.name - str << "_ = new " - str << arg.type - str << "(false, false)".nl - end - - str << "\n" if out_args.length > 0 - - if original_type == "@" - str << "id result = ".indent - str << function["name"] - elsif original_type != "v" - if out_args.length > 0 - str << return_type.indent - str << " result = " - else - str << "return ".indent - end - end - - if original_type == "v" - str << function["name"].indent - elsif original_type != "@" - str << "cast(" - str << return_type - str << ") " - str << function["name"] - end - - str << "_" - str << "(" - str << args.string[0 ... -2] unless function["arg"].nil? - str << ")".nl - str << "\n" if out_args.length > 0 - - out_args.each do |arg| - str << arg.name.indent(2) - str << " = " - str << arg.name - str << "_".nl - end - - if out_args.length > 0 - str << "\n" - str << "return result".indent unless original_type == "v" + str << "return Bridge.invokeObjcFunction!(".indent + str << return_type + str << ", bindings." + str << function.name + + function.arg.each do |arg| + str << ", " + str << get_type(arg.type, arg.type, arg.declaredType) + end unless function.arg.nil? + + unless function.arg.nil? + str << ")" + str << "(" end - if original_type == "@" - str << "return result !is null ? new ".indent - str << return_type - str << "(result)".nl - elsif original_type != "v" && out_args.length > 0 - str << "".nl - end - + function.arg.each_with_index do |arg, i| + str << arg.name + str << ", " unless i == function.arg.length - 1 + end unless function.arg.nil? + + str << ")".nl + str << "}".nl(false).nl(false) end @function_wrappers.clear - str.string[0 ... -2] + str.string end # Generates the D code for the imports def imports (imports, filename, framework_name = nil) + return "" if imports.length == 0 + str = StringIO.new imports.each do |import| - str << "import #{@package}." - i = import.index('/') - import = import[0 ... i].downcase + import[i .. -1] if i - str << import.gsub("/", ".").gsub("Frameworks", "").gsub(".framework", "").gsub("Headers", "").gsub(/\.{2,}/, ".").nl + str << "import #{@package}." + import = import.gsub("/", ".").gsub("Frameworks", "").gsub(".framework", "").gsub("Headers", "").gsub(/\.{2,}/, ".").nl + + splits = import.split('.') + import = "" + + splits[0 .. -2].each do |s| + import << get_identifier(s.downcase) + import << '.' + end + + str << import + str << splits[-1 .. -1] end + str << "import dstep.objc.bridge.Bridge".nl + str << "import dstep.objc.objc : id".nl + str << "\n\n" str = str.string.sort.to_s @@ -781,225 +984,83 @@ # Generates the D code for the methods def methods (methods, class_name) + return "" if methods.length == 0 + str = StringIO.new - methods.each do |method| - next if method.selector == ("alloc" || "init") - - return_type = get_type(method["returnValue"][0].type, method["returnValue"][0]["type64"], method["returnValue"][0]["declaredType"]) - variadic = method["variadic"] == "true" - static = method["static"] == "true" - args = "" - out_args = [] - original_type = method.returnValue[0].type - - if method.selector[0 ... 4] == "init" && return_type == "id" - return_type = class_name - method.returnValue[0].declaredType = class_name - end + methods.each do |method| + return_type = get_type(method.returnValue[0].type, method.returnValue[0].type64, method.returnValue[0].declaredType) + variadic = method.variadic == "true" + static = method.classMethod == "true" - method["arg"].each do |arg| - args << " &" if arg.type == "^@" - args << arg["name"] - - if arg.type == "@" - args << " !is null ? " - args << arg["name"] - args << ".id : null" - elsif arg.type == "^@" - type = get_type(arg.type, arg.type, arg["declaredType"]) - out_args << { :type => type[4 .. -1], :name => arg["name"] } - args << "_.id" - end - - args << ", " - end unless method["arg"].nil? - + index = 0 declaration = build_function(method, true, static)[0 ... -2].indent.nl(false) - index = declaration.index_of(" ") + index = declaration.index_of(" ") if static + index = declaration.index_of(" ", index) str << (declaration[0 .. index] + get_method_name(method["selector"]) + declaration[index .. -1]).gsub(/ +/, " ") str << "{".indent.nl(false) + str << "return invokeObjcSelf!(".indent(2) unless static + str << "return invokeObjcSelfClass!(".indent(2) if static + str << return_type + str << ', "' + str << method.selector + str << '"' - out_args.each do |arg| - str << arg.type.indent(2) - str << " " - str << arg.name - str << "_ = new " - str << arg.type - str << "(false, false)".nl + method.arg.each do |arg| + str << ", " + str << get_type(arg.type, arg.type, arg.declaredType) + end unless method.arg.nil? + + unless method.arg.nil? + str << ")" + str << "(" end - str << "\n" if out_args.length > 0 - + method.arg.each_with_index do |arg, i| + str << arg.name + str << ", " unless i == method.arg.length - 1 + end unless method.arg.nil? - if method["returnValue"][0].type == "@" - str << "id result = objc_msgSend(#{this}, sel_".indent(2) - str << transform_selector(method["selector"]) - str << ", " unless method.arg.nil? - str << args[0 ... -2] unless method.arg.nil? - str << ")".nl - str << "\n" if out_args.length > 0 - - out_args.each do |arg| - str << arg.name.indent(2) - str << " = " - str << arg.name - str << "_".nl - end - - str << "\n" if out_args.length > 0 - - if method["returnValue"][0]["declaredType"] == class_name - str << "return result is this.id ? this : (return result ".indent(2) - else - str << "return result ".indent(2) - end - - str << "!is null ? new " - str << return_type - str << "(result) : null" - - if method["returnValue"][0]["declaredType"] == class_name - str << ")".nl - else - str << "".nl - end - - str << "}".indent.nl(false).nl(false) - else - if original_type == "d" || original_type == "f" - - str << "version (X86)".indent(2).nl(false) - - if out_args.length > 0 - str << return_type.indent(3) - str << " result " - else - if original_type == "d" - str << "return ".indent(3) - else - str << "return cast(".indent(3) - str << return_type - str << ") " - end - end - - str << "objc_msgSend_fpret(#{this}, sel_" - str << transform_selector(method["selector"]) - str << ", " unless method.arg.nil? - - args = "" - - method["arg"].each do |arg| - args << arg["name"] - args << ", " - end unless method["arg"].nil? - - str << args[0 ... -2] if args.length > 0 - str << ")".nl.nl(false) - - str << "else".indent(2).nl(false) - - if out_args.length > 0 - str << return_type.indent(3) - str << " result " - else - if original_type == "d" - str << "return ".indent(3) - else - str << "return cast(".indent(3) - str << return_type - str << ") " - end - end - - str << "objc_msgSend(#{this}, sel_" - str << transform_selector(method["selector"]) - str << ", " unless method.arg.nil? - - args = "" - - method["arg"].each do |arg| - args << arg["name"] - args << ", " - end unless method["arg"].nil? - - str << args[0 ... -2] if args.length > 0 - str << ")".nl - str << "\n" if out_args.length > 0 - - out_args.each do |arg| - str << arg.name.indent(3) - str << " = " - str << arg.name - str << "_".nl - end - - if out_args.length > 0 - str << "\n" - str << "retrun result".indent(3).nl - end - - str << "\n" if out_args.length > 0 - str << "}".indent.nl(false).nl(false) - else - unless return_type == "void" - if out_args.length > 0 - str << return_type.indent(2) - str << " result " - else - str << "return cast(".indent(2) - end - - str << return_type - str << ") " - end - - str << "objc_msgSend(#{this}, sel_".indent(2) if return_type == "void" - str << "objc_msgSend(#{this}, sel_" unless return_type == "void" - str << transform_selector(method["selector"]) - str << ", " unless method.arg.nil? - - args = "" - - method["arg"].each do |arg| - args << arg["name"] - args << ", " - end unless method["arg"].nil? - - str << args[0 ... -2] if args.length > 0 - str << ")".nl - - str << "\n" if out_args.length > 0 - - out_args.each do |arg| - str << arg.name.indent(2) - str << " = " - str << arg.name - str << "_".nl - end - - if out_args.length > 0 - str << "\n" - str << "retrun result".indent(2).nl - end - - str << "}".indent.nl(false).nl(false) - end - end + str << ")".nl + + str << "}".indent.nl(false).nl(false) end str.string[0 .. -2] end + # Generates the D code for the interface methods + def interface_methods (methods, interface_name) + return "" if methods.length == 0 + + str = StringIO.new + + methods.each do |method| + return_type = get_type(method.returnValue[0].type, method.returnValue[0].type64, method.returnValue[0].declaredType) + + variadic = method.variadic == "true" + static = method.classMethod == "true" + + index = 0 + declaration = build_function(method, true, static)[0 ... -2].indent.nl(false) + index = declaration.index_of(" ", index) + str << ((declaration[0 .. index] + get_method_name(method["selector"]) + declaration[index .. -1]).gsub(/ +/, " "))[0 .. -2] + str << ";\n" + end + + str.string + end + # Generates the D code for the structs def structs (structs) + return "" if structs.length == 0 + str = StringIO.new structs.each do |struct| str << "struct " - str << struct.name.nl(false) + str << get_identifier(struct.name).nl(false) str << "{".nl struct.member.each do |member| @@ -1007,7 +1068,7 @@ str << type.indent str << " " - str << member.name.nl + str << get_identifier(member.name).nl end unless struct.member.nil? str << "}".nl @@ -1019,6 +1080,8 @@ # Generates the D code for the typedefs def typedefs (typedefs) + return "" if typedefs.length == 0 + str = StringIO.new typedefs.each do |typedef| @@ -1027,26 +1090,24 @@ struct = false if typedef.type.struct? - type = get_struct_type(typedef.type, typedef["type64"], typedef["declaredType"]) + type = get_struct_type(typedef.type, typedef.type64, typedef.declaredType) struct = true else type = get_type(typedef.type, typedef.type64, typedef.declaredType) end - # Special case - type = "wchar" if typedef.name == "unichar" - if struct - str << typedef["declaredType"].gsub("*", "").nl + str << typedef.declaredType.gsub("*", "").nl str << "alias " - str << type[:name] + str << get_identifier(type.name) + str << "*" if typedef.declaredType =~ /\*/ str << " " - str << typedef["name"].nl + str << get_identifier(typedef.name).nl else str << "alias " str << type str << " " - str << typedef.name.nl + str << get_identifier(typedef.name).nl end end @@ -1064,19 +1125,23 @@ # def check_declared_type (type) case type - when "unichar"; return "wchar" + when "unichar" + when "UniChar"; return "wchar" when "BOOL"; return "bool" when "CGFloat"; return type when "NSInteger"; return type when "NSUInteger"; return type + when "IMP"; return type; - when "unichar*"; return "wchar*" + when "unichar*" + when "UniChar*"; return "wchar*" when "BOOL*"; return "bool*" when "CGFloat*"; return type when "NSInteger*"; return type when "NSUInteger*"; return type - when "unichar**"; return "wchar**" + when "unichar**" + when "UniChar**"; return "wchar**" when "BOOL**"; return "bool**" when "CGFloat**"; return type when "NSInteger**"; return type @@ -1093,7 +1158,7 @@ # def get_method_name (selector) i = selector.index_of(":") - selector[0 ... i] + get_identifier(selector[0 ... i]) end # Gets the D type from the encoded C/Objective-C type @@ -1106,14 +1171,14 @@ # get_type("I", "I", "unsigned int") #=> uint # def get_type (type, type64, declared_type) - - return declared_type if type.nil? || type64.nil? - + + return get_identifier(declared_type) if type.nil? && type64.nil? + t = check_declared_type(declared_type) return t unless t.nil? unless type64 == "" || type64.nil? - return declared_type if type != type64 + return get_identifier(declared_type) if type != type64 end case type @@ -1135,9 +1200,15 @@ when '#'; return "Class" when ":"; return "SEL" when "@" - return declared_type.gsub(/\*+/, "") unless declared_type.nil? + unless declared_type.nil? + t = declared_type.gsub(/\*+/, "") + return t == "id" ? "Object" : t + end + raise "No declared type given" else + return declared_type if type =~ /\{/ + case type[0, 1] when "[" str = "" @@ -1152,7 +1223,7 @@ str = get_type(t, t64, declared_type) str << "[#{count}]" - return str + return get_identifier(str) when "(" resolved_types = [] types = $2 if type =~ /\((.+)=(.+)\)/ @@ -1162,28 +1233,34 @@ resolved_types << get_type(types[i], types64[i], declared_type) end - return resolved_types - when "^" + return get_identifier(resolved_types) + when "^" if type == "^@" - return "out " << get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup + return get_identifier(get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup + "*") elsif type.length > 2 && type[0 ... 2] == "^^" - return "out " << get_type(type[2 .. -1], type64[2 .. -1], declared_type).dup - elsif type == "^?" + return get_identifier(get_type(type[2 .. -1], type64[2 .. -1], declared_type).dup + "**") + elsif type == "^?" # assuming function pointer tmp = cfp_to_dfp(type) - return tmp unless tmp.nil? + return get_identifier(tmp) unless tmp.nil? end if !type.nil? && !type64.nil? - return get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup << "*" + t = get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup + + return get_identifier(t) if t =~ /\*/ + return get_identifier(t + "*") if t !~ /\*/ elsif !type.nil? - return get_type(type[1 .. -1], type64, declared_type).dup << "*" + t = get_type(type[1 .. -1], type64, declared_type).dup << "*" + + return get_identifier(t) if t =~ /\*/ + return get_identifier(t + "*") if t !~ /\*/ end when "{" - return declared_type + return get_identifier(declared_type) end end - return declared_type + return get_identifier(declared_type) end # Gets the D type from the encoded C/Objective-C type when it's a struct @@ -1197,7 +1274,6 @@ # { :name => "some", :types => ["uint", "uint", "uint"] } # def get_struct_type (type, type64, declared_type) - return { :name => declared_type } if declared_type[0 ... 2] == "NS" case type[0, 1] @@ -1205,11 +1281,11 @@ resolved_types = [] if type =~ /\^{0,}\{(.{0,})=(.{0,})\}/ - name = $1 - types = $2 + name = get_identifier($1) + types = get_identifier($2) elsif type =~ /\^{0,}\((.{0,})=(.{0,})\)/ - name = $1 - types = $2 + name = get_identifier($1) + types = get_identifier($2) end unless types.nil? @@ -1239,7 +1315,7 @@ name = $2 arg_types = $3 - return "#{return_type} function (#{arg_types})" + return "#{get_identifier(return_type)} function (#{arg_types})" end # Is the supplied argument an "out" argument @@ -1262,7 +1338,162 @@ # def transform_selector (selector) selector.gsub(/:/, "_") + end + + # Gets the identifier, if it's a D keyoword it + # will return string appended with a _ otherwise the string + def get_identifier (str) + return is_keyword?(str) ? str + "_" : str end + + # Returns true if the given string is a D(2) keyword + def is_keyword? (str) + case str + when "abstract"; return true + when "alias"; return true + when "align"; return true + when "asm"; return true + when "assert"; return true + when "auto"; return true + + when "body"; return true + when "bool"; return true + when "break"; return true + when "byte"; return true + + when "case"; return true + when "cast"; return true + when "catch"; return true + when "cdouble"; return true + when "cent"; return true + when "cfloat"; return true + when "char"; return true + when "class"; return true + when "const"; return true + when "continue"; return true + when "creal"; return true + + when "dchar"; return true + when "debug"; return true + when "default"; return true + when "delegate"; return true + when "delete"; return true + when "deprecated"; return true + when "do"; return true + when "double"; return true + + when "else"; return true + when "enum"; return true + when "export"; return true + when "extern"; return true + + when "false"; return true + when "final"; return true + when "finally"; return true + when "float"; return true + when "for"; return true + when "foreach"; return true + when "foreach_reverse"; return true + when "function"; return true + + when "goto"; return true + + when "idouble"; return true + when "if"; return true + when "ifloat"; return true + when "import"; return true + when "in"; return true + when "inout"; return true + when "int"; return true + when "interface"; return true + when "invariant"; return true + when "ireal"; return true + when "is"; return true + + when "lazy"; return true + when "long"; return true + + when "macro"; return true + when "mixin"; return true + when "module"; return true + + when "new"; return true + when "nothrow"; return true + when "null"; return true + + when "out"; return true + when "override"; return true + + when "package"; return true + when "pragma"; return true + when "private"; return true + when "protected"; return true + when "public"; return true + when "pure"; return true + + when "real"; return true + when "ref"; return true + when "return"; return true + + when "scope"; return true + when "shared"; return true;s + when "short"; return true + when "static"; return true + when "struct"; return true + when "super"; return true + when "switch"; return true + when "synchronized"; return true + + when "template"; return true + when "this"; return true + when "throw"; return true + when "true"; return true + when "try"; return true + when "typedef"; return true + when "typeid"; return true + when "typeof"; return true + + when "ubyte"; return true + when "ucent"; return true + when "uint"; return true + when "ulong"; return true + when "union"; return true + when "unittest"; return true + when "ushort"; return true + + when "version"; return true + when "void"; return true + when "volatile"; return true + + when "wchar"; return true + when "while"; return true + when "with"; return true + else return false; + end + end + + def templates_for_class (clazz) + templates = @templates.find_all do |template, value| + value[:class] == clazz + end + + return templates + end + + def interface_for_protocol (protocol) + interface = @interfaces2.find do |interface| + interface.name == protocol + end + + return interface + end + + def get_framework_name (framework) + i = framework.rindex(".framework") + return framework if i.nil? + x = framework.rindex("/", i) + framework[x + 1 ... i] + end end # Prints the message to stderr, exits