📄 classexporter.py
字号:
nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)]
for enum in nested_enums:
enum_info = self.info[enum.name]
enum_info.include = self.info.include
enum_info.name = enum.FullName()
exporter = EnumExporter(enum_info)
exporter.SetDeclarations(self.declarations)
codeunit = SingleCodeUnit(None, None)
exporter.Export(codeunit, exported_names)
self.nested_codeunits.append(codeunit)
def ExportSmartPointer(self):
smart_ptr = self.info.smart_ptr
if smart_ptr:
class_name = self.class_.FullName()
smart_ptr = smart_ptr % class_name
self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
def ExportOpaquePointerPolicies(self):
# check all methods for 'return_opaque_pointer' policies
methods = [x for x in self.public_members if isinstance(x, Method)]
for method in methods:
return_opaque_policy = return_value_policy(return_opaque_pointer)
if self.info[method.name].policy == return_opaque_policy:
macro = exporterutils.EspecializeTypeID(method.result.name)
if macro:
self.Add('declaration-outside', macro)
def ExportAddedCode(self):
if self.info.__code__:
for code in self.info.__code__:
self.Add('inside', code)
#==============================================================================
# Virtual Wrapper utils
#==============================================================================
def _ParamsInfo(m, count=None):
if count is None:
count = len(m.parameters)
param_names = ['p%i' % i for i in range(count)]
param_types = [x.FullName() for x in m.parameters[:count]]
params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)]
#for i, p in enumerate(m.parameters[:count]):
# if p.default is not None:
# #params[i] += '=%s' % p.default
# params[i] += '=%s' % (p.name + '()')
params = ', '.join(params)
return params, param_names, param_types
class _VirtualWrapperGenerator(object):
'Generates code to export the virtual methods of the given class'
def __init__(self, class_, bases, info, codeunit):
self.class_ = copy.deepcopy(class_)
self.bases = bases[:]
self.info = info
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
self.virtual_methods = None
self._method_count = {}
self.codeunit = codeunit
self.GenerateVirtualMethods()
SELF = 'py_self'
def DefaultImplementationNames(self, method):
'''Returns a list of default implementations for this method, one for each
number of default arguments. Always returns at least one name, and return from
the one with most arguments to the one with the least.
'''
base_name = 'default_' + method.name
minArgs = method.minArgs
maxArgs = method.maxArgs
if minArgs == maxArgs:
return [base_name]
else:
return [base_name + ('_%i' % i) for i in range(minArgs, maxArgs+1)]
def Declaration(self, method, indent):
'''Returns a string with the declarations of the virtual wrapper and
its default implementations. This string must be put inside the Wrapper
body.
'''
pyste = namespaces.pyste
python = namespaces.python
rename = self.info[method.name].rename or method.name
result = method.result.FullName()
return_str = 'return '
if result == 'void':
return_str = ''
params, param_names, param_types = _ParamsInfo(method)
constantness = ''
if method.const:
constantness = ' const'
# call_method callback
decl = indent + '%s %s(%s)%s%s {\n' % (result, method.name, params, constantness, method.Exceptions())
param_names_str = ', '.join(param_names)
if param_names_str:
param_names_str = ', ' + param_names_str
self_str = self.SELF
decl += indent*2 + '%(return_str)s%(python)scall_method< %(result)s >' \
'(%(self_str)s, "%(rename)s"%(param_names_str)s);\n' % locals()
decl += indent + '}\n'
# default implementations (with overloading)
def DefaultImpl(method, param_names):
'Return the body of a default implementation wrapper'
indent2 = indent * 2
wrapper = self.info[method.name].wrapper
if not wrapper:
# return the default implementation of the class
return indent2 + '%s%s(%s);\n' % \
(return_str, method.FullName(), ', '.join(param_names))
else:
if wrapper.code:
self.codeunit.Write('declaration-outside', wrapper.code)
# return a call for the wrapper
params = ', '.join(['this'] + param_names)
return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
if not method.abstract and method.visibility != Scope.private:
minArgs = method.minArgs
maxArgs = method.maxArgs
impl_names = self.DefaultImplementationNames(method)
for impl_name, argNum in zip(impl_names, range(minArgs, maxArgs+1)):
params, param_names, param_types = _ParamsInfo(method, argNum)
decl += '\n'
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
decl += DefaultImpl(method, param_names)
decl += indent + '}\n'
return decl
def MethodDefinition(self, method):
'''Returns a list of lines, which should be put inside the class_
statement to export this method.'''
# dont define abstract methods
pyste = namespaces.pyste
rename = self.info[method.name].rename or method.name
default_names = self.DefaultImplementationNames(method)
class_name = self.class_.FullName()
wrapper_name = pyste + self.wrapper_name
result = method.result.FullName()
is_method_unique = method.is_unique
constantness = ''
if method.const:
constantness = ' const'
# create a list of default-impl pointers
minArgs = method.minArgs
maxArgs = method.maxArgs
if method.abstract:
default_pointers = []
elif is_method_unique:
default_pointers = ['&%s::%s' % (wrapper_name, x) for x in default_names]
else:
default_pointers = []
for impl_name, argNum in zip(default_names, range(minArgs, maxArgs+1)):
param_list = [x.FullName() for x in method.parameters[:argNum]]
params = ', '.join(param_list)
signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness)
default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name)
default_pointers.append(default_pointer)
# get the pointer of the method
pointer = method.PointerDeclaration()
if method.abstract:
pointer = namespaces.python + ('pure_virtual(%s)' % pointer)
# warn the user if this method needs a policy and doesn't have one
method_info = self.info[method.name]
method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
# Add policy to overloaded methods also
policy = method_info.policy or ''
if policy:
policy = ', %s%s()' % (namespaces.python, policy.Code())
# generate the defs
definitions = []
# basic def
if default_pointers:
definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy))
for default_pointer in default_pointers[:-1]:
definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy))
else:
definitions.append('.def("%s", %s%s)' % (rename, pointer, policy))
return definitions
def FullName(self):
return namespaces.pyste + self.wrapper_name
def GenerateVirtualMethods(self):
'''To correctly export all virtual methods, we must also make wrappers
for the virtual methods of the bases of this class, as if the methods
were from this class itself.
This method creates the instance variable self.virtual_methods.
'''
def IsVirtual(m):
if type(m) is Method:
pure_virtual = m.abstract and m.virtual
virtual = m.virtual and m.visibility != Scope.private
return virtual or pure_virtual
else:
return False
# extract the virtual methods, avoiding duplications. The duplication
# must take in account the full signature without the class name, so
# that inherited members are correctly excluded if the subclass overrides
# them.
def MethodSig(method):
if method.const:
const = ' const'
else:
const = ''
if method.result:
result = method.result.FullName()
else:
result = ''
params = ', '.join([x.FullName() for x in method.parameters])
return '%s %s(%s)%s%s' % (
result, method.name, params, const, method.Exceptions())
already_added = {}
self.virtual_methods = []
for member in self.class_:
if IsVirtual(member):
already_added[MethodSig(member)] = None
self.virtual_methods.append(member)
for base in self.bases:
base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)]
for base_method in base_methods:
self.class_.AddMember(base_method)
all_methods = [x for x in self.class_ if IsVirtual(x)]
for member in all_methods:
sig = MethodSig(member)
if IsVirtual(member) and not sig in already_added:
self.virtual_methods.append(member)
already_added[sig] = 0
def Constructors(self):
return self.class_.Constructors(publics_only=True)
def GenerateDefinitions(self):
defs = []
for method in self.virtual_methods:
exclude = self.info[method.name].exclude
# generate definitions only for public methods and non-abstract methods
if method.visibility == Scope.public and not exclude:
defs.extend(self.MethodDefinition(method))
return defs
def GenerateVirtualWrapper(self, indent):
'Return the wrapper for this class'
# generate the class code
class_name = self.class_.FullName()
code = 'struct %s: %s\n' % (self.wrapper_name, class_name)
code += '{\n'
# generate constructors (with the overloads for each one)
for cons in self.Constructors(): # only public constructors
minArgs = cons.minArgs
maxArgs = cons.maxArgs
# from the min number of arguments to the max number, generate
# all version of the given constructor
cons_code = ''
for argNum in range(minArgs, maxArgs+1):
params, param_names, param_types = _ParamsInfo(cons, argNum)
if params:
params = ', ' + params
cons_code += indent + '%s(PyObject* %s_%s):\n' % \
(self.wrapper_name, self.SELF, params)
cons_code += indent*2 + '%s(%s), %s(%s_) {}\n\n' % \
(class_name, ', '.join(param_names), self.SELF, self.SELF)
code += cons_code
# generate the body
body = []
for method in self.virtual_methods:
if not self.info[method.name].exclude:
body.append(self.Declaration(method, indent))
body = '\n'.join(body)
code += body + '\n'
# add the self member
code += indent + 'PyObject* %s;\n' % self.SELF
code += '};\n'
return code
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -