def cullOverloadedMethods(self): """ Find all the entries that have multiple indexes for the same method name Get rid of all others. Do this for class methods and instance methods """ self.overloadedClassMethods = FFIOverload.cullOverloadedMethods(self.overloadedClassMethods) self.overloadedInstanceMethods = FFIOverload.cullOverloadedMethods(self.overloadedInstanceMethods)
def generateReturnValueWrapper(self, classTypeDesc, file, userManagesMemory, needsDowncast, nesting): """ Generate code that creates a shadow object of this type then sets the this pointer and returns the object. We call the class destructor with None as the only parameter to get an empty shadow object. """ if classTypeDesc != self: indent(file, nesting, 'import ' + self.foreignTypeName + '\n') indent(file, nesting, 'returnObject = ') # Do not put Class.Class if this file is the file that defines Class # Also check for nested classes. They do not need the module name either typeName = FFIOverload.getTypeName(classTypeDesc, self) file.write(typeName) file.write('(None)\n') indent(file, nesting, 'returnObject.this = returnValue\n') # Zero this pointers get returned as the Python None object indent(file, nesting, 'if (returnObject.this == 0): return None\n') if userManagesMemory: indent(file, nesting, 'returnObject.userManagesMemory = 1\n') if needsDowncast: if (FFIOverload.inheritsFrom(self, TypedObjectDescriptor) or self == TypedObjectDescriptor): indent(file, nesting, 'return returnObject.setPointer()\n') else: indent(file, nesting, 'return returnObject\n') else: indent(file, nesting, 'return returnObject\n')
def cullOverloadedMethods(self): """ Find all the entries that have multiple indexes for the same method name Get rid of all others. Do this for class methods and instance methods """ self.overloadedClassMethods = FFIOverload.cullOverloadedMethods( self.overloadedClassMethods) self.overloadedInstanceMethods = FFIOverload.cullOverloadedMethods( self.overloadedInstanceMethods)
def outputTypeChecking(self, methodClass, args, file, nesting): """ Output an assert statement to check the type of each arg in this method This can be turned off with a command line parameter in generatePythonCode It is valid to pass in None for methodClass if you are not in any methodClass """ if FFIConstants.wantTypeChecking: for i in range(len(args)): methodArgSpec = args[i] typeDesc = methodArgSpec.typeDescriptor.recursiveTypeDescriptor() typeName = FFIOverload.getTypeName(methodClass, typeDesc) # We only do type checking on class types. C++ can do # type checking on the primitive types, and will do a # better job anyway. if typeDesc.__class__ == FFITypes.ClassTypeDescriptor: # Get the real return type (not derived) if ( (not typeDesc.isNested) and # Do not put our own module in the import list (methodClass != typeDesc) ): indent(file, nesting, "import " + typeDesc.foreignTypeName + "\n") indent(file, nesting, "if not isinstance(" + methodArgSpec.name + ", " + typeName + "):\n") indent( file, nesting + 1, 'raise TypeError, "Invalid argument %s, expected <%s>"\n' % (i, typeDesc.foreignTypeName), )
def outputTypeChecking(self, methodClass, args, file, nesting): """ Output an assert statement to check the type of each arg in this method This can be turned off with a command line parameter in generatePythonCode It is valid to pass in None for methodClass if you are not in any methodClass """ if FFIConstants.wantTypeChecking: for i in range(len(args)): methodArgSpec = args[i] typeDesc = methodArgSpec.typeDescriptor.recursiveTypeDescriptor( ) typeName = FFIOverload.getTypeName(methodClass, typeDesc) # We only do type checking on class types. C++ can do # type checking on the primitive types, and will do a # better job anyway. if typeDesc.__class__ == FFITypes.ClassTypeDescriptor: # Get the real return type (not derived) if ((not typeDesc.isNested) and # Do not put our own module in the import list (methodClass != typeDesc)): indent(file, nesting, 'import ' + typeDesc.foreignTypeName + '\n') indent( file, nesting, 'if not isinstance(' + methodArgSpec.name + ', ' + typeName + '):\n') indent( file, nesting + 1, 'raise TypeError, "Invalid argument %s, expected <%s>"\n' % (i, typeDesc.foreignTypeName))
def copyParentMethodsRecursively(self, parentList, file, nesting): """ Copy all the parents instance methods Do not copy functions if this class already has a function with that name We need to recurse up the hierarchy copying all our parents nodes all the way up the tree stopping either at the top, or at another MI node that has already copied his parent's methods in Note: Do not copy the downcast methods """ parent = parentList[-1] if (len(parent.parentTypes) > 0): recurse = 1 else: recurse = 0 for method in parent.instanceMethods: if not self.inheritsMethodNamed(parentList, method.name): # with downcast for all instance methods that are not themselves upcasts method.generateInheritedMethodCode(self, parentList, file, nesting, 1) # Also duplicate the overloaded method dispatch functions, if # we don't already have any matching methods by this name. for methodSpecList in parent.overloadedInstanceMethods.values(): if not self.inheritsMethodNamed(parentList, methodSpecList[0].name): treeColl = FFIOverload.FFIMethodArgumentTreeCollection( self, methodSpecList) treeColl.generateCode(file, nesting) # Copy all the parents upcast methods so we transitively pick them up for method in parent.upcastMethods: if not self.inheritsMethodNamed(parentList, method.name): # no downcast for all instance methods that are themselves upcasts # that would cause an infinite loop method.generateInheritedMethodCode(self, parentList, file, nesting, 0) # Now recurse up the hierarchy until we get to a node that is itself # a multiple inheritance node and stop there because he will have already # copied all his parent functions in if recurse: for parentType in parent.parentTypes: newParentList = parentList[:] newParentList.append(parentType) self.copyParentMethodsRecursively(newParentList, file, nesting)
def generateOverloadedMethods(self, file, nesting): """ Generate code for all the overloaded methods of this class """ if (len(self.overloadedClassMethods.values()) or len(self.overloadedInstanceMethods.values())): indent(file, nesting + 1, '\n') indent(file, nesting + 1, '##################################################\n') indent(file, nesting + 1, '# Overloaded methods #\n') indent(file, nesting + 1, '##################################################\n') indent(file, nesting + 1, '\n') # Overload all the class and instance methods for methodSpecList in (self.overloadedClassMethods.values() + self.overloadedInstanceMethods.values()): treeColl = FFIOverload.FFIMethodArgumentTreeCollection( self, methodSpecList) treeColl.generateCode(file, nesting)
def generateCodeLib(self, codeDir, extensionsDir, CModuleName): # Reset the environment so we are clean from any old modules self.environment.reset() FFIConstants.notify.info('=' * 50) FFIConstants.notify.warning('Importing code library: ' + CModuleName) exec('import ' + CModuleName) if interrogate_error_flag(): FFIConstants.notify.error( "Error reading interrogate database; can't continue.") self.updateBindings(CModuleName) FFIConstants.notify.info('Generating type code...') for type in self.environment.types.values(): # Do not generate code for nested types at the top level if (not type.isNested): type.generateGlobalCode(codeDir, extensionsDir) FFIConstants.notify.info('Generating global downcast code...') downcastFile = constructDowncastFile(codeDir, CModuleName) # Output all the imports based on this list of functions outputGlobalFileImports(downcastFile, self.environment.downcastFunctions, CModuleName) for type in self.environment.downcastFunctions: type.generateGlobalDowncastCode(downcastFile) FFIConstants.notify.info('Generating global code...') globalFile = constructGlobalFile(codeDir, CModuleName) # Make a list of all the global functions. This includes the normal # global functions as well as the getters and setters on all the # global values. This list is used to figure out what files to import # Only include the global functions from the current C module globalFunctions = self.environment.globalFunctions for globalValue in self.environment.globalValues: if globalValue.getter: globalFunctions.append(globalValue.getter) if globalValue.setter: globalFunctions.append(globalValue.setter) # Output all the imports based on this list of functions outputGlobalFileImports(globalFile, globalFunctions, CModuleName) # Generate overloading overloadedGlobalFunctions = {} for methodSpec in globalFunctions: methodList = overloadedGlobalFunctions.setdefault( methodSpec.name, []) methodList.append(methodSpec) overloadedGlobalFunctions = FFIOverload.cullOverloadedMethods( overloadedGlobalFunctions) for methodSpecList in overloadedGlobalFunctions.values(): treeColl = FFIOverload.FFIMethodArgumentTreeCollection( None, methodSpecList) treeColl.generateCode(globalFile, -1) FFIConstants.notify.info('Generating global values...') for type in self.environment.globalValues: type.generateGlobalCode(globalFile) FFIConstants.notify.info('Generating global functions...') for type in self.environment.globalFunctions: type.generateGlobalCode(globalFile) FFIConstants.notify.info('Generating manifests...') for type in self.environment.manifests: type.generateGlobalCode(globalFile) globalFile.close() FFIConstants.notify.info('Generating import code...') importFile = constructImportFile(codeDir, CModuleName) outputImportFileImports(importFile, self.environment.types.values(), CModuleName)
def generateCodeLib(self, codeDir, extensionsDir, CModuleName): # Reset the environment so we are clean from any old modules self.environment.reset() FFIConstants.notify.info('='*50) FFIConstants.notify.warning('Importing code library: ' + CModuleName) exec('import ' + CModuleName) if interrogate_error_flag(): FFIConstants.notify.error("Error reading interrogate database; can't continue.") self.updateBindings(CModuleName) FFIConstants.notify.info('Generating type code...') for type in self.environment.types.values(): # Do not generate code for nested types at the top level if (not type.isNested): type.generateGlobalCode(codeDir, extensionsDir) FFIConstants.notify.info('Generating global downcast code...') downcastFile = constructDowncastFile(codeDir, CModuleName) # Output all the imports based on this list of functions outputGlobalFileImports(downcastFile, self.environment.downcastFunctions, CModuleName) for type in self.environment.downcastFunctions: type.generateGlobalDowncastCode(downcastFile) FFIConstants.notify.info('Generating global code...') globalFile = constructGlobalFile(codeDir, CModuleName) # Make a list of all the global functions. This includes the normal # global functions as well as the getters and setters on all the # global values. This list is used to figure out what files to import # Only include the global functions from the current C module globalFunctions = self.environment.globalFunctions for globalValue in self.environment.globalValues: if globalValue.getter: globalFunctions.append(globalValue.getter) if globalValue.setter: globalFunctions.append(globalValue.setter) # Output all the imports based on this list of functions outputGlobalFileImports(globalFile, globalFunctions, CModuleName) # Generate overloading overloadedGlobalFunctions = {} for methodSpec in globalFunctions: methodList = overloadedGlobalFunctions.setdefault(methodSpec.name, []) methodList.append(methodSpec) overloadedGlobalFunctions = FFIOverload.cullOverloadedMethods(overloadedGlobalFunctions) for methodSpecList in overloadedGlobalFunctions.values(): treeColl = FFIOverload.FFIMethodArgumentTreeCollection(None, methodSpecList) treeColl.generateCode(globalFile, -1) FFIConstants.notify.info('Generating global values...') for type in self.environment.globalValues: type.generateGlobalCode(globalFile) FFIConstants.notify.info('Generating global functions...') for type in self.environment.globalFunctions: type.generateGlobalCode(globalFile) FFIConstants.notify.info('Generating manifests...') for type in self.environment.manifests: type.generateGlobalCode(globalFile) globalFile.close() FFIConstants.notify.info('Generating import code...') importFile = constructImportFile(codeDir, CModuleName) outputImportFileImports(importFile, self.environment.types.values(), CModuleName)