From 0084b86283cb3e90ffb4918c1e29329c9714993f Mon Sep 17 00:00:00 2001 From: Joe Shochet Date: Fri, 17 Nov 2000 22:37:18 +0000 Subject: [PATCH] *** empty log message *** --- direct/src/ffi/FFISpecs.py | 91 ++++--------- direct/src/ffi/FFITypes.py | 253 +++++++++++++++++++++---------------- 2 files changed, 169 insertions(+), 175 deletions(-) diff --git a/direct/src/ffi/FFISpecs.py b/direct/src/ffi/FFISpecs.py index 06444a8df9..e5f0e1ffb5 100644 --- a/direct/src/ffi/FFISpecs.py +++ b/direct/src/ffi/FFISpecs.py @@ -137,11 +137,7 @@ class GlobalFunctionSpecification(FunctionSpecification): self.outputMethodHeader(methodClass, file, nesting) self.outputMethodBody(methodClass, file, nesting) self.outputMethodFooter(methodClass, file, nesting) - def generateInheritedMethodCode(self, methodClass, parentClass, file, nesting, needsDowncast): - self.outputInheritedMethodHeader(methodClass, parentClass, file, nesting, needsDowncast) - self.outputInheritedMethodBody(methodClass, parentClass, file, nesting, needsDowncast) - self.outputInheritedMethodFooter(methodClass, parentClass, file, nesting, needsDowncast) - + ################################################## ## Global Function Code Generation ################################################## @@ -217,52 +213,6 @@ class GlobalFunctionSpecification(FunctionSpecification): def outputMethodFooter(self, methodClass, file, nesting): indent(file, nesting+1, '\n') - ################################################## - ## Upcast Class Method Code Generation - ################################################## - def outputInheritedMethodHeader(self, methodClass, parentClass, file, nesting, needsDowncast): - argTypes = self.typeDescriptor.argumentTypes - thislessArgTypes = self.typeDescriptor.thislessArgTypes() - indent(file, nesting+1, 'def ' + self.getFinalName() + '(self') - if (len(thislessArgTypes) > 0): - file.write(', ') - for i in range(len(thislessArgTypes)): - file.write(thislessArgTypes[i].name) - if (i < (len(thislessArgTypes)-1)): - file.write(', ') - file.write('):\n') - - def outputInheritedMethodBody(self, methodClass, parentClass, file, nesting, needsDowncast): - # The method body will look something like - # upcastSelf = self.upcastToParentClass() - # returnValue = ParentClass.method(upcastSelf, arg) - # returnValue.userManagesMemory = 1 (optional) - # return returnValue - self.outputCFunctionComment(file, nesting+2) - argTypes = self.typeDescriptor.argumentTypes - thislessArgTypes = self.typeDescriptor.thislessArgTypes() - self.outputTypeChecking(methodClass, thislessArgTypes, file, nesting+2) - if self.typeDescriptor.userManagesMemory: - indent(file, nesting+2, 'self.userManagesMemory = 1\n') - indent(file, nesting+2, 'upcastSelf = self.upcast' + 'To' - + parentClass.foreignTypeName + '()\n') - indent(file, nesting+2, 'returnValue = ' + parentClass.foreignTypeName - + '.' + self.typeDescriptor.wrapperName + '(upcastSelf.this') - if (len(thislessArgTypes) > 0): - file.write(', ') - for i in range(len(thislessArgTypes)): - file.write(thislessArgTypes[i].passName()) - if (i < (len(thislessArgTypes)-1)): - file.write(', ') - file.write(')\n') - returnType = self.typeDescriptor.returnType.recursiveTypeDescriptor() - # Generate the return value code with no downcast instructions - returnType.generateReturnValueWrapper(file, self.typeDescriptor.userManagesMemory, - needsDowncast, nesting+2) - - def outputInheritedMethodFooter(self, methodClass, parentClass, file, nesting, needsDowncast): - pass - class MethodSpecification(FunctionSpecification): def __init__(self): @@ -288,10 +238,10 @@ class MethodSpecification(FunctionSpecification): self.outputStaticBody(methodClass, file, nesting) self.outputStaticFooter(methodClass, file, nesting) - def generateInheritedMethodCode(self, methodClass, parentClass, file, nesting, needsDowncast): - self.outputInheritedMethodHeader(methodClass, parentClass, file, nesting, needsDowncast) - self.outputInheritedMethodBody(methodClass, parentClass, file, nesting, needsDowncast) - self.outputInheritedMethodFooter(methodClass, parentClass, file, nesting, needsDowncast) + def generateInheritedMethodCode(self, methodClass, parentList, file, nesting, needsDowncast): + self.outputInheritedMethodHeader(methodClass, parentList, file, nesting, needsDowncast) + self.outputInheritedMethodBody(methodClass, parentList, file, nesting, needsDowncast) + self.outputInheritedMethodFooter(methodClass, parentList, file, nesting, needsDowncast) def generateDowncastMethodCode(self, methodClass, file, nesting): # The downcast method code is just like regular code, but the @@ -342,6 +292,7 @@ class MethodSpecification(FunctionSpecification): indent(file, nesting+2, 'assert(self.this != 0)\n') if self.typeDescriptor.userManagesMemory: indent(file, nesting+2, 'self.userManagesMemory = 1\n') + def outputConstructorFooter(self, methodClass, file, nesting): indent(file, nesting+1, '\n') @@ -443,20 +394,19 @@ class MethodSpecification(FunctionSpecification): file.write(', ') file.write(')\n') returnType = self.typeDescriptor.returnType.recursiveTypeDescriptor() - returnType.generateReturnValueWrapper(file, self.typeDescriptor.userManagesMemory, 1, nesting+2) + returnType.generateReturnValueWrapper(file, self.typeDescriptor.userManagesMemory, + 1, nesting+2) def outputStaticFooter(self, methodClass, file, nesting): indent(file, nesting+1, self.getFinalName() + ' = ' + FFIConstants.staticModuleName + '.' + FFIConstants.staticModuleName + '(' + self.getFinalName() + ')\n') - indent(file, nesting+1, '\n') - - + indent(file, nesting+1, '\n') ################################################## ## Upcast Method Code Generation ################################################## - def outputInheritedMethodHeader(self, methodClass, parentClass, file, nesting, needsDowncast): + def outputInheritedMethodHeader(self, methodClass, parentList, file, nesting, needsDowncast): argTypes = self.typeDescriptor.argumentTypes thislessArgTypes = self.typeDescriptor.thislessArgTypes() indent(file, nesting+1, 'def ' + self.getFinalName() + '(self') @@ -468,7 +418,7 @@ class MethodSpecification(FunctionSpecification): file.write(', ') file.write('):\n') - def outputInheritedMethodBody(self, methodClass, parentClass, file, nesting, needsDowncast): + def outputInheritedMethodBody(self, methodClass, parentList, file, nesting, needsDowncast): # The method body will look something like # upcastSelf = self.upcastToParentClass() # returnValue = libpanda.method(upcastSelf.this, arg) @@ -478,10 +428,19 @@ class MethodSpecification(FunctionSpecification): argTypes = self.typeDescriptor.argumentTypes thislessArgTypes = self.typeDescriptor.thislessArgTypes() self.outputTypeChecking(methodClass, thislessArgTypes, file, nesting+2) - indent(file, nesting+2, 'upcastSelf = self.upcast' + 'To' - + parentClass.foreignTypeName + '()\n') + for i in range(len(parentList)): + # Only output the upcast call if that parent class defines it + parentClass = parentList[i] + methodName = 'upcastTo' + parentClass.foreignTypeName + if (i != 0): + childClass = parentList[i-1] + if childClass.hasMethodNamed(methodName): + indent(file, nesting+2, 'upcastSelf = self.' + methodName + '()\n') + else: + if methodClass.hasMethodNamed(methodName): + indent(file, nesting+2, 'upcastSelf = self.' + methodName + '()\n') indent(file, nesting+2, 'returnValue = ' + self.typeDescriptor.moduleName - + '.' + self.typeDescriptor.wrapperName + '(upcastSelf.this') + + '.' + self.typeDescriptor.wrapperName + '(upcastSelf.this') if (len(thislessArgTypes) > 0): file.write(', ') for i in range(len(thislessArgTypes)): @@ -494,8 +453,8 @@ class MethodSpecification(FunctionSpecification): returnType.generateReturnValueWrapper(file, self.typeDescriptor.userManagesMemory, needsDowncast, nesting+2) - def outputInheritedMethodFooter(self, methodClass, parentClass, file, nesting, needsDowncast): - indent(file, nesting+1, '\n') + def outputInheritedMethodFooter(self, methodClass, parentList, file, nesting, needsDowncast): + indent(file, nesting+1, '\n') class GlobalValueSpecification: diff --git a/direct/src/ffi/FFITypes.py b/direct/src/ffi/FFITypes.py index 8f076c6da8..93ab24502f 100644 --- a/direct/src/ffi/FFITypes.py +++ b/direct/src/ffi/FFITypes.py @@ -212,10 +212,6 @@ class ClassTypeDescriptor(BaseTypeDescriptor): # Instance methods that had no this pointer are moved into here self.staticMethods = [] - # Global methods that take this class as the first parameter are just - # stored with the class because it is more useable that way - self.globalMethods = [] - # These are dictionaries used to temporarily hold methods for # overloading while generating code self.overloadedClassMethods = {} @@ -224,6 +220,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): # Nested typeDescriptors inside this class self.nestedTypes = [] + def getExtensionModuleName(self): """ Return a filename for the extensions for this class @@ -243,12 +240,10 @@ class ClassTypeDescriptor(BaseTypeDescriptor): # Otherwise, it must be our first time through, do the real work self.CModules = [] for method in (self.constructors + [self.destructor] + self.instanceMethods - + self.upcastMethods + self.downcastMethods - + self.staticMethods + self.globalMethods): + + self.upcastMethods + self.downcastMethods + self.staticMethods): if method: if (not (method.typeDescriptor.moduleName in self.CModules)): self.CModules.append(method.typeDescriptor.moduleName) - # Now look at all the methods that we might inherit if we are at # a multiple inheritance node and get their C modules if (len(self.parentTypes) >= 2): @@ -259,10 +254,6 @@ class ClassTypeDescriptor(BaseTypeDescriptor): for method in parentType.upcastMethods: if (not (method.typeDescriptor.moduleName in self.CModules)): self.CModules.append(method.typeDescriptor.moduleName) - for method in parentType.globalMethods: - if (not (method.typeDescriptor.moduleName in self.CModules)): - self.CModules.append(method.typeDescriptor.moduleName) - return self.CModules @@ -272,51 +263,52 @@ class ClassTypeDescriptor(BaseTypeDescriptor): class references. Be careful about nested types """ - moduleList = [] - - upcastMethods = [] - if (len(self.parentTypes) >= 2): - for parentType in self.parentTypes: - for method in parentType.instanceMethods: - upcastMethods.append(method) - for method in parentType.upcastMethods: - upcastMethods.append(method) - for method in parentType.globalMethods: - upcastMethods.append(method) - - for method in (self.constructors + [self.destructor] + self.instanceMethods - + self.upcastMethods + self.downcastMethods - + self.staticMethods + self.globalMethods + upcastMethods): - if method: - # Get the real return type (not derived) - returnType = method.typeDescriptor.returnType.recursiveTypeDescriptor() - if (not returnType.isNested): - returnTypeName = returnType.foreignTypeName - # Do not put our own module in the import list - if ((returnTypeName != self.foreignTypeName) and - # Do not put modules already in the list (like a set) - (not (returnTypeName in moduleList))): - # If this is a class (not a primitive), put it on the list - if (returnType.__class__ == ClassTypeDescriptor): - moduleList.append(returnTypeName) - - # Now look at all the arguments - argTypes = method.typeDescriptor.argumentTypes - for argType in argTypes: + # Return type modules are cached once they are calculated so we + # do not have to calculate them again + try: + return self.returnTypeModules + except: + moduleList = [] + upcastMethods = [] + if (len(self.parentTypes) >= 2): + for parentType in self.parentTypes: + for method in parentType.instanceMethods: + upcastMethods.append(method) + for method in parentType.upcastMethods: + upcastMethods.append(method) + for method in (self.constructors + [self.destructor] + self.instanceMethods + + self.upcastMethods + self.downcastMethods + + self.staticMethods + upcastMethods): + if method: # Get the real return type (not derived) - argType = argType.typeDescriptor.recursiveTypeDescriptor() - if (not argType.isNested): - argTypeName = argType.foreignTypeName + returnType = method.typeDescriptor.returnType.recursiveTypeDescriptor() + if (not returnType.isNested): + returnTypeName = returnType.foreignTypeName # Do not put our own module in the import list - if ((argTypeName != self.foreignTypeName) and + if ((returnTypeName != self.foreignTypeName) and # Do not put modules already in the list (like a set) - (not (argTypeName in moduleList))): + (not (returnTypeName in moduleList))): # If this is a class (not a primitive), put it on the list - if (argType.__class__ == ClassTypeDescriptor): - moduleList.append(argTypeName) - - return moduleList - + if (returnType.__class__ == ClassTypeDescriptor): + moduleList.append(returnTypeName) + # Now 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 + if ((argTypeName != self.foreignTypeName) and + # Do not put modules already in the list (like a set) + (not (argTypeName in moduleList))): + # If this is a class (not a primitive), put it on the list + if (argType.__class__ == ClassTypeDescriptor): + moduleList.append(argTypeName) + self.returnTypeModules = moduleList + return self.returnTypeModules + + def recordClassMethod(self, methodSpec): """ Record all class methods in a 2 level dictionary so we can go @@ -326,6 +318,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): methodList = ifAbsentPut(self.overloadedClassMethods, methodSpec.name, []) methodList.append(methodSpec) + def recordInstanceMethod(self, methodSpec): """ Record all instance methods in a 2 level dictionary so we can go @@ -335,6 +328,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): methodList = ifAbsentPut(self.overloadedInstanceMethods, methodSpec.name, []) methodList.append(methodSpec) + def cullOverloadedMethods(self): """ Find all the entries that have multiple indexes for the same method name @@ -343,6 +337,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): self.overloadedClassMethods = FFIOverload.cullOverloadedMethods(self.overloadedClassMethods) self.overloadedInstanceMethods = FFIOverload.cullOverloadedMethods(self.overloadedInstanceMethods) + def filterOutStaticMethods(self): """ Run through the list of instance methods and filter out the @@ -361,6 +356,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): newInstanceMethods.append(method) self.instanceMethods = newInstanceMethods + def recordOverloadedMethods(self): """ Record all the methods in dictionaries based on method name @@ -372,16 +368,75 @@ class ClassTypeDescriptor(BaseTypeDescriptor): for method in classMethods: self.recordClassMethod(method) - instanceMethods = (self.instanceMethods + self.globalMethods - + self.upcastMethods + self.downcastMethods) + instanceMethods = (self.instanceMethods + self.upcastMethods + self.downcastMethods) for method in instanceMethods: self.recordInstanceMethod(method) + + def hasMethodNamed(self, methodName): + for method in (self.constructors + [self.destructor] + self.instanceMethods + + self.upcastMethods + self.downcastMethods + self.staticMethods): + if (method and (method.name == methodName)): + return 1 + return 0 + + + def copyParentMethods(self, file, nesting): + """ + At multiple inheritance nodes, copy all the parent methods into + this class and call them after upcasting us to that class + """ + if (len(self.parentTypes) >= 2): + indent(file, nesting+1, '\n') + indent(file, nesting+1, '##################################################\n') + indent(file, nesting+1, '# Upcast inherited instance method wrappers #\n') + indent(file, nesting+1, '##################################################\n') + indent(file, nesting+1, '\n') + for parentType in self.parentTypes: + parentList = [parentType] + self.copyParentMethodsRecursively(parentList, file, nesting) + + + 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.hasMethodNamed(method.name): + # with downcast for all instance methods that are not themselves upcasts + method.generateInheritedMethodCode(self, parentList, file, nesting, 1) + # Copy all the parents upcast methods so we transitively pick them up + for method in parent.upcastMethods: + if not self.hasMethodNamed(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 heirarchy 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') @@ -389,14 +444,13 @@ class ClassTypeDescriptor(BaseTypeDescriptor): indent(file, nesting+1, '# Overloaded methods #\n') indent(file, nesting+1, '##################################################\n') indent(file, nesting+1, '\n') - - for methodSpecList in self.overloadedClassMethods.values(): - treeColl = FFIOverload.FFIMethodArgumentTreeCollection(self, methodSpecList) - treeColl.generateCode(file, nesting) - for methodSpecList in self.overloadedInstanceMethods.values(): + # 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 generateGlobalCode(self, dir, extensionsDir): """ Generate shadow class code for this type. @@ -414,6 +468,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): self.outputClassFooter(file) file.close() + def generateCode(self, file, nesting): self.recordOverloadedMethods() self.cullOverloadedMethods() @@ -482,46 +537,12 @@ class ClassTypeDescriptor(BaseTypeDescriptor): for method in self.downcastMethods: method.generateDowncastMethodCode(self, file, nesting) - if len(self.globalMethods): - indent(file, nesting+1, '\n') - indent(file, nesting+1, '##################################################\n') - indent(file, nesting+1, '# Global methods #\n') - indent(file, nesting+1, '##################################################\n') - indent(file, nesting+1, '\n') - for method in self.globalMethods: - method.generateMethodCode(self, file, nesting) - - # At multiple inheritance nodes, copy all the parent methods into - # this class and call them after upcasting us to that class - if (len(self.parentTypes) >= 2): - indent(file, nesting+1, '\n') - indent(file, nesting+1, '##################################################\n') - indent(file, nesting+1, '# Upcast inherited instance method wrappers #\n') - indent(file, nesting+1, '##################################################\n') - indent(file, nesting+1, '\n') - for parentType in self.parentTypes: - # Copy all the parents instance methods - for method in parentType.instanceMethods: - method.generateInheritedMethodCode(self, parentType, file, nesting, 1) # with downcast - # Copy all the parents upcast methods so we transitively pick them up - for method in parentType.upcastMethods: - method.generateInheritedMethodCode(self, parentType, file, nesting, 0) # no downcast - # Do not copy the downcast methods - - # At multiple inheritance nodes, copy all the parent methods into - # this class and call them after upcasting us to that class - if (len(self.parentTypes) >= 2): - indent(file, nesting+1, '\n') - indent(file, nesting+1, '##################################################\n') - indent(file, nesting+1, '# Upcast global method wrappers #\n') - indent(file, nesting+1, '##################################################\n') - indent(file, nesting+1, '\n') - for parentType in self.parentTypes: - for method in parentType.globalMethods: - method.generateInheritedMethodCode(self, parentType, file, nesting, 1) # with downcast - + # Copy in all our parent nodes (only does work if we are an MI node) + self.copyParentMethods(file, nesting) + self.generateOverloadedMethods(file, nesting) + def outputNestedTypes(self, file, nesting): if (len(self.nestedTypes) > 0): indent(file, nesting+1, '\n') @@ -533,6 +554,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): for nestedType in self.nestedTypes: nestedType.generateCode(file, nesting+1) + def copyExtensions(self, extensionsDir, file, nesting): """ Copy in the extension file for this class if one exists @@ -568,28 +590,37 @@ class ClassTypeDescriptor(BaseTypeDescriptor): indent(file, 0, 'import ' + moduleName + 'Downcasts\n') indent(file, 0, '\n') indent(file, 0, 'import FFIExternalObject\n') + + + def outputImportsRecursively(self, parent, file, nesting): + for parentType in parent.parentTypes: + self.outputImportsRecursively(parentType, file, nesting) + indent(file, nesting, 'import ' + parent.foreignTypeName + '\n') + returnTypeModules = parent.getReturnTypeModules() + if len(returnTypeModules): + for moduleName in returnTypeModules: + indent(file, nesting, 'import ' + moduleName + '\n') + def outputImports(self, file, nesting): """ Generate code that imports the modules we need for this class """ + indent(file, nesting, '# Import everybody we inherit from\n') + indent(file, nesting, '# and all the shadow class modules this class uses\n') - if len(self.parentTypes): - indent(file, nesting, '# Import everybody we inherit from\n') - for parent in self.parentTypes: - indent(file, nesting, 'import ' + parent.foreignTypeName + '\n') - indent(file, nesting, '\n') - + # Output all of our return types returnTypeModules = self.getReturnTypeModules() if len(returnTypeModules): - indent(file, nesting, '# Import all the shadow class modules this class uses\n') for moduleName in returnTypeModules: indent(file, nesting, 'import ' + moduleName + '\n') - - # an extra line just for spacing + + for parentType in self.parentTypes: + self.outputImportsRecursively(parentType, file, nesting) indent(file, nesting, '\n') + def outputClassComment(self, file, nesting): """ Output the class comment to the file @@ -660,6 +691,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): def outputClassFooter(self, file): indent(file, 0, " # When this class gets defined, put it in this module's namespace\n") indent(file, 0, " globals()['" + self.foreignTypeName + "'] = " + self.foreignTypeName + '\n') + def outputBaseConstructor(self, file, nesting): """ @@ -681,6 +713,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): indent(file, nesting+2, 'apply(self.constructor, _args)\n') indent(file, nesting+2, '\n') + def outputEmptyConstructor(self, file, nesting): """ If there is no C++ constructor, we output code for a runtime error @@ -689,6 +722,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): indent(file, nesting+1, 'def constructor(self):\n') indent(file, nesting+2, "raise RuntimeError, 'No C++ constructor defined for class: ' + self.__class__.__name__\n") + def outputBaseDestructor(self, file, nesting): """ This destructor overwrites the builtin Python destructor @@ -711,6 +745,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor): indent(file, nesting+2, 'if (self.userManagesMemory and (self.this != 0)):\n') indent(file, nesting+3, 'self.destructor()\n') + def outputEmptyDestructor(self, file, nesting): """ If there is no C++ destructor, we just output this @@ -719,8 +754,8 @@ class ClassTypeDescriptor(BaseTypeDescriptor): indent(file, nesting+1, 'def destructor(self):\n') indent(file, nesting+2, 'pass\n') - def generateReturnValueWrapper(self, file, userManagesMemory, - needsDowncast, nesting): + + def generateReturnValueWrapper(self, 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