def generatePyFunction(self, pf, stream, indent=''): assert isinstance(pf, extractors.PyFunctionDef) if len(indent) == 0: stream.write('%%Extract(id=pycode%s' % self.module_name) if pf.order is not None: stream.write(', order=%d' % pf.order) stream.write(')\n') if pf.deprecated: if isinstance(pf.deprecated, int): stream.write('%[email protected]\n' % indent) else: stream.write('%[email protected]("%s")\n' % (indent, pf.deprecated)) if pf.isStatic: stream.write('%s@staticmethod\n' % indent) stream.write('%sdef %s%s:\n' % (indent, pf.name, pf.argsString)) indent2 = indent + ' ' * 4 if pf.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pf.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) stream.write(nci(pf.body, len(indent2))) if len(indent) == 0: stream.write('\n%End\n') stream.write('\n')
def generateFunction(self, function, stream, _needDocstring=True): assert isinstance(function, extractors.FunctionDef) if not function.ignored: stream.write('%s %s(' % (function.type, function.name)) if function.items: stream.write('\n') self.generateParameters(function.items, stream, ' ' * 4) stream.write(')%s;\n' % self.annotate(function)) if _needDocstring: self.generateDocstring(function, stream, '') # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False if function.mustHaveAppFlag: stream.write('%PreMethodCode\n') stream.write(nci("if (!wxPyCheckForApp()) return NULL;\n", 4)) stream.write('%End\n') if function.cppCode: code, codeType = function.cppCode if codeType == 'sip': stream.write('%MethodCode\n') stream.write(nci(code, 4)) stream.write('%End\n') elif codeType == 'function': raise NotImplementedError( ) # TODO: See generateMethod for an example, refactor to share code... for f in function.overloads: self.generateFunction(f, stream, _needDocstring) stream.write('\n')
def generateFunction(self, function, stream, _needDocstring=True): assert isinstance(function, extractors.FunctionDef) if not function.ignored: stream.write('%s %s(' % (function.type, function.name)) if function.items: stream.write('\n') self.generateParameters(function.items, stream, ' '*4) stream.write(')%s;\n' % self.annotate(function)) if _needDocstring: self.generateDocstring(function, stream, '') # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False if function.mustHaveAppFlag: stream.write('%PreMethodCode\n') stream.write(nci("if (!wxPyCheckForApp()) return NULL;\n", 4)) stream.write('%End\n') if function.cppCode: code, codeType = function.cppCode if codeType == 'sip': stream.write('%MethodCode\n') stream.write(nci(code, 4)) stream.write('%End\n') elif codeType == 'function': raise NotImplementedError() # TODO: See generateMethod for an example, refactor to share code... for f in function.overloads: self.generateFunction(f, stream, _needDocstring) stream.write('\n')
def generateMethod(self, method, stream, indent): assert isinstance(method, extractors.MethodDef) _needDocstring = getattr(method, '_needDocstring', True) checkOverloads = True if not method.ignored: if method.isVirtual: stream.write("%svirtual\n" % indent) if method.isStatic: stream.write("%sstatic\n" % indent) if method.isCtor or method.isDtor: stream.write('%s%s(' % (indent, method.name)) else: stream.write('%s%s %s(' % (indent, method.type, method.name)) if method.items: stream.write('\n') self.generateParameters(method.items, stream, indent+' '*4) stream.write(indent) stream.write(')') if method.isConst: stream.write(' const') if method.isPureVirtual: stream.write(' = 0') cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" if cppSig: stream.write(cppSig) stream.write('%s;\n' % self.annotate(method)) if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False if method.cppCode: #checkOverloads = False ## SIP now allows overloads to have %MethodCode code, codeType = method.cppCode if codeType == 'sip': stream.write('%s%%MethodCode\n' % indent) stream.write(nci(code, len(indent)+4)) stream.write('%s%%End\n' % indent) elif codeType == 'function': cm = extractors.CppMethodDef.FromMethod(method) cm.body = code self.generateCppMethod(cm, stream, indent, skipDeclaration=True) # generateCppMethod will have already done the overloads # and virtual catcher code, so we can just return from # here. return if method.virtualCatcherCode: stream.write('%s%%VirtualCatcherCode\n' % indent) stream.write(nci(method.virtualCatcherCode, len(indent)+4)) stream.write('%s%%End\n' % indent) stream.write('\n') if checkOverloads and method.overloads: for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent)
def generatePyMethod(self, pm, stream, indent): assert isinstance(pm, extractors.PyMethodDef) if pm.ignored: return if pm.klass.generatingInClass: pm.klass.generateAfterClass.append(pm) else: klassName = pm.klass.pyName or pm.klass.name stream.write("%%Extract(id=pycode%s)\n" % self.module_name) stream.write("def _%s_%s%s:\n" % (klassName, pm.name, pm.argsString)) pm.pyDocstring = "" if pm.briefDoc: doc = nci(pm.briefDoc) pm.pyDocstring = doc stream.write(nci('"""\n%s"""\n' % doc, 4)) stream.write(nci(pm.body, 4)) stream.write('%s.%s = ' % (klassName, pm.name)) end = '\n' if pm.isStatic: stream.write('staticmethod(') end = ')' + end if pm.deprecated: stream.write('wx.deprecated(') end = ')' + end stream.write('_%s_%s' % (klassName, pm.name)) if pm.deprecated and not isinstance(pm.deprecated, int): stream.write(', "%s"' % pm.deprecated) stream.write(end) stream.write('del _%s_%s\n' % (klassName, pm.name)) stream.write('%End\n\n')
def generateDocstring(self, item, stream, indent): item.pyDocstring = "" if item.name.startswith('operator'): return # Apparently sip doesn't like operators to have docstrings... # get the docstring text text = nci(extractors.flattenNode(item.briefDoc, False)) text = wrapText(text) #if isinstance(item, extractors.ClassDef): # # append the function signatures for the class constructors (if any) to the class' docstring # try: # ctor = item.find(item.name) # sigs = ctor.collectPySignatures() # if sigs: # text += '\n' + '\n'.join(sigs) # except extractors.ExtractorError: # pass #else: # # Prepend function signature string(s) for functions and methods # sigs = item.collectPySignatures() # if sigs: # if text: # text = '\n\n' + text # text = '\n'.join(sigs) + text sigs = None if isinstance(item, extractors.ClassDef): try: ctor = item.find(item.name) sigs = ctor.collectPySignatures() except extractors.ExtractorError: pass else: sigs = item.collectPySignatures() if sigs: if text: text = '\n\n' + text text = '\n'.join(sigs) + text # write the docstring directive and the text stream.write('%s%%Docstring\n' % indent) stream.write(nci(text, len(indent)+4)) stream.write('%s%%End\n' % indent) # and save the docstring back into item in case it is needed by other # generators later on item.pyDocstring = nci(text)
def generatePyClass(self, pc, stream, indent=""): assert isinstance(pc, extractors.PyClassDef) # write the class declaration and docstring if pc.deprecated: stream.write("%[email protected]\n" % indent) stream.write("%sclass %s" % (indent, pc.name)) if pc.bases: stream.write("(%s):\n" % ", ".join(pc.bases)) else: stream.write("(object):\n") indent2 = indent + " " * 4 if pc.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pc.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) # these are the only kinds of items allowed to be items in a PyClass dispatch = { extractors.PyFunctionDef: self.generatePyFunction, extractors.PyPropertyDef: self.generatePyProperty, extractors.PyCodeDef: self.generatePyCode, extractors.PyClassDef: self.generatePyClass, } for item in pc.items: item.klass = pc f = dispatch[item.__class__] f(item, stream, indent2)
def generatePyClass(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyClassDef) # write the class declaration and docstring if pc.deprecated: stream.write('%[email protected]\n' % indent) stream.write('%sclass %s' % (indent, pc.name)) if pc.bases: stream.write('(%s):\n' % ', '.join(pc.bases)) else: stream.write('(object):\n') indent2 = indent + ' '*4 if pc.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pc.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) # these are the only kinds of items allowed to be items in a PyClass dispatch = { extractors.PyFunctionDef : self.generatePyFunction, extractors.PyPropertyDef : self.generatePyProperty, extractors.PyCodeDef : self.generatePyCode, extractors.PyClassDef : self.generatePyClass, } for item in pc.items: item.klass = pc f = dispatch[item.__class__] f(item, stream, indent2)
def generatePyCode(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyCodeDef) code = pc.code if hasattr(pc, 'klass'): code = code.replace(pc.klass.pyName+'.', '') stream.write('\n') stream.write(nci(code, len(indent)))
def generateMethod(self, method, stream, indent, name=None, docstring=None): assert isinstance(method, extractors.MethodDef) for m in method.all( ): # use the first not ignored if there are overloads if not m.ignored or piIgnored(m): method = m break else: return if method.isDtor: return name = name or method.pyName or method.name if name in magicMethods: name = magicMethods[name] # write the method declaration if method.isStatic: stream.write('\n%s@staticmethod' % indent) stream.write('\n%sdef %s' % (indent, name)) if method.hasOverloads(): if not method.isStatic: stream.write('(self, *args, **kw)') else: stream.write('(*args, **kw)') else: argsString = method.pyArgsString if not argsString: argsString = '()' if '->' in argsString: pos = argsString.find(') ->') argsString = argsString[:pos + 1] if '(' != argsString[0]: pos = argsString.find('(') argsString = argsString[pos:] if not method.isStatic: if argsString == '()': argsString = '(self)' else: argsString = '(self, ' + argsString[1:] argsString = argsString.replace('::', '.') stream.write(argsString) stream.write(':\n') indent2 = indent + ' ' * 4 # docstring if not docstring: if hasattr(method, 'pyDocstring'): docstring = method.pyDocstring else: docstring = "" stream.write('%s"""\n' % indent2) if docstring.strip(): stream.write(nci(docstring, len(indent2))) stream.write('%s"""\n' % indent2)
def generatePyCode(self, pc, stream, indent=""): assert isinstance(pc, extractors.PyCodeDef) code = pc.code if hasattr(pc, "klass"): code = code.replace(pc.klass.pyName + ".", "") stream.write("\n") stream.write(nci(code, len(indent)))
def generateCppMethod_sip(self, method, stream, indent=''): # Add a new C++ method to a class without the extra generated # function, so SIP specific stuff can be done in the function body. assert isinstance(method, extractors.CppMethodDef_sip) if method.ignored: return _needDocstring = getattr(method, '_needDocstring', True) cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" if method.isCtor: stream.write('%s%s%s%s%s;\n' % (indent, method.name, method.argsString, self.annotate(method), cppSig)) else: virtual = "virtual " if method.isVirtual else "" stream.write('%s%s%s %s%s%s%s;\n' % (indent, virtual, method.type, method.name, method.argsString, self.annotate(method), cppSig)) # write the docstring if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False stream.write('%s%%MethodCode\n' % indent) if not (method.isCtor or method.isDtor): stream.write('%sPyErr_Clear();\n' % (indent + ' ' * 4)) stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent + ' ' * 4)) stream.write(nci(method.body, len(indent) + 4)) if not (method.isCtor or method.isDtor): stream.write('%sPy_END_ALLOW_THREADS\n' % (indent + ' ' * 4)) stream.write('%sif (PyErr_Occurred()) sipIsErr = 1;\n' % (indent + ' ' * 4)) stream.write('%s%%End\n\n' % indent)
def generateTypedef(self, typedef, stream, indent=''): assert isinstance(typedef, extractors.TypedefDef) if typedef.ignored or piIgnored(typedef): return # If it's not a template instantiation, or has not been flagged by # the tweaker script that it should be treated as a class, then just # ignore the typedef and return. if not ('<' in typedef.type and '>' in typedef.type) and not typedef.docAsClass: return # Otherwise write a mock class for it that combines the template and class. # First, extract the info we need. if typedef.docAsClass: bases = [self.fixWxPrefix(b, True) for b in typedef.bases] name = self.fixWxPrefix(typedef.name) elif '<' in typedef.type and '>' in typedef.type: t = typedef.type.replace('>', '') t = t.replace(' ', '') bases = t.split('<') bases = [self.fixWxPrefix(b, True) for b in bases] name = self.fixWxPrefix(typedef.name) # Now write the Python equivalent class for the typedef if not bases: bases = ['object'] # this should not happpen, but just in case... stream.write('%sclass %s(%s):\n' % (indent, name, ', '.join(bases))) indent2 = indent + ' '*4 if typedef.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(typedef.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) else: stream.write('%spass\n\n' % indent2)
def generateTypedef(self, typedef, stream, indent=""): assert isinstance(typedef, extractors.TypedefDef) if typedef.ignored: return # If it's not a template instantiation, or has not been flagged by # the tweaker script that it should be treated as a class, then just # ignore the typedef and return. if not ("<" in typedef.type and ">" in typedef.type) and not typedef.docAsClass: return # Otherwise write a mock class for it that combines the template and class. # First, extract the info we need. if typedef.docAsClass: bases = [self.fixWxPrefix(b, True) for b in typedef.bases] name = self.fixWxPrefix(typedef.name) elif "<" in typedef.type and ">" in typedef.type: t = typedef.type.replace(">", "") t = t.replace(" ", "") bases = t.split("<") bases = [self.fixWxPrefix(b, True) for b in bases] name = self.fixWxPrefix(typedef.name) # Now write the Python equivallent class for the typedef if not bases: bases = ["object"] # this should not happpen, but just in case... stream.write("%sclass %s(%s):\n" % (indent, name, ", ".join(bases))) indent2 = indent + " " * 4 if typedef.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(typedef.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) else: stream.write("%spass\n\n" % indent2)
def generateMemberVar(self, memberVar, stream, indent): assert isinstance(memberVar, extractors.MemberVarDef) if memberVar.ignored: return stream.write('%s%s %s' % (indent, memberVar.type, memberVar.name)) stream.write(self.annotate(memberVar)) if memberVar.getCode or memberVar.setCode: stream.write('\n%s{\n' % (indent, )) if memberVar.getCode: stream.write('%s%%GetCode\n' % (indent)) stream.write(nci(memberVar.getCode, len(indent) + 4)) stream.write('%s%%End\n' % (indent)) if memberVar.setCode: stream.write('%s%%SetCode\n' % (indent)) stream.write(nci(memberVar.setCode, len(indent) + 4)) stream.write('%s%%End\n' % (indent)) stream.write('%s}' % (indent, )) stream.write(';\n\n')
def generateMethod(self, method, stream, indent, name=None, docstring=None): assert isinstance(method, extractors.MethodDef) for m in method.all(): # use the first not ignored if there are overloads if not m.ignored or piIgnored(m): method = m break else: return if method.isDtor: return name = name or method.pyName or method.name if name in magicMethods: name = magicMethods[name] # write the method declaration if method.isStatic: stream.write('\n%s@staticmethod' % indent) stream.write('\n%sdef %s' % (indent, name)) if method.hasOverloads(): if not method.isStatic: stream.write('(self, *args, **kw)') else: stream.write('(*args, **kw)') else: argsString = method.pyArgsString if not argsString: argsString = '()' if '->' in argsString: pos = argsString.find(') ->') argsString = argsString[:pos+1] if '(' != argsString[0]: pos = argsString.find('(') argsString = argsString[pos:] if not method.isStatic: if argsString == '()': argsString = '(self)' else: argsString = '(self, ' + argsString[1:] argsString = argsString.replace('::', '.') stream.write(argsString) stream.write(':\n') indent2 = indent + ' '*4 # docstring if not docstring: if hasattr(method, 'pyDocstring'): docstring = method.pyDocstring else: docstring = "" stream.write('%s"""\n' % indent2) if docstring.strip(): stream.write(nci(docstring, len(indent2))) stream.write('%s"""\n' % indent2)
def generateMethod(self, method, stream, indent, name=None, docstring=None): assert isinstance(method, extractors.MethodDef) for m in method.all(): # use the first not ignored if there are overloads if not m.ignored: method = m break else: return if method.isDtor: return name = name or method.pyName or method.name if name in magicMethods: name = magicMethods[name] # write the method declaration if method.isStatic: stream.write("\n%s@staticmethod" % indent) stream.write("\n%sdef %s" % (indent, name)) if method.hasOverloads(): if not method.isStatic: stream.write("(self, *args, **kw)") else: stream.write("(*args, **kw)") else: argsString = method.pyArgsString if not argsString: argsString = "()" if "->" in argsString: pos = argsString.find(") ->") argsString = argsString[: pos + 1] if "(" != argsString[0]: pos = argsString.find("(") argsString = argsString[pos:] if not method.isStatic: if argsString == "()": argsString = "(self)" else: argsString = "(self, " + argsString[1:] argsString = argsString.replace("::", ".") stream.write(argsString) stream.write(":\n") indent2 = indent + " " * 4 # docstring if not docstring: if hasattr(method, "pyDocstring"): docstring = method.pyDocstring else: docstring = "" stream.write('%s"""\n' % indent2) if docstring.strip(): stream.write(nci(docstring, len(indent2))) stream.write('%s"""\n' % indent2)
def generateFunction(self, function, stream, _needDocstring=True): assert isinstance(function, extractors.FunctionDef) if not function.ignored: stream.write('%s %s(' % (function.type, function.name)) if function.items: stream.write('\n') self.generateParameters(function.items, stream, ' ' * 4) stream.write(')%s;\n' % self.annotate(function)) if _needDocstring: self.generateDocstring(function, stream, '') # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False if function.preMethodCode: stream.write('%PreMethodCode\n') stream.write(nci(function.preMethodCode, 4)) stream.write('%End\n') if function.cppCode: code, codeType = function.cppCode if codeType == 'sip': stream.write('%MethodCode\n') stream.write(nci(code, 4)) stream.write('%End\n') elif codeType == 'function': ## raise NotImplementedError() # TODO: See generateMethod for an example, refactor to share code... cm = extractors.CppMethodDef.FromMethod(function) cm.body = code self.generateCppMethod(cm, stream, "", skipDeclaration=True) # generateCppMethod will have already done the overloads # and virtual catcher code, so we can just return from # here. return for f in function.overloads: self.generateFunction(f, stream, _needDocstring) stream.write('\n')
def generatePyMethod(self, pm, stream, indent): assert isinstance(pm, extractors.PyMethodDef) if pm.ignored or piIgnored(pm): return if pm.isStatic: stream.write('\n%s@staticmethod' % indent) stream.write('\n%sdef %s' % (indent, pm.name)) stream.write(getattr(pm, 'piArgsString', pm.argsString)) stream.write(':\n') indent2 = indent + ' '*4 stream.write('%s"""\n' % indent2) stream.write(nci(pm.pyDocstring, len(indent2))) stream.write('%s"""\n' % indent2)
def generatePyFunction(self, pf, stream, indent=''): assert isinstance(pf, extractors.PyFunctionDef) stream.write('\n') if pf.deprecated: stream.write('%[email protected]\n' % indent) if pf.isStatic: stream.write('%s@staticmethod\n' % indent) stream.write('%sdef %s%s:\n' % (indent, pf.name, pf.argsString)) indent2 = indent + ' '*4 if pf.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pf.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) stream.write('%spass\n' % indent2)
def generatePyMethod(self, pm, stream, indent): assert isinstance(pm, extractors.PyMethodDef) if pm.ignored: return if pm.isStatic: stream.write("\n%s@staticmethod" % indent) stream.write("\n%sdef %s" % (indent, pm.name)) stream.write(pm.argsString) stream.write(":\n") indent2 = indent + " " * 4 stream.write('%s"""\n' % indent2) stream.write(nci(pm.pyDocstring, len(indent2))) stream.write('%s"""\n' % indent2)
def generatePyFunction(self, pf, stream, indent=""): assert isinstance(pf, extractors.PyFunctionDef) stream.write("\n") if pf.deprecated: stream.write("%[email protected]\n" % indent) if pf.isStatic: stream.write("%s@staticmethod\n" % indent) stream.write("%sdef %s%s:\n" % (indent, pf.name, pf.argsString)) indent2 = indent + " " * 4 if pf.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pf.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) stream.write("%spass\n" % indent2)
def generatePyFunction(self, pf, stream, indent=''): assert isinstance(pf, extractors.PyFunctionDef) if len(indent) == 0: stream.write('%%Extract(id=pycode%s' % self.module_name) if pf.order is not None: stream.write(', order=%d' % pf.order) stream.write(')\n') if pf.deprecated: if isinstance(pf.deprecated, int): stream.write('%[email protected]\n' % indent) else: stream.write('%[email protected]("%s")\n' % (indent, pf.deprecated)) if pf.isStatic: stream.write('%s@staticmethod\n' % indent) stream.write('%sdef %s%s:\n' % (indent, pf.name, pf.argsString)) indent2 = indent + ' '*4 if pf.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pf.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) stream.write(nci(pf.body, len(indent2))) if len(indent) == 0: stream.write('\n%End\n') stream.write('\n')
def generatePyCode(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyCodeDef) if hasattr(pc, 'klass') and isinstance(pc.klass, extractors.ClassDef) and pc.klass.generatingInClass: pc.klass.generateAfterClass.append(pc) else: if len(indent) == 0: stream.write('%%Extract(id=pycode%s' % self.module_name) if pc.order is not None: stream.write(', order=%d' % pc.order) stream.write(')\n') stream.write(nci(pc.code, len(indent))) if len(indent) == 0: stream.write('\n%End\n\n')
def generateCppMethod_sip(self, method, stream, indent=''): # Add a new C++ method to a class without the extra generated # function, so SIP specific stuff can be done in the function body. assert isinstance(method, extractors.CppMethodDef_sip) if method.ignored: return cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" if method.isCtor: stream.write('%s%s%s%s%s;\n' % (indent, method.name, method.argsString, self.annotate(method), cppSig)) else: stream.write('%s%s %s%s%s%s;\n' % (indent, method.type, method.name, method.argsString, self.annotate(method), cppSig)) stream.write('%s%%MethodCode\n' % indent) stream.write(nci(method.body, len(indent)+4)) stream.write('%s%%End\n\n' % indent)
def generatePyClass(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyClassDef) if len(indent) == 0: stream.write('%%Extract(id=pycode%s' % self.module_name) if pc.order is not None: stream.write(', order=%d' % pc.order) stream.write(')\n') # write the class declaration and docstring if pc.deprecated: if isinstance(pc.deprecated, int): stream.write('%[email protected]\n' % indent) else: stream.write('%[email protected]("%s")\n' % (indent, pc.deprecated)) stream.write('%sclass %s' % (indent, pc.name)) if pc.bases: stream.write('(%s):\n' % ', '.join(pc.bases)) else: stream.write('(object):\n') indent2 = indent + ' ' * 4 if pc.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pc.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) # these are the only kinds of items allowed to be items in a PyClass dispatch = { extractors.PyFunctionDef: self.generatePyFunction, extractors.PyPropertyDef: self.generatePyProperty, extractors.PyCodeDef: self.generatePyCode, extractors.PyClassDef: self.generatePyClass, } for item in pc.items: item.klass = pc f = dispatch[item.__class__] f(item, stream, indent2) if len(indent) == 0: stream.write('\n%End\n') stream.write('\n')
def generatePyClass(self, pc, stream, indent=''): assert isinstance(pc, extractors.PyClassDef) if len(indent) == 0: stream.write('%%Extract(id=pycode%s' % self.module_name) if pc.order is not None: stream.write(', order=%d' % pc.order) stream.write(')\n') # write the class declaration and docstring if pc.deprecated: if isinstance(pc.deprecated, int): stream.write('%[email protected]\n' % indent) else: stream.write('%[email protected]("%s")\n' % (indent, pc.deprecated)) stream.write('%sclass %s' % (indent, pc.name)) if pc.bases: stream.write('(%s):\n' % ', '.join(pc.bases)) else: stream.write('(object):\n') indent2 = indent + ' '*4 if pc.briefDoc: stream.write('%s"""\n' % indent2) stream.write(nci(pc.briefDoc, len(indent2))) stream.write('%s"""\n' % indent2) # these are the only kinds of items allowed to be items in a PyClass dispatch = { extractors.PyFunctionDef : self.generatePyFunction, extractors.PyPropertyDef : self.generatePyProperty, extractors.PyCodeDef : self.generatePyCode, extractors.PyClassDef : self.generatePyClass, } for item in pc.items: item.klass = pc f = dispatch[item.__class__] f(item, stream, indent2) if len(indent) == 0: stream.write('\n%End\n') stream.write('\n')
def generateFunction(self, function, stream): assert isinstance(function, extractors.FunctionDef) if not function.pyName: return stream.write('\ndef %s' % function.pyName) if function.hasOverloads(): stream.write('(*args, **kw)') else: argsString = function.pyArgsString if not argsString: argsString = '()' if '->' in argsString: pos = argsString.find(')') argsString = argsString[:pos+1] if '(' != argsString[0]: pos = argsString.find('(') argsString = argsString[pos:] argsString = argsString.replace('::', '.') stream.write(argsString) stream.write(':\n') stream.write(' """\n') stream.write(nci(function.pyDocstring, 4)) stream.write(' """\n')
def generateFunction(self, function, stream): assert isinstance(function, extractors.FunctionDef) if not function.pyName: return stream.write("\ndef %s" % function.pyName) if function.hasOverloads(): stream.write("(*args, **kw)") else: argsString = function.pyArgsString if not argsString: argsString = "()" if "->" in argsString: pos = argsString.find(")") argsString = argsString[: pos + 1] if "(" != argsString[0]: pos = argsString.find("(") argsString = argsString[pos:] argsString = argsString.replace("::", ".") stream.write(argsString) stream.write(":\n") stream.write(' """\n') stream.write(nci(function.pyDocstring, 4)) stream.write(' """\n')
def generateMethod(self, method, stream, indent): assert isinstance(method, extractors.MethodDef) _needDocstring = getattr(method, '_needDocstring', True) checkOverloads = True if not method.ignored: if method.isVirtual: stream.write("%svirtual\n" % indent) if method.isStatic: stream.write("%sstatic\n" % indent) if method.isCtor or method.isDtor: stream.write('%s%s(' % (indent, method.name)) else: stream.write('%s%s %s(' % (indent, method.type, method.name)) if method.items: stream.write('\n') self.generateParameters(method.items, stream, indent + ' ' * 4) stream.write(indent) stream.write(')') if method.isConst: stream.write(' const') if method.isPureVirtual: stream.write(' = 0') cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" if cppSig: stream.write(cppSig) stream.write('%s;\n' % self.annotate(method)) if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False if method.mustHaveAppFlag: stream.write('%s%%PreMethodCode\n' % indent) stream.write( nci("if (!wxPyCheckForApp()) return NULL;\n", len(indent) + 4)) stream.write('%s%%End\n' % indent) if method.cppCode: #checkOverloads = False ## SIP now allows overloads to have %MethodCode code, codeType = method.cppCode if codeType == 'sip': stream.write('%s%%MethodCode\n' % indent) stream.write(nci(code, len(indent) + 4)) stream.write('%s%%End\n' % indent) elif codeType == 'function': cm = extractors.CppMethodDef.FromMethod(method) cm.body = code self.generateCppMethod(cm, stream, indent, skipDeclaration=True) # generateCppMethod will have already done the overloads # and virtual catcher code, so we can just return from # here. return if method.virtualCatcherCode: stream.write('%s%%VirtualCatcherCode\n' % indent) stream.write(nci(method.virtualCatcherCode, len(indent) + 4)) stream.write('%s%%End\n' % indent) stream.write('\n') if checkOverloads and method.overloads: for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent)
def generateCppMethod(self, method, stream, indent='', skipDeclaration=False): # Add a new C++ method to a class. This one adds the code as a # separate function and then adds a call to that function in the # MethodCode directive. def _removeIgnoredParams(argsString, paramList): # if there are ignored parameters adjust the argsString to match lastP = argsString.rfind(')') args = argsString[:lastP].strip('()').split(',') for idx, p in enumerate(paramList): if p.ignored: args[idx] = '' args = [a for a in args if a != ''] return '(' + ', '.join(args) + ')' assert isinstance(method, extractors.CppMethodDef) if method.ignored: return _needDocstring = getattr(method, '_needDocstring', True) argsString = _removeIgnoredParams(method.argsString, method.items) lastP = argsString.rfind(')') pnames = argsString[:lastP].strip('()').split(',') for idx, pn in enumerate(pnames): # take only the part before the =, if there is one name = pn.split('=')[0].strip() # remove annotations name = re.sub('/[A-Za-z]*/', '', name) name = name.strip() # now get just the part after any space, * or &, which should be # the parameter name name = re.split(r'[ \*\&]+', name)[-1] pnames[idx] = name pnames = ', '.join(pnames) typ = method.type if not skipDeclaration: cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" # First insert the method declaration if method.isCtor or method.isDtor: virtual = 'virtual ' if method.isVirtual else '' stream.write('%s%s%s%s%s%s;\n' % (indent, virtual, method.name, argsString, self.annotate(method), cppSig)) else: constMod = " const" if method.isConst else "" static = "static " if method.isStatic else "" virtual = "virtual " if method.isVirtual else "" pure = " = 0" if method.isPureVirtual else "" stream.write('%s%s%s%s %s%s%s%s%s%s;\n' % (indent, static, virtual, typ, method.name, argsString, constMod, pure, self.annotate(method), cppSig)) # write the docstring if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False klass = method.klass if klass: assert isinstance(klass, extractors.ClassDef) # create the new function fstream = Utf8EncodingStream() # using a new stream so we can do the actual write a little later lastP = argsString.rfind(')') fargs = argsString[:lastP].strip('()').split(',') for idx, arg in enumerate(fargs): # take only the part before the =, if there is one arg = arg.split('=')[0].strip() arg = arg.replace('&', '*') # SIP will always want to use pointers for parameters arg = re.sub('/[A-Za-z]*/', '', arg) # remove annotations fargs[idx] = arg fargs = ', '.join(fargs) if method.isCtor: fname = '_%s_ctor' % klass.name fargs = '(%s)' % fargs fstream.write('%s%%TypeCode\n' % indent) typ = klass.name if method.useDerivedName: typ = 'sip'+klass.name fstream.write('%sclass %s;\n' % (indent, typ)) # forward declare the derived class fstream.write('%s%s* %s%s\n%s{\n' % (indent, typ, fname, fargs, indent)) fstream.write(nci(method.body, len(indent)+4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) elif method.isDtor: fname = '_%s_dtor' % klass.name fargs = '(%s* self)' % klass.name fstream.write('%s%%TypeCode\n' % indent) fstream.write('%svoid %s%s\n%s{\n' % (indent, fname, fargs, indent)) fstream.write(nci(method.body, len(indent)+4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) else: if klass: fname = '_%s_%s' % (klass.name, method.name) if method.isStatic: # If the method is static then there is no sipCpp to send to # the new function, so it should not have a self parameter. fargs = '(%s)' % fargs else: if fargs: fargs = ', ' + fargs selfConst = '' if method.isConst: selfConst = 'const ' fargs = '(%s%s* self%s)' % (selfConst, klass.name, fargs) fstream.write('%s%%TypeCode\n' % indent) else: fname = '_%s_function' % method.name fargs = '(%s)' % fargs fstream.write('%s%%ModuleCode\n' % indent) # If the return type is in the forcePtrTypes list then make sure # that it is a pointer, not a return by value or reference, since # SIP almost always deals with pointers to newly allocated # objects. typPtr = method.type if typPtr in forcePtrTypes: if '&' in typPtr: typPtr.replace('&', '*') elif '*' not in typPtr: typPtr += '*' fstream.write('%s%s %s%s\n%s{\n' % (indent, typPtr, fname, fargs, indent)) fstream.write(nci(method.body, len(indent)+4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) # Write the code that will call the new function stream.write('%s%%MethodCode\n' % indent) stream.write(indent+' '*4) if method.isCtor: stream.write('sipCpp = %s(%s);\n' % (fname, pnames)) elif method.isDtor: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent+' '*4)) stream.write(indent+' '*4) stream.write('%s(sipCpp);\n' % fname) stream.write('%sPy_END_ALLOW_THREADS\n' % (indent+' '*4)) else: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent+' '*4)) stream.write(indent+' '*4) if method.type != 'void': stream.write('sipRes = ') if klass: if method.isStatic: # If the method is static then there is no sipCpp to send to # the new function, so it should not have a self parameter. stream.write('%s(%s);\n' % (fname, pnames)) else: if pnames: pnames = ', ' + pnames stream.write('%s(sipCpp%s);\n' % (fname, pnames)) else: stream.write('%s(%s);\n' % (fname, pnames)) stream.write('%sPy_END_ALLOW_THREADS\n' % (indent+' '*4)) stream.write('%sif (PyErr_Occurred()) sipIsErr = 1;\n' % (indent+' '*4)) stream.write('%s%%End\n' % indent) if method.virtualCatcherCode: stream.write('%s%%VirtualCatcherCode\n' % indent) stream.write(nci(method.virtualCatcherCode, len(indent)+4)) stream.write('%s%%End\n' % indent) # and finally, add the new function itself stream.write(fstream.getvalue()) stream.write('\n') if method.overloads: for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent)
def generateClass(self, klass, stream, indent=""): assert isinstance(klass, extractors.ClassDef) if klass.ignored: return # check if there is a pi-customized version of the base class names if hasattr(klass, "piBases"): bases = klass.piBases else: # check if it's a template with the template parameter as the base class bases = klass.bases[:] for tp in klass.templateParams: if tp in bases: bases.remove(tp) # write class declaration klassName = klass.pyName or klass.name stream.write("\n%sclass %s" % (indent, klassName)) if bases: stream.write("(") bases = [self.fixWxPrefix(b, True) for b in bases] stream.write(", ".join(bases)) stream.write(")") else: stream.write("(object)") stream.write(":\n") indent2 = indent + " " * 4 # docstring stream.write('%s"""\n' % indent2) stream.write(nci(klass.pyDocstring, len(indent2))) stream.write('%s"""\n' % indent2) # generate nested classes for item in klass.innerclasses: self.generateClass(item, stream, indent2) # Split the items into public and protected groups enums = [i for i in klass if isinstance(i, extractors.EnumDef) and i.protection == "public"] ctors = [ i for i in klass if isinstance(i, extractors.MethodDef) and i.protection == "public" and (i.isCtor or i.isDtor) ] public = [i for i in klass if i.protection == "public" and i not in ctors and i not in enums] protected = [i for i in klass if i.protection == "protected"] dispatch = { extractors.MemberVarDef: self.generateMemberVar, extractors.TypedefDef: lambda a, b, c: None, extractors.PropertyDef: self.generateProperty, extractors.PyPropertyDef: self.generatePyProperty, extractors.MethodDef: self.generateMethod, extractors.EnumDef: self.generateEnum, extractors.CppMethodDef: self.generateCppMethod, extractors.CppMethodDef_sip: self.generateCppMethod_sip, extractors.PyMethodDef: self.generatePyMethod, extractors.PyCodeDef: self.generatePyCode, extractors.WigCode: self.generateWigCode, } for item in enums: item.klass = klass self.generateEnum(item, stream, indent2) for item in ctors: if item.isCtor: item.klass = klass self.generateMethod(item, stream, indent2, name="__init__", docstring=klass.pyDocstring) for item in public: item.klass = klass f = dispatch[item.__class__] f(item, stream, indent2) for item in protected: item.klass = klass f = dispatch[item.__class__] f(item, stream, indent2) stream.write("%s# end of class %s\n\n" % (indent, klassName))
def generateConvertCode(self, kind, code, stream, indent): stream.write('%s%s\n' % (indent, kind)) stream.write(nci(code, len(indent)+4)) stream.write('%s%%End\n' % indent)
def generateWigCode(self, wig, stream, indent=''): assert isinstance(wig, extractors.WigCode) stream.write(nci(wig.code, len(indent), False)) stream.write('\n\n')
def generateClass(self, klass, stream, indent=''): assert isinstance(klass, extractors.ClassDef) if klass.ignored or piIgnored(klass): return # check if there is a pi-customized version of the base class names if hasattr(klass, 'piBases'): bases = klass.piBases else: # check if it's a template with the template parameter as the base class bases = klass.bases[:] for tp in klass.templateParams: if tp in bases: bases.remove(tp) # write class declaration klassName = klass.pyName or klass.name stream.write('\n%sclass %s' % (indent, klassName)) if bases: stream.write('(') bases = [self.fixWxPrefix(b, True) for b in bases] stream.write(', '.join(bases)) stream.write(')') else: stream.write('(object)') stream.write(':\n') indent2 = indent + ' '*4 # docstring stream.write('%s"""\n' % indent2) stream.write(nci(klass.pyDocstring, len(indent2))) stream.write('%s"""\n' % indent2) # generate nested classes for item in klass.innerclasses: self.generateClass(item, stream, indent2) # Split the items into public and protected groups enums = [i for i in klass if isinstance(i, extractors.EnumDef) and i.protection == 'public'] ctors = [i for i in klass if isinstance(i, extractors.MethodDef) and i.protection == 'public' and (i.isCtor or i.isDtor)] public = [i for i in klass if i.protection == 'public' and i not in ctors and i not in enums] protected = [i for i in klass if i.protection == 'protected'] dispatch = { extractors.MemberVarDef : self.generateMemberVar, extractors.TypedefDef : lambda a,b,c: None, extractors.PropertyDef : self.generateProperty, extractors.PyPropertyDef : self.generatePyProperty, extractors.MethodDef : self.generateMethod, extractors.EnumDef : self.generateEnum, extractors.CppMethodDef : self.generateCppMethod, extractors.CppMethodDef_sip : self.generateCppMethod_sip, extractors.PyMethodDef : self.generatePyMethod, extractors.PyCodeDef : self.generatePyCode, extractors.WigCode : self.generateWigCode, } for item in enums: item.klass = klass self.generateEnum(item, stream, indent2) for item in ctors: if item.isCtor: item.klass = klass self.generateMethod(item, stream, indent2, name='__init__', docstring=klass.pyDocstring) for item in public: item.klass = klass f = dispatch[item.__class__] f(item, stream, indent2) for item in protected: item.klass = klass f = dispatch[item.__class__] f(item, stream, indent2) stream.write('%s# end of class %s\n\n' % (indent, klassName))
def generateClass(self, klass, stream, indent=''): assert isinstance(klass, extractors.ClassDef) if klass.ignored: return # write the class header if klass.templateParams: stream.write('%stemplate<%s>\n' % (indent, ', '.join(klass.templateParams))) stream.write('%s%s %s' % (indent, klass.kind, klass.name)) if klass.bases: stream.write(' : ') stream.write(', '.join(klass.bases)) stream.write(self.annotate(klass)) stream.write('\n%s{\n' % indent) indent2 = indent + ' '*4 if klass.briefDoc is not None: self.generateDocstring(klass, stream, indent2) if klass.includes: stream.write('%s%%TypeHeaderCode\n' % indent2) for inc in klass.includes: stream.write('%s #include <%s>\n' % (indent2, inc)) stream.write('%s%%End\n\n' % indent2) # C++ code to be written to the Type's header if klass.headerCode: stream.write("%s%%TypeHeaderCode\n" % indent2) for c in klass.headerCode: stream.write(nci(c, len(indent2)+4)) stream.write("%s%%End\n" % indent2) # C++ code to be written out to the this Type's wrapper code module if klass.cppCode: stream.write("%s%%TypeCode\n" % indent2) for c in klass.cppCode: stream.write(nci(c, len(indent2)+4)) stream.write("%s%%End\n" % indent2) # C++ code to create a new instance of this class if klass.instanceCode: stream.write("%s%%InstanceCode\n" % indent2) stream.write(nci(klass.instanceCode, len(indent2)+4)) stream.write("%s%%End\n" % indent2) # is the generator currently inside the class or after it? klass.generatingInClass = True # Split the items into public and protected groups ctors = [i for i in klass if isinstance(i, extractors.MethodDef) and i.protection == 'public' and (i.isCtor or i.isDtor)] enums = [i for i in klass if isinstance(i, extractors.EnumDef) and i.protection == 'public'] public = [i for i in klass if i.protection == 'public' and i not in ctors+enums] protected = [i for i in klass if i.protection == 'protected'] private = [i for i in klass if i.protection == 'private'] if klass.kind == 'class': stream.write('%spublic:\n' % indent) # Write enums first since they may be used as default values in # methods or in nested classes for item in enums: self.dispatchClassItem(klass, item, stream, indent2) # Next do inner classes for item in klass.innerclasses: if klass.kind == 'class': stream.write('%s%s:\n' % (indent, item.protection)) item.klass = klass self.generateClass(item, stream, indent2) # and then the ctors and the rest of the items in the class for item in ctors: self.dispatchClassItem(klass, item, stream, indent2) for item in public: self.dispatchClassItem(klass, item, stream, indent2) if protected and [i for i in protected if not i.ignored]: stream.write('\nprotected:\n') for item in protected: self.dispatchClassItem(klass, item, stream, indent2) if private and [i for i in private if not i.ignored]: stream.write('\nprivate:\n') for item in private: self.dispatchClassItem(klass, item, stream, indent2) if klass.convertFromPyObject: self.generateConvertCode('%ConvertToTypeCode', klass.convertFromPyObject, stream, indent + ' '*4) if klass.convertToPyObject: self.generateConvertCode('%ConvertFromTypeCode', klass.convertToPyObject, stream, indent + ' '*4) stream.write('%s}; // end of class %s\n\n\n' % (indent, klass.name)) # Now generate anything that was deferred until after the class is finished klass.generatingInClass = False for item in klass.generateAfterClass: self.dispatchClassItem(klass, item, stream, indent)
def generateCppMethod(self, method, stream, indent='', skipDeclaration=False): # Add a new C++ method to a class. This one adds the code as a # separate function and then adds a call to that function in the # MethodCode directive. def _removeIgnoredParams(argsString, paramList): # if there are ignored parameters adjust the argsString to match lastP = argsString.rfind(')') args = argsString[:lastP].strip('()').split(',') for idx, p in enumerate(paramList): if p.ignored: args[idx] = '' args = [a for a in args if a != ''] return '(' + ', '.join(args) + ')' assert isinstance(method, extractors.CppMethodDef) if method.ignored: return _needDocstring = getattr(method, '_needDocstring', True) argsString = _removeIgnoredParams(method.argsString, method.items) lastP = argsString.rfind(')') pnames = argsString[:lastP].strip('()').split(',') for idx, pn in enumerate(pnames): # take only the part before the =, if there is one name = pn.split('=')[0].strip() # remove annotations name = re.sub('/[A-Za-z]*/', '', name) name = name.strip() # now get just the part after any space, * or &, which should be # the parameter name name = re.split(r'[ \*\&]+', name)[-1] pnames[idx] = name pnames = ', '.join(pnames) typ = method.type if not skipDeclaration: cppSig = " [ %s ]" % method.cppSignature if method.cppSignature else "" # First insert the method declaration if method.isCtor or method.isDtor: virtual = 'virtual ' if method.isVirtual else '' stream.write('%s%s%s%s%s%s;\n' % (indent, virtual, method.name, argsString, self.annotate(method), cppSig)) else: constMod = " const" if method.isConst else "" static = "static " if method.isStatic else "" virtual = "virtual " if method.isVirtual else "" pure = " = 0" if method.isPureVirtual else "" stream.write( '%s%s%s%s %s%s%s%s%s%s;\n' % (indent, static, virtual, typ, method.name, argsString, constMod, pure, self.annotate(method), cppSig)) # write the docstring if _needDocstring and not (method.isCtor or method.isDtor): self.generateDocstring(method, stream, indent) # We only write a docstring for the first overload, otherwise # SIP appends them all together. _needDocstring = False klass = method.klass if klass: assert isinstance(klass, extractors.ClassDef) # create the new function fstream = Utf8EncodingStream( ) # using a new stream so we can do the actual write a little later lastP = argsString.rfind(')') fargs = argsString[:lastP].strip('()').split(',') for idx, arg in enumerate(fargs): # take only the part before the =, if there is one arg = arg.split('=')[0].strip() arg = arg.replace( '&', '*') # SIP will always want to use pointers for parameters arg = re.sub('/[A-Za-z]*/', '', arg) # remove annotations fargs[idx] = arg fargs = ', '.join(fargs) if method.isCtor: fname = '_%s_ctor' % klass.name fargs = '(%s)' % fargs fstream.write('%s%%TypeCode\n' % indent) typ = klass.name if method.useDerivedName: typ = 'sip' + klass.name fstream.write( '%sclass %s;\n' % (indent, typ)) # forward declare the derived class fstream.write('%s%s* %s%s\n%s{\n' % (indent, typ, fname, fargs, indent)) fstream.write(nci(method.body, len(indent) + 4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) elif method.isDtor: fname = '_%s_dtor' % klass.name fargs = '(%s* self)' % klass.name fstream.write('%s%%TypeCode\n' % indent) fstream.write('%svoid %s%s\n%s{\n' % (indent, fname, fargs, indent)) fstream.write(nci(method.body, len(indent) + 4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) else: if klass: fname = '_%s_%s' % (klass.name, method.name) if method.isStatic: # If the method is static then there is no sipCpp to send to # the new function, so it should not have a self parameter. fargs = '(%s)' % fargs else: if fargs: fargs = ', ' + fargs selfConst = '' if method.isConst: selfConst = 'const ' fargs = '(%s%s* self%s)' % (selfConst, klass.name, fargs) fstream.write('%s%%TypeCode\n' % indent) else: fname = '_%s_function' % method.name fargs = '(%s)' % fargs fstream.write('%s%%ModuleCode\n' % indent) # If the return type is in the forcePtrTypes list then make sure # that it is a pointer, not a return by value or reference, since # SIP almost always deals with pointers to newly allocated # objects. typPtr = method.type if typPtr in forcePtrTypes: if '&' in typPtr: typPtr.replace('&', '*') elif '*' not in typPtr: typPtr += '*' fstream.write('%s%s %s%s\n%s{\n' % (indent, typPtr, fname, fargs, indent)) fstream.write(nci(method.body, len(indent) + 4)) fstream.write('%s}\n' % indent) fstream.write('%s%%End\n' % indent) # Write the code that will call the new function stream.write('%s%%MethodCode\n' % indent) stream.write(indent + ' ' * 4) if method.isCtor: # _THREAD macros are intentionally not used in this case stream.write('PyErr_Clear();\n') stream.write('%ssipCpp = %s(%s);\n' % (indent + ' ' * 4, fname, pnames)) elif method.isDtor: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent + ' ' * 4)) stream.write(indent + ' ' * 4) stream.write('%s(sipCpp);\n' % fname) stream.write('%sPy_END_ALLOW_THREADS\n' % (indent + ' ' * 4)) else: stream.write('PyErr_Clear();\n') stream.write('%sPy_BEGIN_ALLOW_THREADS\n' % (indent + ' ' * 4)) stream.write(indent + ' ' * 4) if method.type != 'void': stream.write('sipRes = ') if klass: if method.isStatic: # If the method is static then there is no sipCpp to send to # the new function, so it should not have a self parameter. stream.write('%s(%s);\n' % (fname, pnames)) else: if pnames: pnames = ', ' + pnames if method.isSlot: argname = 'a0' else: argname = 'sipCpp' stream.write('%s(%s%s);\n' % (fname, argname, pnames)) else: stream.write('%s(%s);\n' % (fname, pnames)) stream.write('%sPy_END_ALLOW_THREADS\n' % (indent + ' ' * 4)) stream.write('%sif (PyErr_Occurred()) sipIsErr = 1;\n' % (indent + ' ' * 4)) stream.write('%s%%End\n' % indent) if method.virtualCatcherCode: stream.write('%s%%VirtualCatcherCode\n' % indent) stream.write(nci(method.virtualCatcherCode, len(indent) + 4)) stream.write('%s%%End\n' % indent) # and finally, add the new function itself stream.write(fstream.getvalue()) stream.write('\n') if method.overloads: for m in method.overloads: m._needDocstring = _needDocstring self.dispatchClassItem(method.klass, m, stream, indent)
def generateConvertCode(self, kind, code, stream, indent): stream.write('%s%s\n' % (indent, kind)) stream.write(nci(code, len(indent) + 4)) stream.write('%s%%End\n' % indent)
def generateClass(self, klass, stream, indent=''): assert isinstance(klass, extractors.ClassDef) if klass.ignored: return # Propagate mustHaveApp setting to the ctors if klass.mustHaveAppFlag: for item in klass.allItems(): if isinstance(item, extractors.MethodDef) and item.isCtor: item.mustHaveApp(True) # write the class header if klass.templateParams: stream.write('%stemplate<%s>\n' % (indent, ', '.join(klass.templateParams))) stream.write('%s%s %s' % (indent, klass.kind, klass.name)) if klass.bases: stream.write(' : ') stream.write(', '.join(klass.bases)) stream.write(self.annotate(klass)) stream.write('\n%s{\n' % indent) indent2 = indent + ' ' * 4 if klass.briefDoc is not None: self.generateDocstring(klass, stream, indent2) if klass.includes: stream.write('%s%%TypeHeaderCode\n' % indent2) for inc in klass.includes: stream.write('%s #include <%s>\n' % (indent2, inc)) stream.write('%s%%End\n\n' % indent2) # C++ code to be written to the Type's header if klass.headerCode: stream.write("%s%%TypeHeaderCode\n" % indent2) for c in klass.headerCode: stream.write(nci(c, len(indent2) + 4)) stream.write("%s%%End\n" % indent2) # C++ code to be written out to the this Type's wrapper code module if klass.cppCode: stream.write("%s%%TypeCode\n" % indent2) for c in klass.cppCode: stream.write(nci(c, len(indent2) + 4)) stream.write("%s%%End\n" % indent2) # C++ code to create a new instance of this class if klass.instanceCode: stream.write("%s%%InstanceCode\n" % indent2) stream.write(nci(klass.instanceCode, len(indent2) + 4)) stream.write("%s%%End\n" % indent2) # is the generator currently inside the class or after it? klass.generatingInClass = True # Split the items into public and protected groups ctors = [ i for i in klass if isinstance(i, extractors.MethodDef) and i.protection == 'public' and (i.isCtor or i.isDtor) ] enums = [ i for i in klass if isinstance(i, extractors.EnumDef) and i.protection == 'public' ] public = [ i for i in klass if i.protection == 'public' and i not in ctors + enums ] protected = [i for i in klass if i.protection == 'protected'] private = [i for i in klass if i.protection == 'private'] if klass.kind == 'class': stream.write('%spublic:\n' % indent) # Write enums first since they may be used as default values in # methods or in nested classes for item in enums: self.dispatchClassItem(klass, item, stream, indent2) # Next do inner classes for item in klass.innerclasses: if klass.kind == 'class': stream.write('%s%s:\n' % (indent, item.protection)) item.klass = klass self.generateClass(item, stream, indent2) # and then the ctors and the rest of the items in the class for item in ctors: self.dispatchClassItem(klass, item, stream, indent2) for item in public: self.dispatchClassItem(klass, item, stream, indent2) if protected and [i for i in protected if not i.ignored]: stream.write('\nprotected:\n') for item in protected: self.dispatchClassItem(klass, item, stream, indent2) if private and [i for i in private if not i.ignored]: stream.write('\nprivate:\n') for item in private: self.dispatchClassItem(klass, item, stream, indent2) if klass.convertFromPyObject: self.generateConvertCode('%ConvertToTypeCode', klass.convertFromPyObject, stream, indent + ' ' * 4) if klass.convertToPyObject: self.generateConvertCode('%ConvertFromTypeCode', klass.convertToPyObject, stream, indent + ' ' * 4) stream.write('%s}; // end of class %s\n\n\n' % (indent, klass.name)) # Now generate anything that was deferred until after the class is finished klass.generatingInClass = False for item in klass.generateAfterClass: self.dispatchClassItem(klass, item, stream, indent)