Browse Source

*** empty log message ***

Joe Shochet 25 years ago
parent
commit
237a3e50a2

+ 3 - 0
direct/src/ffi/FFIEnvironment.py

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

+ 63 - 3
direct/src/ffi/FFIInterrogateDatabase.py

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

+ 52 - 15
direct/src/ffi/FFIOverload.py

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

+ 68 - 7
direct/src/ffi/FFISpecs.py

@@ -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 = ''