⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 classexporter.py

📁 C++的一个好库。。。现在很流行
💻 PY
📖 第 1 页 / 共 3 页
字号:
# 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 exporters
from Exporter import Exporter
from declarations import *
from settings import *
from policies import *
from SingleCodeUnit import SingleCodeUnit
from EnumExporter import EnumExporter
from utils import makeid, enumerate
import copy
import exporterutils
import 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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -