Add ability to generate code into a .py file which does the import of the extension module. This will be used to add Python code to a module so we dont' have to do everything in C++.

git-svn-id: https://svn.wxwidgets.org/svn/wx/sandbox/trunk/Phoenix@66127 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2010-11-12 22:20:16 +00:00
parent 7ddbef68b5
commit 4b9c4f29c7

View File

@@ -50,17 +50,34 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
""")
if module.name == module.module:
stream.write("""
%%Module %s.%s
%%Module(name=%s.%s, use_argument_names=True)
%%Copying
Copyright: (c) 2010 by Total Control Software
Licence: wxWindows license
%%End
%%RealArgNames
""" % (module.package, module.name))
if module.name.startswith('_'):
doc = ''
if module.docstring:
doc = '\n"""\n%s\n"""\n' % module.docstring
stream.write("""\
%%Extract pycode
# This file is generated by wxPython's SIP generator. Do not edit by hand.
#
# Copyright: (c) 2010 by Total Control Software
# Licence: wxWindows license
%s
from %s import *
%%End
""" % (doc, module.name))
else:
stream.write("//\n// This file is included from %s.sip\n//\n" % module.module)
stream.write("//\n// This file will be included by %s.sip\n//\n" % module.module)
stream.write(divider)
@@ -118,6 +135,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
extractors.GlobalVarDef : self.generateGlobalVar,
extractors.TypedefDef : self.generateTypedef,
extractors.WigCode : self.generateWigCode,
extractors.PyCodeDef : self.generatePyCode,
}
for item in module:
@@ -194,11 +212,21 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
#-----------------------------------------------------------------------
def generateWigCode(self, wig, stream, indent=''):
assert isinstance(wig, extractors.WigCode)
lines = [indent+line for line in wig.code.split('\n')]
stream.write('\n'.join(lines))
stream.write(nci(wig.code, len(indent), False))
stream.write('\n\n')
#-----------------------------------------------------------------------
def generatePyCode(self, pc, stream, indent=''):
assert isinstance(pc, extractors.PyCodeDef)
if hasattr(pc, 'klass') and pc.klass.generatingInClass:
pc.klass.generateAfterClass.append(pc)
else:
stream.write('%Extract pycode\n')
stream.write(nci(pc.code, 4))
stream.write('\n%End\n\n')
#-----------------------------------------------------------------------
def generateClass(self, klass, stream, indent=''):
assert isinstance(klass, extractors.ClassDef)
@@ -218,6 +246,9 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
stream.write('%s #include <%s>\n' % (indent, inc))
stream.write('%s%%End\n' % indent)
stream.write('\n%spublic:\n' % indent)
# 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
@@ -232,6 +263,8 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
extractors.MethodDef : self.generateMethod,
extractors.EnumDef : self.generateEnum,
extractors.CppMethodDef : self.generateCppMethod,
extractors.PyMethodDef : self.generatePyMethod,
extractors.PyCodeDef : self.generatePyCode,
extractors.WigCode : self.generateWigCode,
# TODO: nested classes too?
}
@@ -250,28 +283,37 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
f(item, stream, indent + ' '*4)
if klass.convertFromPyObject:
stream.write('%s%%ConvertToTypeCode\n' % indent)
lines = [indent+l for l in klass.convertFromPyObject.split('\n')]
stream.write('\n'.join(lines))
stream.write('%s%%End\n' % indent)
self.generateConvertCode('%ConvertToTypeCode',
klass.convertFromPyObject,
stream, indent + ' '*4)
if klass.convertToPyObject:
stream.write('%s%%ConvertFromTypeCode\n' % indent)
lines = [indent+l for l in klass.convertToPyObject.split('\n')]
stream.write('\n'.join(lines))
stream.write('%s%%End\n' % indent)
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:
f = dispatch[item.__class__]
f(item, 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 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('%s;\n' % self.annotate(memberVar))
stream.write('%s;\n\n' % self.annotate(memberVar))
def generateProperty(self, prop, stream, indent):
@@ -320,12 +362,24 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
(indent, method.type, method.name, method.argsString,
self.annotate(method)))
stream.write('%s%%MethodCode\n' % indent)
lines = [indent+l for l in method.body.split('\n')]
stream.write('\n'.join(lines))
if len(lines) == 1:
stream.write('\n%s' % indent)
stream.write('%End\n\n')
stream.write(nci(method.body, len(indent)+4))
stream.write('%s%%End\n\n' % indent)
def generatePyMethod(self, pm, stream, indent):
assert isinstance(pm, extractors.PyMethodDef)
if pm.klass.generatingInClass:
pm.klass.generateAfterClass.append(pm)
else:
klassName = pm.klass.pyName or pm.klass.name
stream.write("%Extract pycode\n")
stream.write("def _%s_%s%s:\n" % (klassName, pm.name, pm.argsString))
if pm.briefDoc:
stream.write(nci('"""\n%s\n"""\n' % pm.briefDoc, 4))
stream.write(nci(pm.body, 4))
stream.write('%s.%s = _%s_%s\n' % (klassName, pm.name, klassName, pm.name))
stream.write('\n%End\n\n')
#-----------------------------------------------------------------------
def annotate(self, item):
@@ -383,3 +437,48 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
return ''
#---------------------------------------------------------------------------
# helpers and utilities
def nci(text, numSpaces=0, stripLeading=True):
"""
Normalize Code Indents
First use the count of leading spaces on the first line and remove that
many spaces from the front of all lines, and then indent each line by
adding numSpaces spaces. This is used so we can convert the arbitrary
indents that might be used by the treaker code into what is expected for
the context we are generating for.
"""
def _getLeadingSpaceCount(line):
count = 0
for c in line:
assert c != '\t', "Use spaces for indent, not tabs"
if c != ' ':
break
count += 1
else:
assert False, "First line should not be empty."
return count
def _allSpaces(text):
for c in text:
if c != ' ':
return False
return True
lines = text.rstrip().split('\n')
if stripLeading:
numStrip = _getLeadingSpaceCount(lines[0])
else:
numStrip = 0
for idx, line in enumerate(lines):
assert _allSpaces(line[:numStrip]), "Indentation inconsistent with first line"
lines[idx] = ' '*numSpaces + line[numStrip:]
newText = '\n'.join(lines) + '\n'
return newText
#---------------------------------------------------------------------------