From: Kevin Ollivier Date: Sat, 2 May 2009 22:26:40 +0000 (+0000) Subject: Move the scripts into a separate directory and commit initial start on automatic... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/4e735ed6a6973429c5964c30825862a10949619c Move the scripts into a separate directory and commit initial start on automatic bindings generator. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@60490 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/doxygen/doxymlparser.py b/docs/doxygen/doxymlparser.py deleted file mode 100755 index 414cf988d2..0000000000 --- a/docs/doxygen/doxymlparser.py +++ /dev/null @@ -1,233 +0,0 @@ -""" -Name: doxymlparser.py -Author: Kevin Ollivier -License: wxWidgets License -""" - -__description__ = """ -Takes the output of Doxygen XML and parses it to retrieve metadata about the classes and methods. - -To create the Doxygen XML files, from the wxWidgets/docs/doxygen directory, do: - -./regen.sh xml - -To see the results from parsing a particular class, do: - -python doxymlparser.py --report out/xml/classwx_.xml -""" - -#!/usr/bin/env python -import optparse -import os -import string - -import sys -import types -from xml.dom import minidom - -option_dict = { - "report" : (False, "Print out the classes and methods found by this script."), - "verbose" : (False, "Provide status updates and other information."), - } - -parser = optparse.OptionParser(usage="usage: %prog [options] \n" + __description__, version="%prog 1.0") - -for opt in option_dict: - default = option_dict[opt][0] - - action = "store" - if type(default) == types.BooleanType: - action = "store_true" - parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1]) - -options, arguments = parser.parse_args() - -def get_first_value(alist): - if len(alist) > 0: - return alist[0] - else: - return "" - -class ClassDefinition: - def __init__(self): - self.name = "" - self.constructors = [] - self.destructors = [] - self.methods = [] - self.brief_description = "" - self.detailed_description = "" - self.includes = [] - self.bases = [] - self.enums = {} - - def __str__(self): - str_repr = """ -Class: %s -Bases: %s -Includes: %s -Brief Description: -%s - -Detailed Description: -%s -""" % (self.name, string.join(self.bases, ", "), self.includes, self.brief_description, self.detailed_description) - str_repr += "Methods:\n" - - for method in self.methods: - str_repr += str(method) - - return str_repr - -class MethodDefinition: - def __init__(self): - self.name = "" - self.return_type = "" - self.argsstring = "" - self.definition = "" - self.params = [] - self.brief_description = "" - self.detailed_description = "" - - def __str__(self): - str_repr = """ -Method: %s -Return Type: %s -Params: %r -Prototype: %s -Brief Description: -%s - -Detailed Description: -%s -""" % (self.name, self.return_type, self.params, self.definition + self.argsstring, self.brief_description, self.detailed_description) - return str_repr - -def getTextValue(node, recursive=False): - text = "" - for child in node.childNodes: - if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref": - text += getTextValue(child) - if child.nodeType == child.TEXT_NODE: - # Add a space to ensure we have a space between qualifiers and parameter names - text += child.nodeValue.strip() + " " - - return text.strip() - -def doxyMLToText(node): - return text - -class DoxyMLParser: - def __init__(self): - self.classes = [] - - def find_class(self, name): - for aclass in self.classes: - if aclass.name == name: - return aclass - - return None - - def get_enums_and_functions(self, filename, aclass): - file_path = os.path.dirname(filename) - enum_filename = os.path.join(file_path, aclass.name[2:] + "_8h.xml") - if os.path.exists(enum_filename): - root = minidom.parse(enum_filename).documentElement - for method in root.getElementsByTagName("memberdef"): - if method.getAttribute("kind") == "enum": - self.parse_enum(aclass, method, root) - - def is_derived_from_base(self, aclass, abase): - base = get_first_value(aclass.bases) - while base and base != "": - - if base == abase: - return True - - parentclass = self.find_class(base) - - if parentclass: - base = get_first_value(parentclass.bases) - else: - base = None - - return False - - def parse(self, filename): - self.xmldoc = minidom.parse(filename).documentElement - for node in self.xmldoc.getElementsByTagName("compounddef"): - new_class = self.parse_class(node) - self.classes.append(new_class) - self.get_enums_and_functions(filename, new_class) - - def parse_class(self, class_node): - new_class = ClassDefinition() - new_class.name = getTextValue(class_node.getElementsByTagName("compoundname")[0]) - for node in class_node.childNodes: - if node.nodeName == "basecompoundref": - new_class.bases.append(getTextValue(node)) - elif node.nodeName == "briefdescription": - # let the post-processor determ - new_class.brief_description = node.toxml() - elif node.nodeName == "detaileddescription": - new_class.detailed_description = node.toxml() - elif node.nodeName == "includes": - new_class.includes.append(getTextValue(node)) - - self.parse_methods(new_class, class_node) - - return new_class - - def parse_enum(self, new_class, enum, root): - enum_name = "" - enum_values = [] - - for node in enum.childNodes: - if node.nodeName == "name": - enum_name = getTextValue(node) - elif node.nodeName == "enumvalue": - enum_values.append(getTextValue(node.getElementsByTagName("name")[0])) - - new_class.enums[enum_name] = enum_values - - def parse_methods(self, new_class, root): - for method in root.getElementsByTagName("memberdef"): - new_method = MethodDefinition() - for node in method.childNodes: - if node.nodeName == "name": - new_method.name = getTextValue(node) - elif node.nodeName == "type": - new_method.return_type = getTextValue(node) - elif node.nodeName == "definition": - new_method.definition = getTextValue(node) - elif node.nodeName == "argsstring": - new_method.argsstring = getTextValue(node) - elif node.nodeName == "param": - param = {} - for child in node.childNodes: - if child.nodeType == child.ELEMENT_NODE: - param[child.nodeName] = getTextValue(child) - new_method.params.append(param) - - if options.verbose: - print "Adding %s" % (new_method.name + new_method.argsstring) - - if new_method.name == new_class.name: - new_class.constructors.append(new_method) - elif new_method.name == "~" + new_class.name: - new_class.destructors.append(new_method) - else: - new_class.methods.append(new_method) - -if __name__ == "__main__": - if len(arguments) < 1: - parser.print_usage() - sys.exit(1) - - doxyparse = DoxyMLParser() - for arg in arguments: - doxyparse.parse(arg) - - if options.report: - for aclass in doxyparse.classes: - print str(aclass) - diff --git a/docs/doxygen/scripts/doxymlparser.py b/docs/doxygen/scripts/doxymlparser.py new file mode 100755 index 0000000000..414cf988d2 --- /dev/null +++ b/docs/doxygen/scripts/doxymlparser.py @@ -0,0 +1,233 @@ +""" +Name: doxymlparser.py +Author: Kevin Ollivier +License: wxWidgets License +""" + +__description__ = """ +Takes the output of Doxygen XML and parses it to retrieve metadata about the classes and methods. + +To create the Doxygen XML files, from the wxWidgets/docs/doxygen directory, do: + +./regen.sh xml + +To see the results from parsing a particular class, do: + +python doxymlparser.py --report out/xml/classwx_.xml +""" + +#!/usr/bin/env python +import optparse +import os +import string + +import sys +import types +from xml.dom import minidom + +option_dict = { + "report" : (False, "Print out the classes and methods found by this script."), + "verbose" : (False, "Provide status updates and other information."), + } + +parser = optparse.OptionParser(usage="usage: %prog [options] \n" + __description__, version="%prog 1.0") + +for opt in option_dict: + default = option_dict[opt][0] + + action = "store" + if type(default) == types.BooleanType: + action = "store_true" + parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1]) + +options, arguments = parser.parse_args() + +def get_first_value(alist): + if len(alist) > 0: + return alist[0] + else: + return "" + +class ClassDefinition: + def __init__(self): + self.name = "" + self.constructors = [] + self.destructors = [] + self.methods = [] + self.brief_description = "" + self.detailed_description = "" + self.includes = [] + self.bases = [] + self.enums = {} + + def __str__(self): + str_repr = """ +Class: %s +Bases: %s +Includes: %s +Brief Description: +%s + +Detailed Description: +%s +""" % (self.name, string.join(self.bases, ", "), self.includes, self.brief_description, self.detailed_description) + str_repr += "Methods:\n" + + for method in self.methods: + str_repr += str(method) + + return str_repr + +class MethodDefinition: + def __init__(self): + self.name = "" + self.return_type = "" + self.argsstring = "" + self.definition = "" + self.params = [] + self.brief_description = "" + self.detailed_description = "" + + def __str__(self): + str_repr = """ +Method: %s +Return Type: %s +Params: %r +Prototype: %s +Brief Description: +%s + +Detailed Description: +%s +""" % (self.name, self.return_type, self.params, self.definition + self.argsstring, self.brief_description, self.detailed_description) + return str_repr + +def getTextValue(node, recursive=False): + text = "" + for child in node.childNodes: + if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref": + text += getTextValue(child) + if child.nodeType == child.TEXT_NODE: + # Add a space to ensure we have a space between qualifiers and parameter names + text += child.nodeValue.strip() + " " + + return text.strip() + +def doxyMLToText(node): + return text + +class DoxyMLParser: + def __init__(self): + self.classes = [] + + def find_class(self, name): + for aclass in self.classes: + if aclass.name == name: + return aclass + + return None + + def get_enums_and_functions(self, filename, aclass): + file_path = os.path.dirname(filename) + enum_filename = os.path.join(file_path, aclass.name[2:] + "_8h.xml") + if os.path.exists(enum_filename): + root = minidom.parse(enum_filename).documentElement + for method in root.getElementsByTagName("memberdef"): + if method.getAttribute("kind") == "enum": + self.parse_enum(aclass, method, root) + + def is_derived_from_base(self, aclass, abase): + base = get_first_value(aclass.bases) + while base and base != "": + + if base == abase: + return True + + parentclass = self.find_class(base) + + if parentclass: + base = get_first_value(parentclass.bases) + else: + base = None + + return False + + def parse(self, filename): + self.xmldoc = minidom.parse(filename).documentElement + for node in self.xmldoc.getElementsByTagName("compounddef"): + new_class = self.parse_class(node) + self.classes.append(new_class) + self.get_enums_and_functions(filename, new_class) + + def parse_class(self, class_node): + new_class = ClassDefinition() + new_class.name = getTextValue(class_node.getElementsByTagName("compoundname")[0]) + for node in class_node.childNodes: + if node.nodeName == "basecompoundref": + new_class.bases.append(getTextValue(node)) + elif node.nodeName == "briefdescription": + # let the post-processor determ + new_class.brief_description = node.toxml() + elif node.nodeName == "detaileddescription": + new_class.detailed_description = node.toxml() + elif node.nodeName == "includes": + new_class.includes.append(getTextValue(node)) + + self.parse_methods(new_class, class_node) + + return new_class + + def parse_enum(self, new_class, enum, root): + enum_name = "" + enum_values = [] + + for node in enum.childNodes: + if node.nodeName == "name": + enum_name = getTextValue(node) + elif node.nodeName == "enumvalue": + enum_values.append(getTextValue(node.getElementsByTagName("name")[0])) + + new_class.enums[enum_name] = enum_values + + def parse_methods(self, new_class, root): + for method in root.getElementsByTagName("memberdef"): + new_method = MethodDefinition() + for node in method.childNodes: + if node.nodeName == "name": + new_method.name = getTextValue(node) + elif node.nodeName == "type": + new_method.return_type = getTextValue(node) + elif node.nodeName == "definition": + new_method.definition = getTextValue(node) + elif node.nodeName == "argsstring": + new_method.argsstring = getTextValue(node) + elif node.nodeName == "param": + param = {} + for child in node.childNodes: + if child.nodeType == child.ELEMENT_NODE: + param[child.nodeName] = getTextValue(child) + new_method.params.append(param) + + if options.verbose: + print "Adding %s" % (new_method.name + new_method.argsstring) + + if new_method.name == new_class.name: + new_class.constructors.append(new_method) + elif new_method.name == "~" + new_class.name: + new_class.destructors.append(new_method) + else: + new_class.methods.append(new_method) + +if __name__ == "__main__": + if len(arguments) < 1: + parser.print_usage() + sys.exit(1) + + doxyparse = DoxyMLParser() + for arg in arguments: + doxyparse.parse(arg) + + if options.report: + for aclass in doxyparse.classes: + print str(aclass) + diff --git a/docs/doxygen/scripts/make_bindings.py b/docs/doxygen/scripts/make_bindings.py new file mode 100644 index 0000000000..34f4d45d49 --- /dev/null +++ b/docs/doxygen/scripts/make_bindings.py @@ -0,0 +1,347 @@ +import doxymlparser +import optparse +import sys +import os +import string +import types + +option_dict = { + "output_dir" : ("output", "Directory to output bindings to"), + "sip" : (True, "Produce SIP bindings"), + "swig" : (True, "Produce SWIG bindings."), + +} + +# format: class : {method : (prototype1, prototype2)} +# using a "*" means all prototypes +ignored_methods = { + "wxIcon": {'wxIcon': (['const char', 'int', 'int'], )}, + +} + +# these classes are either replaced by different data types in bindings, or have equivalent / better +# functionality provided by the target language. +excluded_classes = [ + "wxArchiveClassFactory", + "wxArchiveEntry", + "wxArchiveInputStream", + "wxArchiveIterator", + "wxArchiveNotifier", + "wxArchiveOutputStream", + "wxArray< T >", + "wxArrayString", + "wxAutomationObject", + "wxBufferedInputStream", + "wxBufferedOutputStream", + "wxCharBuffer", + "wxCharTypeBuffer", + "wxClassInfo", + "wxCmdLineParser", + "wxCondition", + "wxConnection", + "wxConnectionBase", + "wxConvAuto", + "wxCountingOutputStream", + "wxCriticalSection", + "wxCriticalSectionLocker", + "wxCSConv", + "wxDatagramSocket", + "wxDataInputStream", + "wxDataOutputStream", + "wxDir", + "wxDirTraverser", + "wxFFile", + "wxFFileInputStream", + "wxFFileOutputStream", + "wxFile", + "wxFileInputStream", + "wxFileName", + "wxFileOutputStream", + "wxFileStream", + "wxFilterClassFactory", + "wxFilterInputStream", + "wxFilterOutputStream", + "wxFSFile", + "wxFSVolume", + "wxFTP", + "wxHashMap", + "wxHashSet", + "wxHashTable", + "wxHTTP", + "wxImage::HSVValue", + "wxImage::RGBValue", + "wxInputStream", + "wxIPAddress", + "wxIPV4Address", + "wxList< T >", + "wxLongLong", + "wxMBConv", + "wxMBConvFile", + "wxMBConvUTF7", + "wxMBConvUTF8", + "wxMBConvUTF16", + "wxMBConvUTF32", + "wxMemoryBuffer", + "wxMemoryFSHandler", + "wxMemoryInputStream", + "wxMemoryOutputStream", + "wxMessageQueue< T >", + "wxModule", + "wxMutex", + "wxMutexLocker", + "wxNode< T >", + "wxObjectDataPtr< T >", + "wxObjectRefData", + "wxOutputStream", + "wxProcess", + "wxProcessEvent", + "wxProtocol", + "wxProtocolLog", + "wxRecursionGuard", + "wxRecursionGuardFlag", + "wxRegKey", + "wxScopedArray", + "wxScopedCharTypeBuffer", + "wxScopedPtr", + "wxScopedPtr< T >", + "wxSharedPtr< T >", + "wxServer", + "wxSockAddress", + "wxSocketBase", + "wxSocketClient", + "wxSocketEvent", + "wxSocketInputStream", + "wxSocketOutputStream", + "wxSortedArrayString", + "wxStopWatch", + "wxStreamBase", + "wxStreamBuffer", + "wxStreamToTextRedirector", + "wxString", + "wxStringBuffer", + "wxStringBufferLength", + "wxStringClientData", + "wxStringInputStream", + "wxStringOutputStream", + "wxTarClassFactory", + "wxTarEntry", + "wxTarInputStream", + "wxTarOutputStream", + "wxTCPClient", + "wxTCPConnection", + "wxTCPServer", + "wxTempFile", + "wxTempFileOutputStream", + "wxTextInputStream", + "wxTextOutputStream", + "wxThread", + "wxThreadEvent", + "wxThreadHelper", + "wxULongLong", + "wxUniChar", + "wxUniCharRef", + "wxURI", + "wxURL", + "wxUString", + "wxVariant", + "wxVariantData", + "wxVector< T >", + "wxVector< T >::reverse_iterator", + "wxWCharBuffer", + "wxWeakRef< T >", + "wxWeakRefDynamic< T >", + "wxZipInputStream", + "wxZipOutputStream", + "wxZlibInputStream", + "wxZlibOutputStream", + ] + + +parser = optparse.OptionParser(usage="usage: %prog \n" , version="%prog 1.0") + +for opt in option_dict: + default = option_dict[opt][0] + + action = "store" + if type(default) == types.BooleanType: + action = "store_true" + parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1]) + +options, arguments = parser.parse_args() + +def get_first_value(alist): + if len(alist) > 0: + return alist[0] + else: + return "" + +def make_enums(aclass): + retval = "" + for enum in aclass.enums: + retval += "enum %s {\n" % enum + num_values = len(aclass.enums[enum]) + for value in aclass.enums[enum]: + retval += " %s" % value + if not value == aclass.enums[enum][-1]: + retval += ", " + retval += "\n" + retval += "};\n\n" + + return retval + +class SIPBuilder: + def __init__(self, doxyparse, outputdir): + self.doxyparser = doxyparse + self.output_dir = outputdir + + def make_bindings(self): + output_dir = os.path.abspath(os.path.join(self.output_dir, "sip")) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + for aclass in self.doxyparser.classes: + if aclass.name in excluded_classes: + print "Skipping %s" % aclass.name + continue + + header_name = aclass.name[2:].lower() + filename = os.path.join(output_dir, header_name + ".sip") + enums_text = make_enums(aclass) + method_text = self.make_sip_methods(aclass) + base_class = get_first_value(aclass.bases) + if base_class != "": + base_class = ": %s" % base_class + + text = """ +%s +class %s %s +{ +%%TypeHeaderCode +#include <%s> +%%End + +public: +%s +}; +""" % (enums_text, aclass.name, base_class, get_first_value(aclass.includes), method_text) + + afile = open(filename, "wb") + afile.write(text) + afile.close() + + + def make_sip_methods(self, aclass): + retval = "" + + for amethod in aclass.constructors + aclass.methods: + transfer = "" + + # we need to come up with a way of filtering the methods out by various criteria + # including parameters and method name, and how to deal with overloads + if aclass.name in ignored_methods: + should_ignore = False + for method in ignored_methods[aclass.name]: + print "method = %s" % method + if method == amethod.name: + params = ignored_methods[aclass.name][method] + should_ignore = True + for i in xrange(len(params)): + if i >= len(amethod.params): + should_ignore = False + break + elif amethod.params[i]["type"] != params[i]: + print "param type = %s, amethod.param type = %s" % (params[i], amethod.params[i]["type"]) + should_ignore = False + break + + if should_ignore: + print "Ignoring method %s..." % amethod.name + continue + + if amethod in aclass.constructors and self.doxyparser.is_derived_from_base(aclass, "wxWindow"): + transfer = "/Transfer/" + + if amethod.name.startswith("operator"): + continue + + retval += " %s %s%s%s;\n\n" % (amethod.return_type.replace("virtual ", ""), amethod.name, amethod.argsstring, transfer) + + return retval + + + +class SWIGBuilder: + def __init__(self, doxyparse, outputdir): + self.doxyparser = doxyparse + self.output_dir = outputdir + + def make_bindings(self): + output_dir = os.path.abspath(os.path.join(self.output_dir, "swig")) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + for aclass in self.doxyparser.classes: + header_name = aclass.name[2:].lower() + if aclass.name in excluded_classes: + #print "Skipping %s" % aclass.name + continue + + filename = os.path.join(output_dir, header_name + ".i") + enums_text = make_enums(aclass) + method_text = self.make_swig_methods(aclass) + text = """ +%%newgroup + +%s +class %s : publib %s +{ + +public: +%s +}; +""" % (enums_text, aclass.name, get_first_value(aclass.bases), method_text) + + afile = open(filename, "wb") + afile.write(text) + afile.close() + + + def make_swig_methods(self, aclass): + retval = "" + + retval += """ + %%pythonAppend %s "self._setOORInfo(self)" + %%pythonAppend %s() "" + %%typemap(out) %s*; // turn off this typemap + """ % (aclass.name, aclass.name, aclass.name) + + for amethod in aclass.constructors: + retval += " %s%s;\n\n" % (amethod.name, amethod.argsstring) + + retval += """ + // Turn it back on again + %%typemap(out) %s* { $result = wxPyMake_wxObject($1, $owner); } + """ % aclass.name + + for amethod in aclass.methods: + retval += " %s %s%s;\n\n" % (amethod.return_type, amethod.name, amethod.argsstring) + + return retval + + +if __name__ == "__main__": + if len(arguments) < 1: + parser.print_usage() + sys.exit(1) + + doxyparse = doxymlparser.DoxyMLParser() + for arg in arguments: + doxyparse.parse(arg) + + if options.sip: + builder = SIPBuilder(doxyparse, options.output_dir) + builder.make_bindings() + + if options.swig: + builder = SWIGBuilder(doxyparse, options.output_dir) + builder.make_bindings()