*** empty log message ***

This commit is contained in:
Joe Shochet 2000-10-17 20:01:45 +00:00
parent d52b03d69a
commit 237a3e50a2
4 changed files with 186 additions and 25 deletions

View File

@ -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)

View File

@ -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
moduleName = 'lib' + interrogate_function_module_name(functionIndex)
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()

View File

@ -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
@ -52,10 +54,16 @@ def getTypeName(classTypeDesc, typeDesc):
# Convert the void type to None type... I guess...
# 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)

View File

@ -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
"""
indent(file, 0, 'self.' + self.getFinalName() + '(')
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 = ''