classexporter.py
来自「Boost provides free peer-reviewed portab」· Python 代码 · 共 919 行 · 第 1/3 页
PY
919 行
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and # distribution is subject to the Boost Software License, Version 1.0.# (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt)import exportersfrom Exporter import Exporterfrom declarations import *from settings import *from policies import *from SingleCodeUnit import SingleCodeUnitfrom EnumExporter import EnumExporterfrom utils import makeid, enumerateimport copyimport exporterutilsimport re#==============================================================================# ClassExporter#==============================================================================class ClassExporter(Exporter): 'Generates boost.python code to export a class declaration' def __init__(self, info, parser_tail=None): Exporter.__init__(self, info, parser_tail) # sections of code self.sections = {} # template: each item in the list is an item into the class_<...> # section. self.sections['template'] = [] # constructor: each item in the list is a parameter to the class_ # constructor, like class_<C>(...) self.sections['constructor'] = [] # inside: everything within the class_<> statement self.sections['inside'] = [] # scope: items outside the class statement but within its scope. # scope* s = new scope(class<>()); # ... # delete s; self.sections['scope'] = [] # declarations: outside the BOOST_PYTHON_MODULE macro self.sections['declaration'] = [] self.sections['declaration-outside'] = [] self.sections['include'] = [] # a list of Constructor instances self.constructors = [] # a list of code units, generated by nested declarations self.nested_codeunits = [] def ScopeName(self): return makeid(self.class_.FullName()) + '_scope' def Name(self): return self.info.name def SetDeclarations(self, declarations): Exporter.SetDeclarations(self, declarations) if self.declarations: decl = self.GetDeclaration(self.info.name) if isinstance(decl, Typedef): self.class_ = self.GetDeclaration(decl.type.name) if not self.info.rename: self.info.rename = decl.name else: self.class_ = decl self.class_ = copy.deepcopy(self.class_) else: self.class_ = None def ClassBases(self): all_bases = [] for level in self.class_.hierarchy: for base in level: all_bases.append(base) return [self.GetDeclaration(x.name) for x in all_bases] def Order(self): '''Return the TOTAL number of bases that this class has, including the bases' bases. Do this because base classes must be instantialized before the derived classes in the module definition. ''' num_bases = len(self.ClassBases()) return num_bases, self.class_.FullName() def Export(self, codeunit, exported_names): self.InheritMethods(exported_names) self.MakeNonVirtual() if not self.info.exclude: self.ExportBasics() self.ExportBases(exported_names) self.ExportConstructors() self.ExportVariables() self.ExportVirtualMethods(codeunit) self.ExportMethods() self.ExportOperators() self.ExportNestedClasses(exported_names) self.ExportNestedEnums(exported_names) self.ExportSmartPointer() self.ExportOpaquePointerPolicies() self.ExportAddedCode() self.Write(codeunit) exported_names[self.Name()] = 1 def InheritMethods(self, exported_names): '''Go up in the class hierarchy looking for classes that were not exported yet, and then add their public members to this classes members, as if they were members of this class. This allows the user to just export one type and automatically get all the members from the base classes. ''' valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration) fullnames = [x.FullName() for x in self.class_] pointers = [x.PointerDeclaration(True) for x in self.class_ if isinstance(x, Method)] fullnames = dict([(x, None) for x in fullnames]) pointers = dict([(x, None) for x in pointers]) for level in self.class_.hierarchy: level_exported = False for base in level: base = self.GetDeclaration(base.name) if base.FullName() not in exported_names: for member in base: if type(member) in valid_members: member_copy = copy.deepcopy(member) member_copy.class_ = self.class_.FullName() if isinstance(member_copy, Method): pointer = member_copy.PointerDeclaration(True) if pointer not in pointers: self.class_.AddMember(member) pointers[pointer] = None elif member_copy.FullName() not in fullnames: self.class_.AddMember(member) else: level_exported = True if level_exported: break def IsValid(member): return isinstance(member, valid_members) and member.visibility == Scope.public self.public_members = [x for x in self.class_ if IsValid(x)] def Write(self, codeunit): indent = self.INDENT boost_ns = namespaces.python pyste_ns = namespaces.pyste code = '' # begin a scope for this class if needed nested_codeunits = self.nested_codeunits needs_scope = self.sections['scope'] or nested_codeunits if needs_scope: scope_name = self.ScopeName() code += indent + boost_ns + 'scope* %s = new %sscope(\n' %\ (scope_name, boost_ns) # export the template section template_params = ', '.join(self.sections['template']) code += indent + boost_ns + 'class_< %s >' % template_params # export the constructor section constructor_params = ', '.join(self.sections['constructor']) code += '(%s)\n' % constructor_params # export the inside section in_indent = indent*2 for line in self.sections['inside']: code += in_indent + line + '\n' # write the scope section and end it if not needs_scope: code += indent + ';\n' else: code += indent + ');\n' for line in self.sections['scope']: code += indent + line + '\n' # write the contents of the nested classes for nested_unit in nested_codeunits: code += '\n' + nested_unit.Section('module') # close the scope code += indent + 'delete %s;\n' % scope_name # write the code to the module section in the codeunit codeunit.Write('module', code + '\n') # write the declarations to the codeunit declarations = '\n'.join(self.sections['declaration']) for nested_unit in nested_codeunits: declarations += nested_unit.Section('declaration') if declarations: codeunit.Write('declaration', declarations + '\n') declarations_outside = '\n'.join(self.sections['declaration-outside']) if declarations_outside: codeunit.Write('declaration-outside', declarations_outside + '\n') # write the includes to the codeunit includes = '\n'.join(self.sections['include']) for nested_unit in nested_codeunits: includes += nested_unit.Section('include') if includes: codeunit.Write('include', includes) def Add(self, section, item): 'Add the item into the corresponding section' self.sections[section].append(item) def ExportBasics(self): '''Export the name of the class and its class_ statement.''' class_name = self.class_.FullName() self.Add('template', class_name) name = self.info.rename or self.class_.name self.Add('constructor', '"%s"' % name) def ExportBases(self, exported_names): 'Expose the bases of the class into the template section' hierarchy = self.class_.hierarchy exported = [] for level in hierarchy: for base in level: if base.visibility == Scope.public and base.name in exported_names: exported.append(base.name) if exported: break if exported: code = namespaces.python + 'bases< %s > ' % (', '.join(exported)) self.Add('template', code) def ExportConstructors(self): '''Exports all the public contructors of the class, plus indicates if the class is noncopyable. ''' py_ns = namespaces.python indent = self.INDENT def init_code(cons): 'return the init<>() code for the given contructor' param_list = [p.FullName() for p in cons.parameters] min_params_list = param_list[:cons.minArgs] max_params_list = param_list[cons.minArgs:] min_params = ', '.join(min_params_list) max_params = ', '.join(max_params_list) init = py_ns + 'init< ' init += min_params if max_params: if min_params: init += ', ' init += py_ns + ('optional< %s >' % max_params) init += ' >()' return init constructors = [x for x in self.public_members if isinstance(x, Constructor)] # don't export copy constructors if the class is abstract # we could remove all constructors, but this will have the effect of # inserting no_init in the declaration, which would not allow # even subclasses to be instantiated. self.constructors = constructors[:] if self.class_.abstract: for cons in constructors: if cons.IsCopy(): constructors.remove(cons) break if not constructors: # declare no_init self.Add('constructor', py_ns + 'no_init') else: # write the constructor with less parameters to the constructor section smaller = None for cons in constructors: if smaller is None or len(cons.parameters) < len(smaller.parameters): smaller = cons assert smaller is not None self.Add('constructor', init_code(smaller)) constructors.remove(smaller) # write the rest to the inside section, using def() for cons in constructors: code = '.def(%s)' % init_code(cons) self.Add('inside', code) # check if the class is copyable if not self.class_.HasCopyConstructor() or self.class_.abstract: self.Add('template', namespaces.boost + 'noncopyable') def ExportVariables(self): 'Export the variables of the class, both static and simple variables' vars = [x for x in self.public_members if isinstance(x, Variable)] for var in vars: if self.info[var.name].exclude: continue name = self.info[var.name].rename or var.name fullname = var.FullName() if var.type.const: def_ = '.def_readonly' else: def_ = '.def_readwrite' code = '%s("%s", &%s)' % (def_, name, fullname) self.Add('inside', code) def OverloadName(self, method): 'Returns the name of the overloads struct for the given method' name = makeid(method.FullName())
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?