mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 15:53:55 -04:00
*** empty log message ***
This commit is contained in:
parent
d52b03d69a
commit
237a3e50a2
@ -5,6 +5,7 @@ class FFIEnvironment:
|
||||
self.types = {}
|
||||
self.globalFunctions = []
|
||||
self.globalValues = []
|
||||
self.manifests = []
|
||||
|
||||
def addType(self, typeDescriptor, name):
|
||||
if self.types.has_key(name):
|
||||
@ -21,3 +22,5 @@ class FFIEnvironment:
|
||||
self.globalFunctions.append(typeDescriptor)
|
||||
def addGlobalValue(self, typeDescriptor):
|
||||
self.globalValues.append(typeDescriptor)
|
||||
def addManifest(self, typeDescriptor):
|
||||
self.manifests.append(typeDescriptor)
|
||||
|
@ -44,6 +44,9 @@ def outputGlobalFileImports(file, methodList):
|
||||
# Print the standard header
|
||||
file.write(FFIConstants.generatedHeader)
|
||||
|
||||
# Import Python's builtin types
|
||||
file.write('import types\n')
|
||||
|
||||
# Import the C modules
|
||||
for CModuleName in FFIConstants.CodeModuleNameList:
|
||||
file.write('import ' + CModuleName + '\n')
|
||||
@ -370,7 +373,10 @@ class FFIInterrogateDatabase:
|
||||
# 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
|
||||
@ -497,6 +503,8 @@ class FFIInterrogateDatabase:
|
||||
# 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
|
||||
@ -528,7 +536,9 @@ class FFIInterrogateDatabase:
|
||||
def constructGlobal(self, globalIndex):
|
||||
# We really do not need the descriptor for the value, just
|
||||
# the getter and setter
|
||||
# descriptor = self.typeIndexMap[interrogate_element_type(globalIndex)]
|
||||
# typeIndex = interrogate_element_type(globalIndex)
|
||||
# descriptor = self.constructDescriptor(typeIndex)
|
||||
|
||||
if interrogate_element_has_getter(globalIndex):
|
||||
getterIndex = interrogate_element_getter(globalIndex)
|
||||
getter = self.constructGlobalFunction(getterIndex)
|
||||
@ -602,6 +612,46 @@ class FFIInterrogateDatabase:
|
||||
newGlob = self.constructGlobal(globalIndex)
|
||||
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):
|
||||
FFIConstants.notify.info( 'Generating static class...')
|
||||
generateStaticClass(codeDir)
|
||||
@ -627,6 +677,7 @@ class FFIInterrogateDatabase:
|
||||
# Output all the imports based on this list of functions
|
||||
outputGlobalFileImports(globalFile, globalFunctions)
|
||||
|
||||
FFIConstants.notify.info( 'Generating global value code...')
|
||||
for type in self.environment.globalValues:
|
||||
type.generateGlobalCode(globalFile)
|
||||
|
||||
@ -634,13 +685,17 @@ class FFIInterrogateDatabase:
|
||||
for type in self.environment.globalFunctions:
|
||||
type.generateGlobalCode(globalFile)
|
||||
|
||||
FFIConstants.notify.info( 'Generating manifest code...')
|
||||
for type in self.environment.manifests:
|
||||
type.generateGlobalCode(globalFile)
|
||||
|
||||
globalFile.close()
|
||||
|
||||
FFIConstants.notify.info( 'Generating import code...')
|
||||
importFile = constructImportFile(codeDir)
|
||||
outputImportFileImports(importFile, self.environment.types.values())
|
||||
|
||||
|
||||
FFIConstants.notify.info( 'Compiling code...')
|
||||
compileall.compile_dir(codeDir)
|
||||
|
||||
|
||||
@ -652,4 +707,9 @@ class FFIInterrogateDatabase:
|
||||
self.addGlobalValues()
|
||||
FFIConstants.notify.info( 'Adding global functions...')
|
||||
self.addGlobalFunctions()
|
||||
FFIConstants.notify.info( 'Adding manifests symbols...')
|
||||
self.addManifestSymbols()
|
||||
FFIConstants.notify.info( 'Adding environment types...')
|
||||
self.addEnvironmentTypes()
|
||||
|
||||
|
||||
|
@ -3,11 +3,13 @@ from PythonUtil import *
|
||||
from types import *
|
||||
import string
|
||||
import FFIConstants
|
||||
import FFISpecs
|
||||
|
||||
"""
|
||||
Things that are not supported:
|
||||
- Overloading a function based on an enum being differentiated from an int
|
||||
- Type names from C++ cannot begin with __enum__
|
||||
- Type names from C++ cannot have __enum__ in their name
|
||||
- Overloading static and non-static methods with the same name
|
||||
"""
|
||||
|
||||
AT_not_atomic = 0
|
||||
@ -53,9 +55,15 @@ def getTypeName(classTypeDesc, typeDesc):
|
||||
# So far we do not have any code that uses this
|
||||
return 'types.NoneType'
|
||||
|
||||
else:
|
||||
FFIConstants.notify.error("Unknown atomicType: " + typeDesc.atomicType)
|
||||
|
||||
# If the type is an enum, we really want to treat it like an int
|
||||
# To handle this, the type will have __enum__ prepended to the name
|
||||
elif (typeName[0:8] == '__enum__'):
|
||||
# To handle this, the type will have __enum__ in the name
|
||||
# Usually it will start the typeName, but some typeNames have the
|
||||
# surrounding class as part of their name
|
||||
# like BoundedObject.__enum__BoundingVolumeType
|
||||
elif (typeName.find('__enum__') >= 0):
|
||||
return 'types.IntType'
|
||||
|
||||
# If it was not atomic or enum, it must be a class which is a
|
||||
@ -146,15 +154,44 @@ class FFIMethodArgumentTreeCollection:
|
||||
self.methodDict = {}
|
||||
self.treeDict = {}
|
||||
|
||||
def outputOverloadedMethodHeader(self, file):
|
||||
indent(file, 1, 'def ' + self.methodSpecList[0].name
|
||||
+ '(self, *_args):\n')
|
||||
indent(file, 2, 'numArgs = len(_args)\n')
|
||||
def outputOverloadedMethodHeader(self, file, nesting):
|
||||
# If one is static, we assume they all are.
|
||||
# The current system does not support overloading static and non-static
|
||||
# methods with the same name
|
||||
# Constructors are not treated as static. They are special because
|
||||
# they are not really constructors, they are instance methods that fill
|
||||
# in the this pointer.
|
||||
if (self.methodSpecList[0].isStatic() and
|
||||
(not self.methodSpecList[0].isConstructor())):
|
||||
indent(file, nesting+1, 'def ' +
|
||||
self.methodSpecList[0].name + '(*_args):\n')
|
||||
else:
|
||||
indent(file, nesting+1, 'def ' +
|
||||
self.methodSpecList[0].name + '(self, *_args):\n')
|
||||
indent(file, nesting+2, 'numArgs = len(_args)\n')
|
||||
|
||||
def outputOverloadedMethodFooter(self, file):
|
||||
def outputOverloadedMethodFooter(self, file, nesting):
|
||||
# If the overloaded function got all the way through the if statements
|
||||
# it must have had the wrong number or type of arguments
|
||||
indent(file, 2, "raise TypeError, 'Invalid arguments'\n\n")
|
||||
indent(file, nesting+2, "raise TypeError, 'Invalid arguments'\n")
|
||||
|
||||
# If this is a static method, we need to output a static version
|
||||
# If one is static, we assume they all are.
|
||||
# The current system does not support overloading static and non-static
|
||||
# methods with the same name
|
||||
# Constructors are not treated as static. They are special because
|
||||
# they are not really constructors, they are instance methods that fill
|
||||
# in the this pointer.
|
||||
|
||||
if (self.methodSpecList[0].isStatic() and
|
||||
(not self.methodSpecList[0].isConstructor())):
|
||||
self.outputOverloadedStaticFooter(file, nesting)
|
||||
indent(file, nesting+1, '\n')
|
||||
|
||||
def outputOverloadedStaticFooter(self, file, nesting):
|
||||
indent(file, nesting+1, self.methodSpecList[0].name + ' = '
|
||||
+ FFIConstants.staticModuleName + '.' + FFIConstants.staticModuleName
|
||||
+ '(' + self.methodSpecList[0].name + ')\n')
|
||||
|
||||
def setup(self):
|
||||
for method in self.methodSpecList:
|
||||
@ -169,16 +206,16 @@ class FFIMethodArgumentTreeCollection:
|
||||
|
||||
def generateCode(self, file, nesting):
|
||||
self.setup()
|
||||
self.outputOverloadedMethodHeader(file)
|
||||
self.outputOverloadedMethodHeader(file, nesting)
|
||||
numArgsKeys = self.treeDict.keys()
|
||||
numArgsKeys.sort()
|
||||
for numArgs in numArgsKeys:
|
||||
trees = self.treeDict[numArgs]
|
||||
for tree in trees:
|
||||
indent(file, 2, 'if (numArgs == ' + `numArgs` + '):\n')
|
||||
indent(file, nesting+2, 'if (numArgs == ' + `numArgs` + '):\n')
|
||||
tree.setup()
|
||||
tree.traverse(file)
|
||||
self.outputOverloadedMethodFooter(file)
|
||||
tree.traverse(file, nesting+1)
|
||||
self.outputOverloadedMethodFooter(file, nesting)
|
||||
|
||||
class FFIMethodArgumentTree:
|
||||
"""
|
||||
@ -241,7 +278,7 @@ class FFIMethodArgumentTree:
|
||||
# Output the function
|
||||
methodSpec = self.tree[0][1]
|
||||
indent(file, level+2, 'return ')
|
||||
methodSpec.outputOverloadedCall(file, 0)
|
||||
methodSpec.outputOverloadedCall(file, self.classTypeDesc, 0)
|
||||
else:
|
||||
typeName = getTypeName(self.classTypeDesc, typeDesc)
|
||||
indent(file, level+2, 'if (isinstance(_args[' + `level-1` + '], '
|
||||
@ -260,7 +297,7 @@ class FFIMethodArgumentTree:
|
||||
methodSpec = self.tree[typeDesc][1]
|
||||
indent(file, level+3, 'return ')
|
||||
numArgs = level
|
||||
methodSpec.outputOverloadedCall(file, numArgs)
|
||||
methodSpec.outputOverloadedCall(file, self.classTypeDesc, numArgs)
|
||||
|
||||
|
||||
|
||||
|
@ -12,6 +12,18 @@ class FunctionSpecification:
|
||||
self.typeDescriptor = None
|
||||
self.index = 0
|
||||
self.overloaded = 0
|
||||
# Is this function a constructor
|
||||
self.constructor = 0
|
||||
|
||||
def isConstructor(self):
|
||||
return self.constructor
|
||||
|
||||
def isStatic(self):
|
||||
for arg in self.typeDescriptor.argumentTypes:
|
||||
if arg.isThis:
|
||||
return 0
|
||||
# No args were this pointers, must be static
|
||||
return 1
|
||||
|
||||
def outputTypeChecking(self, methodClass, args, file, nesting):
|
||||
"""
|
||||
@ -73,13 +85,26 @@ class FunctionSpecification:
|
||||
else:
|
||||
return self.name
|
||||
|
||||
def outputOverloadedCall(self, file, numArgs):
|
||||
def outputOverloadedCall(self, file, classTypeDesc, numArgs):
|
||||
"""
|
||||
Write the function call to call this overloaded method
|
||||
For example:
|
||||
self.overloaded_setPos_ptrNodePath_float_float_float(_args[0], _args[1], _args[2])
|
||||
If it is a class (static) method, call the class method
|
||||
Class.overloaded_setPos_ptrNodePath_float_float_float(_args[0], _args[1], _args[2])
|
||||
|
||||
Constructors are not treated as static. They are special because
|
||||
they are not really constructors, they are instance methods that fill
|
||||
in the this pointer.
|
||||
|
||||
These do not get indented because they are not the beginning of the line
|
||||
|
||||
"""
|
||||
if (self.isStatic() and not self.isConstructor()):
|
||||
indent(file, 0, classTypeDesc.foreignTypeName + '.' + self.getFinalName() + '(')
|
||||
else:
|
||||
indent(file, 0, 'self.' + self.getFinalName() + '(')
|
||||
|
||||
for i in range(numArgs):
|
||||
file.write('_args[' + `i` + ']')
|
||||
if (i != (numArgs - 1)):
|
||||
@ -230,11 +255,6 @@ class GlobalFunctionSpecification(FunctionSpecification):
|
||||
class MethodSpecification(FunctionSpecification):
|
||||
def __init__(self):
|
||||
FunctionSpecification.__init__(self)
|
||||
def isStatic(self):
|
||||
for arg in self.typeDescriptor.argumentTypes:
|
||||
if arg.isThis:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def generateConstructorCode(self, methodClass, file, nesting):
|
||||
self.outputConstructorHeader(methodClass, file, nesting)
|
||||
@ -484,6 +504,47 @@ class GlobalValueSpecification:
|
||||
self.setter.generateGlobalCode(file)
|
||||
indent(file, 0, '\n')
|
||||
|
||||
|
||||
# Manifest symbols
|
||||
class ManifestSpecification:
|
||||
def __init__(self):
|
||||
self.name = ''
|
||||
|
||||
# We are not currently using the type descriptor
|
||||
self.typeDescriptor = None
|
||||
|
||||
# To be filled in with a GlobalFunctionSpecification
|
||||
# if this manifest has one
|
||||
self.getter = None
|
||||
|
||||
# Manifests that have int values have their int value defined
|
||||
# instead of having to call a getter (because there are so many of them)
|
||||
self.intValue = None
|
||||
|
||||
# The string definition of this manifest
|
||||
self.definition = None
|
||||
|
||||
def generateGlobalCode(self, file):
|
||||
# Note, if the manifest has no value and no getter we do not output anything
|
||||
# even though they may be defined in the C++ sense. Without any values
|
||||
# they are pretty useless in Python
|
||||
|
||||
# If it has an int value, just output that instead of bothering
|
||||
# with a getter
|
||||
if (self.intValue != None):
|
||||
indent(file, 0, '# Manifest: ' + self.name + '\n')
|
||||
indent(file, 0, (self.name + ' = ' + `self.intValue` + '\n'))
|
||||
indent(file, 0, '\n')
|
||||
|
||||
elif self.definition:
|
||||
indent(file, 0, ('# Manifest: ' + self.name + ' definition: ' +
|
||||
self.definition + '\n'))
|
||||
# Out put the getter
|
||||
if self.getter:
|
||||
self.getter.generateGlobalCode(file)
|
||||
indent(file, 0, '\n')
|
||||
|
||||
|
||||
class MethodArgumentSpecification:
|
||||
def __init__(self):
|
||||
self.name = ''
|
||||
|
Loading…
x
Reference in New Issue
Block a user