mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-24 12:12:36 -06:00
870 lines
38 KiB
Python
870 lines
38 KiB
Python
|
|
# Note: do not import this file directly, it is meant to be used as part of
|
|
# a Python script (generatePythonCode) that sets up variables that this
|
|
# module depends on
|
|
|
|
import string
|
|
import os
|
|
import glob
|
|
|
|
import FFIEnvironment
|
|
import FFITypes
|
|
import FFISpecs
|
|
import FFIRename
|
|
import FFIConstants
|
|
import FFIOverload
|
|
from direct.showbase.PythonUtil import *
|
|
|
|
FFIConstants.notify.info('Importing interrogate library: ' + FFIConstants.InterrogateModuleName)
|
|
|
|
# Note: we do a from lib import * here because we do not want
|
|
# to be dependent on the name of the interrogate library in this code
|
|
exec('from ' + FFIConstants.InterrogateModuleName + ' import *')
|
|
|
|
|
|
def constructGlobalFile(codeDir, CModuleName):
|
|
"""
|
|
Open a file that will hold the global values and functions code
|
|
"""
|
|
file = open(os.path.join(codeDir, CModuleName + 'Globals' + '.py'), 'w')
|
|
return file
|
|
|
|
|
|
def constructDowncastFile(codeDir, CModuleName):
|
|
"""
|
|
Open a file that will hold the global values and functions code
|
|
"""
|
|
file = open(os.path.join(codeDir, CModuleName + 'Downcasts' + '.py'), 'w')
|
|
return file
|
|
|
|
|
|
def constructImportFile(codeDir, CModuleName):
|
|
"""
|
|
Open a file that will hold the global values and functions code
|
|
"""
|
|
file = open(os.path.join(codeDir, CModuleName + 'Modules' + '.py'), 'w')
|
|
return file
|
|
|
|
def outputGlobalFileImports(file, methodList, CModuleName):
|
|
# Print the standard header
|
|
file.write(FFIConstants.generatedHeader)
|
|
file.write('# CMODULE [' + CModuleName + ']\n')
|
|
|
|
# Import Python's builtin types
|
|
file.write('from types import IntType, LongType, FloatType, NoneType, StringType\n')
|
|
file.write('from direct.ffi import FFIExternalObject\n')
|
|
|
|
|
|
# Import the C modules
|
|
CModuleList = []
|
|
for method in methodList:
|
|
if (not (method.typeDescriptor.moduleName in CModuleList)):
|
|
CModuleList.append(method.typeDescriptor.moduleName)
|
|
for CModuleName in CModuleList:
|
|
if CModuleName:
|
|
file.write('import ' + CModuleName + '\n')
|
|
|
|
moduleList = []
|
|
for method in methodList:
|
|
returnType = method.typeDescriptor.returnType.recursiveTypeDescriptor()
|
|
returnTypeName = returnType.foreignTypeName
|
|
if (not (returnTypeName in moduleList)):
|
|
if (returnType.__class__ == FFITypes.ClassTypeDescriptor):
|
|
moduleList.append(returnTypeName)
|
|
|
|
# Look at all the arguments
|
|
argTypes = method.typeDescriptor.argumentTypes
|
|
for argType in argTypes:
|
|
# Get the real return type (not derived)
|
|
argType = argType.typeDescriptor.recursiveTypeDescriptor()
|
|
if (not argType.isNested):
|
|
argTypeName = argType.foreignTypeName
|
|
# Do not put our own module in the import list
|
|
# Do not put modules already in the list (like a set)
|
|
if (not (argTypeName in moduleList)):
|
|
# If this is a class (not a primitive), put it on the list
|
|
if (argType.__class__ == FFITypes.ClassTypeDescriptor):
|
|
moduleList.append(argTypeName)
|
|
|
|
|
|
for moduleName in moduleList:
|
|
if moduleName:
|
|
file.write('import ' + moduleName + '\n')
|
|
file.write('import ' + moduleName + '1\n')
|
|
|
|
file.write('\n')
|
|
|
|
|
|
def outputImportFileImports(file, typeList, CModuleName):
|
|
"""
|
|
This is the file that we will import to get all the panda modules
|
|
"""
|
|
|
|
# Print the standard header
|
|
file.write(FFIConstants.generatedHeader)
|
|
file.write('# CMODULE [' + CModuleName + ']\n')
|
|
file.write('# Import the interrogate module\n')
|
|
file.write('import ' + FFIConstants.InterrogateModuleName + '\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Import the C module\n')
|
|
file.write('import ' + CModuleName + '\n')
|
|
|
|
# Filter out only the class and enum type descriptors (not const, pointers, etc)
|
|
classTypeList = []
|
|
enumTypeList = []
|
|
for type in typeList:
|
|
if (type.__class__ == FFITypes.ClassTypeDescriptor):
|
|
if (not type.isNested):
|
|
classTypeList.append(type)
|
|
elif (type.__class__ == FFITypes.EnumTypeDescriptor):
|
|
if (not type.isNested):
|
|
enumTypeList.append(type)
|
|
|
|
# Sort the types based on inheritance, most generic first
|
|
classTypeList.sort(FFIOverload.inheritanceLevelSort)
|
|
|
|
moduleList = []
|
|
for type in classTypeList:
|
|
moduleList.append(type.foreignTypeName)
|
|
|
|
file.write('# Import enums into the global name space\n')
|
|
for type in enumTypeList:
|
|
file.write('from ' + type.enumName + ' import *\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Import downcast functions\n')
|
|
file.write('from ' + CModuleName + 'Downcasts import *\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Import classes\n')
|
|
for moduleName in moduleList:
|
|
if moduleName:
|
|
file.write('import ' + moduleName + '\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Import classes2\n')
|
|
for moduleName in moduleList:
|
|
if moduleName:
|
|
file.write('import ' + moduleName + '1\n')
|
|
file.write('\n')
|
|
|
|
|
|
file.write('# Import the global module file into our name space\n')
|
|
file.write('from ' + CModuleName + 'Globals import *\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Generate the classes\n')
|
|
#for moduleName in moduleList:
|
|
# file.write(moduleName + '.generateClass_' + moduleName + '()\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Copy the classes into our own namespace\n')
|
|
for moduleName in moduleList:
|
|
file.write(moduleName + ' = ' + moduleName + '.' + moduleName + '\n')
|
|
file.write('\n')
|
|
|
|
file.write('# Put the classes in the wrapper class map\n')
|
|
file.write('from direct.ffi.FFIExternalObject import registerInTypeMap\n')
|
|
file.write('\n')
|
|
for moduleName in moduleList:
|
|
file.write('registerInTypeMap(' + moduleName + ')\n')
|
|
file.write('\n')
|
|
|
|
|
|
|
|
def getTypeName(typeIndex, scoped=0):
|
|
"""
|
|
Return a fully specified type name for this type index
|
|
Return the scoped name if asked for it
|
|
"""
|
|
nameComponents = []
|
|
name = ''
|
|
|
|
|
|
if scoped:
|
|
typeName = interrogate_type_scoped_name(typeIndex)
|
|
else:
|
|
typeName = interrogate_type_name(typeIndex)
|
|
|
|
if typeIndex == 0:
|
|
FFIConstants.notify.debug('typeIndex 0: ' + typeName)
|
|
|
|
if interrogate_type_is_wrapped(typeIndex):
|
|
typeName = getTypeName(interrogate_type_wrapped_type(typeIndex))
|
|
if interrogate_type_is_const(typeIndex):
|
|
nameComponents.append('const')
|
|
if interrogate_type_is_pointer(typeIndex):
|
|
nameComponents.append('ptr')
|
|
if interrogate_type_is_signed(typeIndex):
|
|
# signed is now built into the type name
|
|
#nameComponents.append('signed')
|
|
pass
|
|
if interrogate_type_is_unsigned(typeIndex):
|
|
# unsigned is now built into the type name
|
|
#nameComponents.append('unsigned')
|
|
pass
|
|
if interrogate_type_is_long(typeIndex):
|
|
nameComponents.append('long')
|
|
if interrogate_type_is_longlong(typeIndex):
|
|
nameComponents.append('longLong')
|
|
if interrogate_type_is_short(typeIndex):
|
|
nameComponents.append('short')
|
|
if (len(nameComponents) > 0):
|
|
typeName = string.capitalize(typeName[0]) + typeName[1:]
|
|
nameComponents.append(typeName)
|
|
for i in range(len(nameComponents)):
|
|
if (i == 0):
|
|
name = name + nameComponents[i]
|
|
else:
|
|
name = name + string.capitalize(nameComponents[i][0]) + nameComponents[i][1:]
|
|
|
|
FFIConstants.notify.debug('typeIndex: ' + repr(typeIndex) + ' typeName: ' + typeName + ' has name: ' + name)
|
|
|
|
if not name:
|
|
FFIConstants.notify.warning('typeIndex: ' + repr(typeIndex) + ' typeName: ' + typeName + ' has no name')
|
|
name = "UnnamedType"
|
|
|
|
return name
|
|
|
|
|
|
class FFIInterrogateDatabase:
|
|
|
|
def __init__(self, etcPath = []):
|
|
for dir in etcPath:
|
|
interrogate_add_search_directory(dir)
|
|
|
|
self.typeIndexMap = {}
|
|
self.environment = FFIEnvironment.FFIEnvironment()
|
|
|
|
def isDefinedType(self, typeIndex):
|
|
return typeIndex in self.typeIndexMap
|
|
|
|
def constructDescriptor(self, typeIndex):
|
|
if interrogate_type_is_atomic(typeIndex):
|
|
return self.constructPrimitiveTypeDescriptor(typeIndex)
|
|
|
|
elif interrogate_type_is_enum(typeIndex):
|
|
return self.constructEnumTypeDescriptor(typeIndex)
|
|
|
|
elif interrogate_type_is_wrapped(typeIndex):
|
|
if interrogate_type_is_pointer(typeIndex):
|
|
return self.constructPointerTypeDescriptor(typeIndex)
|
|
elif interrogate_type_is_const(typeIndex):
|
|
return self.constructConstTypeDescriptor(typeIndex)
|
|
|
|
elif (interrogate_type_is_class(typeIndex) or
|
|
interrogate_type_is_struct(typeIndex) or
|
|
interrogate_type_is_union(typeIndex)):
|
|
return self.constructClassTypeDescriptor(typeIndex)
|
|
|
|
elif (not interrogate_type_is_fully_defined(typeIndex)):
|
|
return self.constructClassTypeDescriptor(typeIndex)
|
|
|
|
else:
|
|
raise 'A type in the interrogate database was not recognized: '+ repr(typeIndex)
|
|
|
|
def constructPrimitiveTypeDescriptor(self, typeIndex):
|
|
if self.isDefinedType(typeIndex):
|
|
return self.typeIndexMap[typeIndex]
|
|
else:
|
|
descriptor = FFITypes.PrimitiveTypeDescriptor()
|
|
#descriptor.environment = self.environment
|
|
descriptor.atomicType = interrogate_type_atomic_token(typeIndex)
|
|
if interrogate_type_has_module_name(typeIndex):
|
|
descriptor.moduleName = 'lib' + interrogate_type_module_name(typeIndex)
|
|
descriptor.foreignTypeName = \
|
|
FFIRename.nonClassNameFromCppName(getTypeName(typeIndex))
|
|
descriptor.typeIndex = typeIndex
|
|
self.typeIndexMap[typeIndex] = descriptor
|
|
return descriptor
|
|
|
|
def constructEnumTypeDescriptor(self, typeIndex):
|
|
if self.isDefinedType(typeIndex):
|
|
return self.typeIndexMap[typeIndex]
|
|
else:
|
|
descriptor = FFITypes.EnumTypeDescriptor()
|
|
#descriptor.environment = self.environment
|
|
descriptor.isNested = interrogate_type_is_nested(typeIndex)
|
|
if descriptor.isNested:
|
|
outerTypeIndex = interrogate_type_outer_class(typeIndex)
|
|
descriptor.outerType = self.constructDescriptor(outerTypeIndex)
|
|
if interrogate_type_has_module_name(typeIndex):
|
|
descriptor.moduleName = 'lib' + interrogate_type_module_name(typeIndex)
|
|
|
|
# Enums are ints in C++ but we do not want to redefine the int type
|
|
# So we will just call them enums
|
|
descriptor.enumName = FFIRename.classNameFromCppName(getTypeName(typeIndex))
|
|
descriptor.foreignTypeName = '__enum__' + descriptor.enumName
|
|
numValues = interrogate_type_number_of_enum_values(typeIndex)
|
|
|
|
# Store the names and values of the enum in a dictionary
|
|
for i in range(numValues):
|
|
value = interrogate_type_enum_value(typeIndex, i)
|
|
name = FFIRename.classNameFromCppName(
|
|
interrogate_type_enum_value_name(typeIndex, i))
|
|
scopedName = FFIRename.classNameFromCppName(
|
|
interrogate_type_enum_value_scoped_name(typeIndex, i))
|
|
descriptor.values[name] = value
|
|
|
|
descriptor.typeIndex = typeIndex
|
|
self.typeIndexMap[typeIndex] = descriptor
|
|
return descriptor
|
|
|
|
def constructPointerTypeDescriptor(self, typeIndex):
|
|
if self.isDefinedType(typeIndex):
|
|
return self.typeIndexMap[typeIndex]
|
|
descriptor = FFITypes.PointerTypeDescriptor()
|
|
#descriptor.environment = self.environment
|
|
descriptor.isNested = interrogate_type_is_nested(typeIndex)
|
|
if descriptor.isNested:
|
|
outerTypeIndex = interrogate_type_outer_class(typeIndex)
|
|
descriptor.outerType = self.constructDescriptor(outerTypeIndex)
|
|
if interrogate_type_has_module_name(typeIndex):
|
|
descriptor.moduleName = 'lib' + interrogate_type_module_name(typeIndex)
|
|
descriptor.foreignTypeName = \
|
|
FFIRename.nonClassNameFromCppName(getTypeName(typeIndex))
|
|
descriptor.typeIndex = typeIndex
|
|
wrappedTypeIndex = interrogate_type_wrapped_type(typeIndex)
|
|
wrappedTypeDescriptor = self.constructDescriptor(wrappedTypeIndex)
|
|
descriptor.typeDescriptor = wrappedTypeDescriptor
|
|
self.typeIndexMap[typeIndex] = descriptor
|
|
return descriptor
|
|
|
|
def constructConstTypeDescriptor(self, typeIndex):
|
|
if self.isDefinedType(typeIndex):
|
|
return self.typeIndexMap[typeIndex]
|
|
descriptor = FFITypes.ConstTypeDescriptor()
|
|
#descriptor.environment = self.environment
|
|
descriptor.isNested = interrogate_type_is_nested(typeIndex)
|
|
if descriptor.isNested:
|
|
outerTypeIndex = interrogate_type_outer_class(typeIndex)
|
|
descriptor.outerType = self.constructDescriptor(outerTypeIndex)
|
|
if interrogate_type_has_module_name(typeIndex):
|
|
descriptor.moduleName = 'lib' + interrogate_type_module_name(typeIndex)
|
|
descriptor.foreignTypeName = \
|
|
FFIRename.nonClassNameFromCppName(getTypeName(typeIndex))
|
|
descriptor.typeIndex = typeIndex
|
|
wrappedTypeIndex = interrogate_type_wrapped_type(typeIndex)
|
|
wrappedTypeDescriptor = self.constructDescriptor(wrappedTypeIndex)
|
|
descriptor.typeDescriptor = wrappedTypeDescriptor
|
|
self.typeIndexMap[typeIndex] = descriptor
|
|
return descriptor
|
|
|
|
def constructParentTypeDescriptors(self, typeIndex):
|
|
numParents = interrogate_type_number_of_derivations(typeIndex)
|
|
descriptors = []
|
|
for i in range(numParents):
|
|
parentTypeIndex = interrogate_type_get_derivation(typeIndex, i)
|
|
if self.isDefinedType(parentTypeIndex):
|
|
parentTypeDescriptor = self.typeIndexMap[parentTypeIndex]
|
|
else:
|
|
parentTypeDescriptor = self.constructDescriptor(parentTypeIndex)
|
|
descriptors.append(parentTypeDescriptor)
|
|
return descriptors
|
|
|
|
def constructNestedTypeDescriptors(self, typeIndex):
|
|
nestedTypes = []
|
|
numNestedTypes = interrogate_type_number_of_nested_types(typeIndex)
|
|
for i in range(numNestedTypes):
|
|
nestedTypeIndex = interrogate_type_get_nested_type(typeIndex, i)
|
|
descriptor = self.constructDescriptor(nestedTypeIndex)
|
|
nestedTypes.append(descriptor)
|
|
return nestedTypes
|
|
|
|
def constructClassTypeDescriptor(self, typeIndex):
|
|
if self.isDefinedType(typeIndex):
|
|
return self.typeIndexMap[typeIndex]
|
|
typeName = FFIRename.classNameFromCppName(getTypeName(typeIndex))
|
|
if typeName == "PyObject":
|
|
# A special case: the PyObject type is really a native
|
|
# Python object, not to be molested--it's not really an
|
|
# FFI class object.
|
|
descriptor = FFITypes.PyObjectTypeDescriptor()
|
|
self.typeIndexMap[typeIndex] = descriptor
|
|
return descriptor
|
|
|
|
descriptor = FFITypes.ClassTypeDescriptor()
|
|
self.typeIndexMap[typeIndex] = descriptor
|
|
#descriptor.environment = self.environment
|
|
descriptor.foreignTypeName = typeName
|
|
|
|
if (typeName == "TypedObject"):
|
|
FFITypes.TypedObjectDescriptor = descriptor
|
|
|
|
descriptor.isNested = interrogate_type_is_nested(typeIndex)
|
|
if descriptor.isNested:
|
|
outerTypeIndex = interrogate_type_outer_class(typeIndex)
|
|
descriptor.outerType = self.constructDescriptor(outerTypeIndex)
|
|
if interrogate_type_has_module_name(typeIndex):
|
|
descriptor.moduleName = 'lib' + interrogate_type_module_name(typeIndex)
|
|
if FFIConstants.wantComments:
|
|
if interrogate_type_has_comment(typeIndex):
|
|
descriptor.comment = interrogate_type_comment(typeIndex)
|
|
descriptor.typeIndex = typeIndex
|
|
descriptor.instanceMethods = self.constructMemberFunctionSpecifications(typeIndex)
|
|
descriptor.upcastMethods = self.constructUpcastFunctionSpecifications(typeIndex)
|
|
# Constructing downcasts does not return the functions, it just puts them in the class
|
|
# See the comment in that function
|
|
self.constructDowncastFunctionSpecifications(typeIndex)
|
|
descriptor.filterOutStaticMethods()
|
|
descriptor.constructors = self.constructConstructorSpecifications(typeIndex)
|
|
descriptor.destructor = self.constructDestructorSpecification(typeIndex)
|
|
descriptor.parentTypes = self.constructParentTypeDescriptors(typeIndex)
|
|
descriptor.nestedTypes = self.constructNestedTypeDescriptors(typeIndex)
|
|
return descriptor
|
|
|
|
def constructFunctionTypeDescriptors(self, functionIndex):
|
|
|
|
# Store these values because they will be the same for all the wrappers
|
|
isVirtual = interrogate_function_is_virtual(functionIndex)
|
|
#environment = self.environment
|
|
foreignTypeName = interrogate_function_name(functionIndex)
|
|
if FFIConstants.wantComments:
|
|
prototype = interrogate_function_prototype(functionIndex)
|
|
if interrogate_function_has_comment(functionIndex):
|
|
comment = interrogate_function_comment(functionIndex)
|
|
else:
|
|
comment = ''
|
|
# Prepend lib to the module name it reports because that will be the name of
|
|
# the Python module we import. This is apparently stems from a makefile
|
|
# discrepency in the way we build the libraries
|
|
if interrogate_function_has_module_name(functionIndex):
|
|
moduleName = 'lib' + interrogate_function_module_name(functionIndex)
|
|
else:
|
|
moduleName = None
|
|
typeIndex = functionIndex
|
|
|
|
# Look at the Python wrappers for this function
|
|
numPythonWrappers = interrogate_function_number_of_python_wrappers(functionIndex)
|
|
|
|
if numPythonWrappers == 0:
|
|
# If there are no Python wrappers, it is because interrogate could not handle
|
|
# something about the function. Just return an empty list
|
|
return []
|
|
|
|
wrapperDescriptors = []
|
|
|
|
# Iterate over the wrappers constructing a FunctionTypeDescriptor for each
|
|
for i in range(numPythonWrappers):
|
|
descriptor = FFITypes.FunctionTypeDescriptor()
|
|
descriptor.isVirtual = isVirtual
|
|
#descriptor.environment = environment
|
|
descriptor.foreignTypeName = foreignTypeName
|
|
if FFIConstants.wantComments:
|
|
descriptor.comment = comment
|
|
descriptor.prototype = prototype
|
|
descriptor.moduleName = moduleName
|
|
descriptor.typeIndex = typeIndex
|
|
pythonFunctionIndex = interrogate_function_python_wrapper(functionIndex, i)
|
|
descriptor.wrapperName = interrogate_wrapper_name(pythonFunctionIndex)
|
|
# Even if it does not have a return value, it reports void which is better
|
|
# for generating code, so I will not even ask here
|
|
# if interrogate_wrapper_has_return_value(pythonFunctionIndex):
|
|
returnType = interrogate_wrapper_return_type(pythonFunctionIndex)
|
|
descriptor.returnType = self.constructDescriptor(returnType)
|
|
descriptor.argumentTypes = self.constructFunctionArgumentTypes(pythonFunctionIndex)
|
|
descriptor.userManagesMemory = interrogate_wrapper_caller_manages_return_value(pythonFunctionIndex)
|
|
descriptor.returnValueDestructor = interrogate_wrapper_return_value_destructor(pythonFunctionIndex)
|
|
wrapperDescriptors.append(descriptor)
|
|
|
|
return wrapperDescriptors
|
|
|
|
def constructFunctionArgumentTypes(self, functionIndex):
|
|
numArgs = interrogate_wrapper_number_of_parameters(functionIndex)
|
|
arguments = []
|
|
for argIndex in range(numArgs):
|
|
if interrogate_wrapper_parameter_has_name(functionIndex, argIndex):
|
|
name = FFIRename.nonClassNameFromCppName(
|
|
interrogate_wrapper_parameter_name(functionIndex, argIndex))
|
|
else:
|
|
name = ('parameter' + repr(argIndex))
|
|
descriptor = self.constructDescriptor(
|
|
interrogate_wrapper_parameter_type(functionIndex, argIndex))
|
|
|
|
argSpec = FFISpecs.MethodArgumentSpecification()
|
|
if interrogate_wrapper_parameter_is_this(functionIndex, argIndex):
|
|
argSpec.isThis = 1
|
|
argSpec.name = name
|
|
argSpec.typeDescriptor = descriptor
|
|
arguments.append(argSpec)
|
|
return arguments
|
|
|
|
def constructMemberFunctionSpecifications(self, typeIndex):
|
|
funcSpecs = []
|
|
numFuncs = interrogate_type_number_of_methods(typeIndex)
|
|
for i in range(numFuncs):
|
|
funcIndex = interrogate_type_get_method(typeIndex, i)
|
|
typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
|
|
for typeDesc in typeDescs:
|
|
funcSpec = FFISpecs.MethodSpecification()
|
|
funcSpec.name = FFIRename.methodNameFromCppName(
|
|
interrogate_function_name(funcIndex),
|
|
getTypeName(typeIndex))
|
|
funcSpec.typeDescriptor = typeDesc
|
|
funcSpec.index = funcIndex
|
|
funcSpecs.append(funcSpec)
|
|
return funcSpecs
|
|
|
|
def constructUpcastFunctionSpecifications(self, typeIndex):
|
|
funcSpecs = []
|
|
numFuncs = interrogate_type_number_of_derivations(typeIndex)
|
|
for i in range(numFuncs):
|
|
if interrogate_type_derivation_has_upcast(typeIndex, i):
|
|
funcIndex = interrogate_type_get_upcast(typeIndex, i)
|
|
typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
|
|
for typeDesc in typeDescs:
|
|
funcSpec = FFISpecs.MethodSpecification()
|
|
# We synthesize the upcast function name instead
|
|
# of using the name supplied by interrogate, to
|
|
# allow for possible renaming of types on this
|
|
# side.
|
|
funcSpec.name = 'upcastTo' + typeDesc.returnType.typeDescriptor.foreignTypeName
|
|
#funcSpec.name = FFIRename.methodNameFromCppName(
|
|
# interrogate_function_name(funcIndex))
|
|
funcSpec.typeDescriptor = typeDesc
|
|
funcSpec.index = funcIndex
|
|
funcSpecs.append(funcSpec)
|
|
return funcSpecs
|
|
|
|
def constructDowncastFunctionSpecifications(self, typeIndex):
|
|
"""
|
|
The strange thing about downcast functions is that they appear in the
|
|
class they are being downcast TO, not downcast FROM. But they should be
|
|
built into the class they are being downcast from. For instance, a method
|
|
downcastToNode(ptrBoundedObject) will appear in Node's list of methods
|
|
but should be compiled into BoundedObject's class
|
|
UPDATE: These are no longer compiled into the from-class. That was
|
|
preventing the libraries from being independent since the from class
|
|
now had knowledge of the to class which is potentially in a library
|
|
downstream. Now these functions are just global functions
|
|
"""
|
|
numFuncs = interrogate_type_number_of_derivations(typeIndex)
|
|
for i in range(numFuncs):
|
|
# Make sure this downcast is possible
|
|
if (not interrogate_type_derivation_downcast_is_impossible(typeIndex, i)):
|
|
if interrogate_type_derivation_has_downcast(typeIndex, i):
|
|
funcIndex = interrogate_type_get_downcast(typeIndex, i)
|
|
typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
|
|
for typeDesc in typeDescs:
|
|
funcSpec = FFISpecs.GlobalFunctionSpecification()
|
|
funcSpec.name = FFIRename.methodNameFromCppName(
|
|
interrogate_function_name(funcIndex),
|
|
getTypeName(typeIndex))
|
|
funcSpec.typeDescriptor = typeDesc
|
|
funcSpec.index = funcIndex
|
|
# Here we look for the class in the first argument
|
|
fromClass = typeDesc.argumentTypes[0].typeDescriptor.recursiveTypeDescriptor()
|
|
|
|
# Append the from class name on the method to uniquify it now
|
|
# that these are global methods
|
|
funcSpec.name = funcSpec.name + 'From' + fromClass.foreignTypeName
|
|
|
|
# Append this funcSpec to that class's downcast methods
|
|
# fromClass.downcastMethods.append(funcSpec)
|
|
self.environment.addDowncastFunction(funcSpec)
|
|
|
|
def constructConstructorSpecifications(self, typeIndex):
|
|
funcSpecs = []
|
|
numFuncs = interrogate_type_number_of_constructors(typeIndex)
|
|
for i in range(numFuncs):
|
|
funcIndex = interrogate_type_get_constructor(typeIndex, i)
|
|
typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
|
|
for typeDesc in typeDescs:
|
|
funcSpec = FFISpecs.MethodSpecification()
|
|
funcSpec.name = 'constructor'
|
|
# funcSpec.name = FFIRename.methodNameFromCppName(
|
|
# interrogate_function_name(funcIndex))
|
|
funcSpec.typeDescriptor = typeDesc
|
|
# Flag this function as being a constructor
|
|
funcSpec.constructor = 1
|
|
funcSpec.index = funcIndex
|
|
funcSpecs.append(funcSpec)
|
|
return funcSpecs
|
|
|
|
def constructDestructorSpecification(self, typeIndex):
|
|
if (not interrogate_type_has_destructor(typeIndex)):
|
|
return None
|
|
funcIndex = interrogate_type_get_destructor(typeIndex)
|
|
typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
|
|
if (len(typeDescs) == 0):
|
|
return None
|
|
for typeDesc in typeDescs:
|
|
funcSpec = FFISpecs.MethodSpecification()
|
|
funcSpec.name = 'destructor'
|
|
# funcSpec.name = FFIRename.methodNameFromCppName(
|
|
# interrogate_function_name(funcIndex))
|
|
funcSpec.typeDescriptor = typeDesc
|
|
funcSpec.index = funcIndex
|
|
return funcSpec
|
|
|
|
def addTypes(self, CModuleName):
|
|
for i in range(interrogate_number_of_global_types()):
|
|
typeIndex = interrogate_get_global_type(i)
|
|
if self.typeInCModule(typeIndex, CModuleName):
|
|
self.constructDescriptor(typeIndex)
|
|
|
|
def addEnvironmentTypes(self):
|
|
for descriptor in self.typeIndexMap.values():
|
|
self.environment.addType(descriptor, descriptor.foreignTypeName)
|
|
|
|
def functionInCModule(self, funcIndex, CModuleName):
|
|
if interrogate_function_has_module_name(funcIndex):
|
|
moduleName = 'lib' + interrogate_function_module_name(funcIndex)
|
|
return (moduleName == CModuleName)
|
|
|
|
def typeInCModule(self, typeIndex, CModuleName):
|
|
if interrogate_type_has_module_name(typeIndex):
|
|
moduleName = 'lib' + interrogate_type_module_name(typeIndex)
|
|
return (moduleName == CModuleName)
|
|
|
|
|
|
def constructGlobal(self, globalIndex, CModuleName):
|
|
# We really do not need the descriptor for the value, just
|
|
# the getter and setter
|
|
# typeIndex = interrogate_element_type(globalIndex)
|
|
# descriptor = self.constructDescriptor(typeIndex)
|
|
|
|
if interrogate_element_has_getter(globalIndex):
|
|
getterIndex = interrogate_element_getter(globalIndex)
|
|
# If this function is not in this Cmodule just return
|
|
if not self.functionInCModule(getterIndex, CModuleName):
|
|
return None
|
|
getter = self.constructGlobalFunction(getterIndex)
|
|
else:
|
|
getter = None
|
|
|
|
if interrogate_element_has_setter(globalIndex):
|
|
setterIndex = interrogate_element_setter(globalIndex)
|
|
# If this function is not in this Cmodule just return
|
|
if not self.functionInCModule(setterIndex, CModuleName):
|
|
return None
|
|
setter = self.constructGlobalFunction(setterIndex)
|
|
else:
|
|
setter = None
|
|
globalSpec = FFISpecs.GlobalValueSpecification()
|
|
globalSpec.getter = getter
|
|
globalSpec.setter = setter
|
|
# globalSpec.typeDescriptor = descriptor
|
|
cppName = interrogate_element_name(globalIndex)
|
|
globalSpec.name = FFIRename.classNameFromCppName(cppName)
|
|
return globalSpec
|
|
|
|
def constructGlobalFunction(self, globalIndex):
|
|
descriptors = self.constructFunctionTypeDescriptors(globalIndex)
|
|
if (len(descriptors) == 0):
|
|
return None
|
|
funcSpecs = []
|
|
for descriptor in descriptors:
|
|
funcSpec = FFISpecs.GlobalFunctionSpecification()
|
|
funcSpec.typeDescriptor = descriptor
|
|
funcSpec.name = FFIRename.methodNameFromCppName(
|
|
funcSpec.typeDescriptor.foreignTypeName)
|
|
funcSpec.index = globalIndex
|
|
funcSpecs.append(funcSpec)
|
|
return funcSpecs
|
|
|
|
def addGlobalFunctions(self, CModuleName):
|
|
numGlobals = interrogate_number_of_global_functions()
|
|
for i in range(numGlobals):
|
|
funcIndex = interrogate_get_global_function(i)
|
|
if self.functionInCModule(funcIndex, CModuleName):
|
|
newGlob = self.constructGlobalFunction(funcIndex)
|
|
if newGlob:
|
|
self.environment.addGlobalFunction(newGlob)
|
|
|
|
def addGlobalValues(self, CModuleName):
|
|
numGlobals = interrogate_number_of_globals()
|
|
for i in range(numGlobals):
|
|
globalIndex = interrogate_get_global(i)
|
|
newGlob = self.constructGlobal(globalIndex, CModuleName)
|
|
if newGlob:
|
|
self.environment.addGlobalValue(newGlob)
|
|
|
|
def constructManifest(self, manifestIndex):
|
|
descriptor = None
|
|
intValue = None
|
|
getter = None
|
|
|
|
if interrogate_manifest_has_type(manifestIndex):
|
|
typeIndex = interrogate_manifest_get_type(manifestIndex)
|
|
descriptor = self.constructDescriptor(typeIndex)
|
|
|
|
definition = interrogate_manifest_definition(manifestIndex)
|
|
|
|
# See if this manifest is an int. There are shortcuts if it is.
|
|
# If it does have an int value, there will be no getter, we will
|
|
# just output the value in the generated code
|
|
if interrogate_manifest_has_int_value(manifestIndex):
|
|
intValue = interrogate_manifest_get_int_value(manifestIndex)
|
|
else:
|
|
# See if this manifest has a getter
|
|
if interrogate_manifest_has_getter(manifestIndex):
|
|
getterIndex = interrogate_manifest_getter(manifestIndex)
|
|
getter = self.constructGlobalFunction(getterIndex)
|
|
|
|
manifestSpec = FFISpecs.ManifestSpecification()
|
|
manifestSpec.typeDescriptor = descriptor
|
|
manifestSpec.definition = definition
|
|
manifestSpec.intValue = intValue
|
|
manifestSpec.getter = getter
|
|
cppName = interrogate_manifest_name(manifestIndex)
|
|
manifestSpec.name = FFIRename.classNameFromCppName(cppName)
|
|
return manifestSpec
|
|
|
|
def addManifestSymbols(self):
|
|
numManifests = interrogate_number_of_manifests()
|
|
for i in range(numManifests):
|
|
manifestIndex = interrogate_get_manifest(i)
|
|
newManifest = self.constructManifest(manifestIndex)
|
|
self.environment.addManifest(newManifest)
|
|
|
|
|
|
def generateCode(self, codeDir, extensionsDir):
|
|
# Empty out the codeDir of unnecessary crud from previous runs
|
|
# before we begin.
|
|
for file in os.listdir(codeDir):
|
|
pathname = os.path.join(codeDir, file)
|
|
if not os.path.isdir(pathname):
|
|
os.unlink(pathname)
|
|
|
|
# Import all the C++ modules
|
|
for CModuleName in FFIConstants.CodeModuleNameList:
|
|
self.generateCodeLib(codeDir, extensionsDir, CModuleName)
|
|
|
|
# For convenience, output a file that imports all the c module files
|
|
file = open(os.path.join(codeDir, FFIConstants.importModuleName + '.py'), 'w')
|
|
for CModuleName in FFIConstants.CodeModuleNameList:
|
|
file.write('from ' + CModuleName + 'Modules import *\n')
|
|
file.close()
|
|
|
|
# Generate an empty __init__.py to make the directory a Python
|
|
# package.
|
|
init = os.path.join(codeDir, '__init__.py')
|
|
file = open(init, 'w')
|
|
file.close()
|
|
|
|
def squeezeGeneratedCode(self, outputDir, deleteSource=True):
|
|
|
|
# Since we will be squeezing the importModuleName file, rename
|
|
# the original to something we can import from within the
|
|
# squeezed version.
|
|
squeezedName = FFIConstants.importModuleName
|
|
unsqueezedName = FFIConstants.importModuleName + 'Unsqueezed'
|
|
|
|
os.rename(os.path.join(outputDir, squeezedName + '.py'),
|
|
os.path.join(outputDir, unsqueezedName + '.py'))
|
|
|
|
# Get the list of files to squeeze. This is all of the .py
|
|
# files in the output directory except for the __init__.py
|
|
# file.
|
|
|
|
files = glob.glob(os.path.join(outputDir, '*.py'))
|
|
init = os.path.join(outputDir, '__init__.py')
|
|
try:
|
|
files.remove(init)
|
|
except:
|
|
pass
|
|
|
|
print "Squeezing %s files." % (len(files))
|
|
|
|
from direct.showbase import pandaSqueezeTool
|
|
|
|
pandaSqueezeTool.squeeze(squeezedName, unsqueezedName,
|
|
files, outputDir)
|
|
|
|
if deleteSource:
|
|
# Remove the now-squeezed source files.
|
|
for file in files:
|
|
os.remove(file)
|
|
|
|
|
|
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 updateBindings(self, CModuleName):
|
|
FFIConstants.notify.info('Updating Bindings')
|
|
FFIConstants.notify.info('Adding Types...')
|
|
self.addTypes(CModuleName)
|
|
FFIConstants.notify.info('Adding global values...')
|
|
self.addGlobalValues(CModuleName)
|
|
FFIConstants.notify.info('Adding global functions...')
|
|
self.addGlobalFunctions(CModuleName)
|
|
FFIConstants.notify.info('Adding manifests symbols...')
|
|
self.addManifestSymbols()
|
|
FFIConstants.notify.info('Adding environment types...')
|
|
self.addEnvironmentTypes()
|
|
|
|
|