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 + -
显示快捷键?