# HG changeset patch # User Jacob Carlborg # Date 1246806979 -7200 # Node ID 9fd439a28ce32cbf2bd782f1987db72039e5352e # Parent 033d260cfc9b47de6c6a6cba82e030c0b4cb5faa Adapted the scripts for the new bridge + a lot more diff -r 033d260cfc9b -r 9fd439a28ce3 dsss.conf --- a/dsss.conf Thu Jun 18 22:00:13 2009 +0200 +++ b/dsss.conf Sun Jul 05 17:16:19 2009 +0200 @@ -1,2 +1,2 @@ -#[dstep] -[main.d] \ No newline at end of file +[dstep] +exlude += dstep/Cocoa \ No newline at end of file diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/String.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/Traits.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/Tuple.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/Types.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/Util.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/Version.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/internal/collection/Array.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bindings.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bridge/Bridge.d --- a/dstep/objc/bridge/Bridge.d Thu Jun 18 22:00:13 2009 +0200 +++ b/dstep/objc/bridge/Bridge.d Sun Jul 05 17:16:19 2009 +0200 @@ -64,11 +64,25 @@ template ObjcWrap (string name) { - import dstep.objc.bridge.ClassInitializer : ObjcSubclassInitializer, subclassInit; - import dstep.objc.objc : Class, id, IMP, SEL; - - static private Class objcClass_; - static private Class objcSuperClass_; + private + { + import dstep.objc.bridge.ClassInitializer : ObjcSubclassInitializer, subclassInit; + import dstep.objc.objc : Class, id, IMP, SEL; + + static Class objcClass_; + static Class objcSuperClass_; + } + + this () + { + objcObject = invokeObjcSelfClass!(id, "alloc"); + id ret = invokeObjcSelf!(id, "init"); + + if (ret) + objcObject = ret; + + dObject = this; + } this (id object) { @@ -124,21 +138,22 @@ template ObjcBindMethod (alias method, R, string selector, ARGS...) { - import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule, needsEncapsulation; - import dstep.internal.Tuple; - - private ObjcMethodDeclaration!(method, R, selector, ARGS) objcMethodDeclaration; - - private R delegate (ARGS) resolveVirtualCall () + private { - return null; - } + import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule; + import dstep.objc.bridge.Type : needsEncapsulation, ObjcType; + import dstep.internal.Tuple; + + ObjcMethodDeclaration!(method, R, selector, ARGS) objcMethodDeclaration; - static if (needsEncapsulation!(R)) - { - private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - - private static id forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) + R delegate (ARGS) resolveVirtualCall () + { + return null; + } + + alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + static ObjcType!(R) forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) in { assert(isCapsule(self)); @@ -158,37 +173,11 @@ args[i] = decapsule!(ArgType)(a); } - auto result = dg(args); + static if (is(R == void)) + dg(args); - return encapsule!(R)(result); - } - } - - else - { - private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - - private static R forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) - in - { - assert(isCapsule(self)); - } - body - { - R delegate (ARGS) dg; - dg.funcptr = &method; - dg.ptr = Bridge.getDObject(self); - - ARGS args; - - foreach (i, a ; objcArgs) - { - alias typeof(args[i]) ArgType; - - args[i] = decapsule!(ArgType)(a); - } - - return dg(args); + else + return encapsule!(R)(dg(args)); } } } @@ -200,13 +189,16 @@ template ObjcBindClassMethod (alias method, R, string selector, ARGS...) { - private ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; - - static if (needsEncapsulation!(R)) + private { - private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - - private static id forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) + import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule, needsEncapsulation, ObjcType; + import dstep.internal.Tuple; + + ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; + + alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + static ObjcType!(R) forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) in { assert(isCapsule(self)); @@ -224,35 +216,47 @@ args[i] = decapsule!(ArgType)(a); } - auto result = dg(args); + static if (needsEncapsulation!(R)) + return encapsule!(R)(dg(args)); - return encapsule!(R)(result); + else + return dg(args); } } - - else +} + +template ObjcBindFunction (alias func) +{ + mixin ObjcBindFunction!(func, ReturnTypeOf!(func), ParameterTupleOf!(func)); +} + +template ObjcBindFunction (alias func, R, ARGS...) +{ + private { - private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - - private static R forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) - in - { - assert(isCapsule(self)); - } - body - { - R function (ARGS) dg = &method; - + import dstep.objc.bridge.Capsule : decapsule, encapsule, needsEncapsulation, ObjcType; + import dstep.internal.Tuple; + + ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; + + alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + extern (C) ObjcType!(R) forwardFunctionCall (ObjcArgs objcArgs) + { ARGS args; foreach (i, a ; objcArgs) { alias typeof(args[i]) ArgType; - - args[i] = decapsule!(ArgType)(a); + + args[i] = decapsule!(ArgType)(a); } - return dg(args); + static if (needsEncapsulation!(R)) + return encapsule!(R)(dg(args)); + + else + return dg(args); } } } @@ -428,4 +432,53 @@ else return self.msgSend!(R)(sel, objcArgs); } + + R invokeObjcFunction (R, alias func, ARGS...) (ARGS args) + { + static if (!is(R : void)) + R result; + + auto funcPtr = &func; // use a function pointer instead of the alias because the function can be private. + + alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + ObjcArgs objcArgs; + + foreach (i, a ; args) + { + alias typeof(a) ArgType; + + objcArgs[i] = encapsule!(ArgType)(a); + } + + static if (is(R : ObjcWrapper)) + { + id r = funcPtr(objcArgs); + + if (!r) + return null; + + if (isCapsule(r)) + { + result = decapsule!(R)(r); + + if (result) + return result; + } + + return new R(r); + } + + else static if (is(R : Object)) + { + id r = funcPtr(objcArgs); + + if (!r) + return null; + + return decapsule!(R)(r); + } + + else + return funcPtr(objcArgs); + } } \ No newline at end of file diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bridge/Capsule.d --- a/dstep/objc/bridge/Capsule.d Thu Jun 18 22:00:13 2009 +0200 +++ b/dstep/objc/bridge/Capsule.d Sun Jul 05 17:16:19 2009 +0200 @@ -24,6 +24,7 @@ import dstep.internal.String; import dstep.objc.bridge.Bridge; +import dstep.objc.bridge.Type; import dstep.objc.bridge.TypeEncoding; import dstep.objc.bridge.Wrapper; import dstep.objc.message; @@ -33,15 +34,6 @@ import mambo.io; -template ObjcType (T) -{ - static if (needsEncapsulation!(T)) - alias id ObjcType; - - else - alias T ObjcType; -} - Class capsuleClass () { if (!Capsule.capsuleClass) @@ -119,17 +111,8 @@ return cls.getInstanceVariable!(Bridge.dObjectVar) !is null; } -template needsEncapsulation (T) -{ - static if (is(T == class)) - const needsEncapsulation = true; - - else - const needsEncapsulation = false; -} - ObjcType!(T) encapsule (T) (T value) -{ +{ static if (needsEncapsulation!(T)) { if (!value) @@ -145,28 +128,25 @@ return value; } -template decapsule (T) +T decapsule (T) (ObjcType!(T) value) { - T decapsule (ObjcType!(T) value) + static if (needsEncapsulation!(T)) { - static if (needsEncapsulation!(T)) + if (isCapsule(value)) + return cast(T) Bridge.getDObject(value); + + else { - if (isCapsule(value)) - return cast(T) Bridge.getDObject(value); + static if (is(T : ObjcWrapper)) + new T(value); else - { - static if (is(T : ObjcWrapper)) - new T(value); - - else - return null; - } + return null; } - - else - return value; } + + else + return value; } private id encapsuleString (string str) diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bridge/ClassInitializer.d --- a/dstep/objc/bridge/ClassInitializer.d Thu Jun 18 22:00:13 2009 +0200 +++ b/dstep/objc/bridge/ClassInitializer.d Sun Jul 05 17:16:19 2009 +0200 @@ -110,7 +110,7 @@ private static R invokeObjcSuperClass (R, string name, ARGS...) (ARGS args) { - return Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcClass.getSuperclass, args); + return Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcSuperClass, args); } } diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bridge/Type.d --- a/dstep/objc/bridge/Type.d Thu Jun 18 22:00:13 2009 +0200 +++ b/dstep/objc/bridge/Type.d Sun Jul 05 17:16:19 2009 +0200 @@ -14,6 +14,24 @@ import dstep.objc.objc; +template ObjcType (T) +{ + static if (needsEncapsulation!(T)) + alias id ObjcType; + + else + alias T ObjcType; +} + +template needsEncapsulation (T) +{ + static if (is(T == class)) + const needsEncapsulation = true; + + else + const needsEncapsulation = false; +} + template ObjcTypeTuple (TList...) { alias replaceClasses!(TList).types ObjcTypeTuple; diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bridge/TypeEncoding.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/bridge/Wrapper.d --- a/dstep/objc/bridge/Wrapper.d Thu Jun 18 22:00:13 2009 +0200 +++ b/dstep/objc/bridge/Wrapper.d Sun Jul 05 17:16:19 2009 +0200 @@ -15,12 +15,22 @@ class ObjcWrapper { - package objc_super* objcSuper; - static private Class objcClass_; static private Class objcSuperClass_; private id objcObject_; + private objc_super* objcSuper_; + + this () + { + objcObject = Bridge.invokeObjcClassMethod!(id, "alloc")(objcClass); + id ret = Bridge.invokeObjcMethod!(id, "init")(objcObject); + + if (ret) + objcObject = ret; + + dObject = this; + } /// Initialize object from an Objective-C object instance to wrap. this (id object) @@ -57,24 +67,15 @@ Bridge.setDObject(dObject, objcObject); } - /*this (bool init = true, bool alloc = true) + objc_super* objcSuper () { - if (init && alloc) + if (!objcSuper_) { - id result = objc_msgSend!(id)(objc_getClass(this.classinfo.name), sel.registerName!("alloc")); - id result2; - - if (result) - result2 = objc_msgSend(result, sel.registerName!("init")); - - if (result2) - objc.object = result2; - - else - objc.object = result; + objcSuper_ = new objc_super; + objcSuper_.receiver = objcObject; + objcSuper_.cls = objcSuperClass; } - else if (alloc) - objc.object = objc_msgSend(objc_getClass(this.classinfo.name), sel.registerName!("alloc")); - }*/ + return objcSuper_; + } } \ No newline at end of file diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/message.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/objc.d diff -r 033d260cfc9b -r 9fd439a28ce3 dstep/objc/runtime.d diff -r 033d260cfc9b -r 9fd439a28ce3 scripts/dgen.rb --- 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 diff -r 033d260cfc9b -r 9fd439a28ce3 scripts/dstepgen.rb --- a/scripts/dstepgen.rb Thu Jun 18 22:00:13 2009 +0200 +++ b/scripts/dstepgen.rb Sun Jul 05 17:16:19 2009 +0200 @@ -121,6 +121,13 @@ end end +Category = Struct.new(:name, :class) do + def initialize + self.name = "" + self.class = "" + end +end + # This class scans the headers class HeaderScaner CPP = ['/usr/bin/cpp-4.0', '/usr/bin/cpp-3.3', '/usr/bin/cpp3'].find { |x| File.exist?(x) } @@ -136,19 +143,29 @@ @file_content = nil @headers = [] @classes = {} - @informal_protocols = {} + @protocols = {} + @categories = {} + #@informal_protocols = {} @function_pointer_types = {} @do_64bit = false end - def classes + def get_classes @classes end - def protocols - @informal_protocols + def get_protocols + @protocols end + def get_categories + @categories + end + + # def get_informal_protocols + # @informal_protocols + # end + def cftypes (header) re = /typedef\s+(const\s+)?(struct\s*\w+\s*\*\s*)([^\s]+Ref)\s*;/ @cpp_result.scan(re).each do |m| @@ -262,12 +279,24 @@ header.imports = tmp.compact.uniq end - def informal_protocols (header) - self.methods(header) + # def informal_protocols (header) + # methods(header, /^@(interface)\s+(\w+)\s*:?\s*(\w*)\s*(\([^)]+\))?/, @protocols, false) + # end + + def classes (header) + methods(header, /^@(interface)\s+(\w+)\s*:?\s*(\w*)\s*(\<([\w,\s]+)>)?$/, @classes, false) end - def methods (header) - interface_re = /^@(interface|protocol)\s+(\w+)\s*:?\s*(\w*)\s*(\([^)]+\))?/ + def protocols (header) + methods(header, /^@(protocol)\s+(\w+)\s*:?\s*(\w*)\s*(\<([\w,\s]+)>)?(\([^)]+\))?/, @protocols, true) + end + + def categories (header) + methods(header, /^@(interface)\s+(\w+)\s*:?\s*(\w*)\s*(\<([\w,\s]+)>)?(\([^)]+\))/, @categories, false, true) + end + + def methods (header, regex, array, protocol, category = false) + interface_re = regex end_re = /^@end/ body_re = /^[-+]\s*(\([^)]+\))?\s*([^:\s;]+)/ @@ -275,17 +304,28 @@ prop_re = /^@property\s*(\([^)]+\))?\s*([^;]+);$/ current_interface = current_category = nil i = 0 - parent = nil + parent = nil + protocols = nil + cat = nil - @cpp_result.each_line do |line| + @cpp_result.each_line do |line| size = line.size line.strip! if md = interface_re.match(line) parent = nil - current_interface = md[1] == "protocol" ? "NSObject" : md[2] - current_category = md[4].delete("()").strip if md[4] + protocols = nil + current_category = md[6].delete("()").strip if md[6] + current_interface = md[2] unless category + current_interface = current_category if category parent = md[3] unless md[3] == "" + protocols = md[5] if md[5] + + if category + cat = Category.new if category + cat.name = current_category + cat.class = md[2] + end elsif end_re.match(line) current_interface = current_category = nil @@ -310,8 +350,10 @@ typeinfo = VarInfo.new(type, "", "") - @classes[current_interface] ||= {} - methods = (@classes[current_interface].methods ||= []) + array[current_interface] ||= {} unless category + array[cat] ||= {} if category + methods = (array[current_interface].methods ||= []) unless category + methods = (array[cat].methods ||= []) if category methods << MethodInfo.new(typeinfo, getter, false, [], line) unless readonly @@ -377,23 +419,34 @@ args << VarInfo.new("...", "vararg", "") if variadic method = MethodInfo.new(retval, selector, line[0] == ?+, args, data) - if current_category && current_interface == "NSObject" - (@informal_protocols[current_category] ||= []) << method - end + # if protocol && current_category && current_interface == "NSObject" + # (@informal_protocols[current_category] ||= []) << method + # end - @classes[current_interface] ||= {} + array[current_interface] ||= {} unless category + array[cat] ||= {} if category if header.name == current_interface - @classes[current_interface].file = header.name + array[current_interface].file = header.name unless category + array[cat].file = header.name if category else - @classes[current_interface].file ||= header.name + array[current_interface].file ||= header.name unless category + array[cat].file ||= header.name if category end unless parent == current_interface || parent =~ /\s+/ || parent.nil? - @classes[current_interface].parent = parent - end + array[current_interface].parent = parent unless category + array[cat].parent = parent if category + end - (@classes[current_interface].methods ||= []) << method + unless protocols.nil? + protocols.gsub!(/ /, "") + array[current_interface].protocols = protocols unless category + array[cat].protocols = protocols if category + end + + (array[current_interface].methods ||= []) << method unless category + (array[cat].methods ||= []) << method if category end i += size end @@ -493,7 +546,7 @@ end end - def prepare (path) + def prepare (path) @file_content = File.read(path) @file_content.gsub!(%r{(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)}, ""); @complete_cpp_result, @cpp_result = do_cpp(path, false, true, "") @@ -517,7 +570,10 @@ functions(header) functions(header, true) defines(header) - methods(header) + classes(header) + protocols(header) + #informal_protocols(header) + categories(header) function_pointer_types(header) end end @@ -535,7 +591,10 @@ functions(header) functions(header, true) defines(header) - methods(header) + classes(header) + protocols(header) + #informal_protocols(header) + categories(header) function_pointer_types(header) end end @@ -815,7 +874,7 @@ VERSION = 1.0 - attr_accessor :out_file, :scaner, :code_to_inject + attr_accessor :out_file, :scaner, :code_to_inject, :dependencies_switch def initialize @do_64bit = false @@ -823,12 +882,15 @@ @framework_paths = [] @headers = [] @import_directives = "#import \n" - @informal_protocols = [] + #@informal_protocols = [] @classes = [] + @protocols = [] + @categories = [] @scaner = HeaderScaner.new @scaner.do_64bit = @do_64bit @umbrella_framework = nil @handled_dependencies = [] + @dependencies_switch = false # link to foundation framework by default @compiler_flags = "-framework Foundation" @@ -841,12 +903,14 @@ def do_64bit= (do_64bit) @do_64bit = do_64bit @scaner.do_64bit = do_64bit - end + end def collect scaner.scan(@frameworks, @headers) - @classes = scaner.classes - @informal_protocols = scaner.protocols + @classes = scaner.get_classes + @protocols = scaner.get_protocols + @categories = scaner.get_categories + #@informal_protocols = scaner.get_informal_protocols end def handle_framework (framework, sub_framework = false, parent_framework = nil) @@ -981,7 +1045,7 @@ def compile_and_execute (code, enable_64bit = false, clean_when_fail = false) compiler_line = "gcc " - src = File.new(unique_tmp_path("src", ".m", "/Users/doob/development/eclipse_workspace/dstep/bindings"), "w") + src = File.new(unique_tmp_path("src", ".m"), "w") src << code src.close @@ -993,8 +1057,8 @@ compiler_line << arch_flag - bin = unique_tmp_path "bin", "", "/Users/doob/development/eclipse_workspace/dstep/bindings" - log = unique_tmp_path "log", ".txt", "/Users/doob/development/eclipse_workspace/dstep/bindings" + bin = unique_tmp_path "bin", "" + log = unique_tmp_path "log", ".txt" line = "#{compiler_line} -o #{bin} #{src.path} #{@compiler_flags} 2>#{log}" @@ -1093,11 +1157,43 @@ types end - def collect_informal_protocols_types (enable_64bit) + def collect_protocols_types (enable_64bit) types = [] - @informal_protocols.each do |name, methods| - methods.each do |method| + @protocols.each do |protocol, value| + value.methods.each do |method| + types << method.stripped_return_type + + method.args.each do |arg| + types << arg.stripped_return_type + end + end + end + + types + end + + # def collect_informal_protocols_types (enable_64bit) + # types = [] + # + # @informal_protocols.each do |name, methods| + # methods.each do |method| + # types << method.stripped_return_type + # + # method.args.each do |arg| + # types << arg.stripped_return_type + # end + # end + # end + # + # types + # end + + def collect_categories_types (enable_64bit) + types = [] + + @categories.each do |category, value| + value.methods.each do |method| types << method.stripped_return_type method.args.each do |arg| @@ -1154,7 +1250,7 @@ i end - def resolve_methods_types (enable_64bit, resolved_types, x) + def resolve_classes_types (enable_64bit, resolved_types, x) i = x @classes.each do |clazz, value| @@ -1174,11 +1270,51 @@ i end - def resolve_informal_protocols_types (enable_64bit, resolved_types, x) + def resolve_protocols_types (enable_64bit, resolved_types, x) i = x - @informal_protocols.each do |name, methods| - methods.each do |method| + @protocols.each do |protocol, value| + value.methods.each do |method| + method.resolved_type = resolved_types[i] unless enable_64bit + method.resolved_type64 = resolved_types[i] if enable_64bit + i += 1 + + method.args.each do |arg| + arg.resolved_type = resolved_types[i] unless enable_64bit + arg.resolved_type64 = resolved_types[i] if enable_64bit + i += 1 + end + end + end + + i + end + + # def resolve_informal_protocols_types (enable_64bit, resolved_types, x) + # i = x + # + # @informal_protocols.each do |name, methods| + # methods.each do |method| + # method.resolved_type = resolved_types[i] unless enable_64bit + # method.resolved_type64 = resolved_types[i] if enable_64bit + # i += 1 + # + # method.args.each do |arg| + # arg.resolved_type = resolved_types[i] unless enable_64bit + # arg.resolved_type64 = resolved_types[i] if enable_64bit + # i += 1 + # end + # end + # end + # + # i + # end + + def resolve_categories_types (enable_64bit, resolved_types, x) + i = x + + @categories.each do |category, value| + value.methods.each do |method| method.resolved_type = resolved_types[i] unless enable_64bit method.resolved_type64 = resolved_types[i] if enable_64bit i += 1 @@ -1211,7 +1347,7 @@ code << @import_directives types = [] - code << @code_to_inject + ";\n" unless @code_to_inject.nil? + code << @code_to_inject + "\n" unless @code_to_inject.nil? @frameworks.each do |framework| framework.headers.each do |header| @@ -1229,7 +1365,9 @@ end types << collect_classes_types(enable_64bit) - types << collect_informal_protocols_types(enable_64bit) + types << collect_protocols_types(enable_64bit) + #types << collect_informal_protocols_types(enable_64bit) + types << collect_categories_types(enable_64bit) code << "int main ()\n{\n" types.flatten! @@ -1257,9 +1395,11 @@ @headers.each do |header| i = resolve_header_types(header, enable_64bit, resolved_types, i) end - - i = resolve_methods_types(enable_64bit, resolved_types, i) - i = resolve_informal_protocols_types(enable_64bit, resolved_types, i) + + i = resolve_classes_types(enable_64bit, resolved_types, i) + i = resolve_protocols_types(enable_64bit, resolved_types, i) + #i = resolve_informal_protocols_types(enable_64bit, resolved_types, i) + i = resolve_categories_types(enable_64bit, resolved_types, i) end def generate_header (xml, header) @@ -1314,7 +1454,7 @@ def generate_classes (xml) @classes.each do |clazz, value| - xml.class :name => clazz, :parent => value.parent, :file => value.file do + xml.class :name => clazz, :parent => value.parent, :protocols => value.protocols, :file => value.file do value.methods.each do |method| xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do method.args.each do |arg| @@ -1328,10 +1468,42 @@ end end - def generate_informal_protocols (xml) - @informal_protocols.each do |name, methods| - xml.informalProtocol :name => name do - methods.each do |method| + def generate_protocols (xml) + @protocols.each do |protocol, value| + xml.protocol :name => protocol, :parent => value.parent, :protocols => value.protocols, :file => value.file do + value.methods.each do |method| + xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do + method.args.each do |arg| + xml.arg :name => arg.name, :declaredType => arg.return_type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const, :typeModifier => arg.type_modifier + end + + xml.returnValue :declaredType => method.return_type, :type => method.resolved_type, :type64 => method.resolved_type64, :const => method.const, :typeModifier => method.type_modifier + end + end + end + end + end + + # def generate_informal_protocols (xml) + # @informal_protocols.each do |name, methods| + # xml.informalProtocol :name => name do + # methods.each do |method| + # xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do + # method.args.each do |arg| + # xml.arg :name => arg.name, :declaredType => arg.return_type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const, :typeModifier => arg.type_modifier + # end + # + # xml.returnValue :declaredType => method.return_type, :type => method.resolved_type, :type64 => method.resolved_type64, :const => method.const, :typeModifier => method.type_modifier + # end + # end + # end + # end + # end + + def generate_categories (xml) + @categories.each do |category, value| + xml.category :name => category.name, :class => category.class, :parent => value.parent, :protocols => value.protocols, :file => value.file do + value.methods.each do |method| xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do method.args.each do |arg| xml.arg :name => arg.name, :declaredType => arg.return_type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const, :typeModifier => arg.type_modifier @@ -1368,10 +1540,25 @@ end generate_classes(xml) - generate_informal_protocols(xml) + generate_protocols(xml) + #generate_informal_protocols(xml) + generate_categories(xml) end file.close unless file == STDOUT + end + + def write_dependencies + file = STDOUT if @out_file == nil + file = File.open @out_file, "w" unless @out_file == nil + + @dependencies.each do |dep| + file << dep + "\n" + end + + file.close unless file == STDOUT + + exit 0 end end @@ -1410,10 +1597,14 @@ # dstep_gen.out_dir = opt # end - opts.on("-C", "--code CODE", "Add code") do |opt| + opts.on("-c", "--code CODE", "Add code") do |opt| dstep_gen.code_to_inject = opt end + opts.on("-d", "--dependencies", "Write framework dependencies and exit") do |opt| + dstep_gen.dependencies_switch = true + end + help_msg = "Use the `-h' flag or for help." opts.on("-h", "--help", "Show this message.") do @@ -1434,6 +1625,8 @@ #begin opts.parse!(ARGV) + dstep_gen.write_dependencies if dstep_gen.dependencies_switch + ARGV.each do |header| dstep_gen.add_header(header) end @@ -1448,4 +1641,4 @@ # end end end -end +end \ No newline at end of file