mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-26 13:12:30 -06:00
587 lines
26 KiB
Python
587 lines
26 KiB
Python
|
|
||
|
import FFIConstants
|
||
|
import FFITypes
|
||
|
import FFIOverload
|
||
|
import string
|
||
|
|
||
|
from direct.showbase.PythonUtil import *
|
||
|
|
||
|
augmentedAssignments = ['__iadd__', '__isub__', '__imul__', '__idiv__',
|
||
|
'__ior__', '__iand__', '__ixor__',
|
||
|
'__ilshift__', '__irshift__']
|
||
|
|
||
|
class FunctionSpecification:
|
||
|
def __init__(self):
|
||
|
self.name = ''
|
||
|
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):
|
||
|
"""
|
||
|
Output an assert statement to check the type of each arg in this method
|
||
|
This can be turned off with a command line parameter in generatePythonCode
|
||
|
It is valid to pass in None for methodClass if you are not in any methodClass
|
||
|
"""
|
||
|
if FFIConstants.wantTypeChecking:
|
||
|
for i in range(len(args)):
|
||
|
methodArgSpec = args[i]
|
||
|
typeDesc = methodArgSpec.typeDescriptor.recursiveTypeDescriptor()
|
||
|
typeName = FFIOverload.getTypeName(methodClass, typeDesc)
|
||
|
|
||
|
# We only do type checking on class types. C++ can do
|
||
|
# type checking on the primitive types, and will do a
|
||
|
# better job anyway.
|
||
|
if typeDesc.__class__ == FFITypes.ClassTypeDescriptor:
|
||
|
# Get the real return type (not derived)
|
||
|
if ((not typeDesc.isNested) and
|
||
|
# Do not put our own module in the import list
|
||
|
(methodClass != typeDesc)):
|
||
|
indent(file, nesting, 'import ' + typeDesc.foreignTypeName + '\n')
|
||
|
indent(file, nesting, 'if not isinstance(' +
|
||
|
methodArgSpec.name + ', ' + typeName + '):\n')
|
||
|
indent(file, nesting + 1,
|
||
|
'raise TypeError, "Invalid argument %s, expected <%s>"\n' % (i, typeDesc.foreignTypeName))
|
||
|
|
||
|
def outputCFunctionComment(self, file, nesting):
|
||
|
"""
|
||
|
Output a docstring to the file describing the C++ call with type info
|
||
|
Also output the C++ comment from interrogate.
|
||
|
"""
|
||
|
if FFIConstants.wantComments:
|
||
|
indent(file, nesting, '"""\n')
|
||
|
|
||
|
# Output the function prototype
|
||
|
if self.typeDescriptor.prototype:
|
||
|
indent(file, nesting, self.typeDescriptor.prototype + '\n')
|
||
|
|
||
|
# Output the function comment
|
||
|
if self.typeDescriptor.comment:
|
||
|
# To insert tabs into the comment, replace all newlines with a newline+tabs
|
||
|
comment = string.replace(self.typeDescriptor.comment,
|
||
|
'\n', ('\n' + (' ' * nesting)))
|
||
|
indent(file, nesting, comment)
|
||
|
|
||
|
indent(file, 0, '\n')
|
||
|
indent(file, nesting, '"""\n')
|
||
|
|
||
|
def getFinalName(self):
|
||
|
"""
|
||
|
Return the name of the function given that it might be overloaded
|
||
|
If it is overloaded, prepend "overloaded", then append the types of
|
||
|
each argument to make it unique.
|
||
|
|
||
|
So "getChild(int)" becomes "overloaded_getChild_int(int)"
|
||
|
"""
|
||
|
if self.overloaded:
|
||
|
name = 'private__overloaded_' + self.name
|
||
|
for methodArgSpec in self.typeDescriptor.argumentTypes:
|
||
|
name = name + '_' + methodArgSpec.typeDescriptor.foreignTypeName
|
||
|
return name
|
||
|
else:
|
||
|
return self.name
|
||
|
|
||
|
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)
|
||
|
If it is a class (static) method, call the class method
|
||
|
Class.overloaded_setPos_ptrNodePath_float_float_float(*_args)
|
||
|
|
||
|
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 classTypeDesc is None, then this is a global function and should
|
||
|
output code as such
|
||
|
|
||
|
"""
|
||
|
if classTypeDesc:
|
||
|
if (self.isStatic() and not self.isConstructor()):
|
||
|
if numArgs:
|
||
|
indent(file, 0, classTypeDesc.foreignTypeName + '.' + self.getFinalName() + '(*_args)\n')
|
||
|
else:
|
||
|
indent(file, 0, classTypeDesc.foreignTypeName + '.' + self.getFinalName() + '()\n')
|
||
|
else:
|
||
|
if numArgs:
|
||
|
indent(file, 0, 'self.' + self.getFinalName() + '(*_args)\n')
|
||
|
else:
|
||
|
indent(file, 0, 'self.' + self.getFinalName() + '()\n')
|
||
|
else:
|
||
|
if numArgs:
|
||
|
indent(file, 0, self.getFinalName() + '(*_args)\n')
|
||
|
else:
|
||
|
indent(file, 0, self.getFinalName() + '()\n')
|
||
|
|
||
|
|
||
|
class GlobalFunctionSpecification(FunctionSpecification):
|
||
|
def __init__(self):
|
||
|
FunctionSpecification.__init__(self)
|
||
|
|
||
|
# Use generateCode when creating a global (non-class) function
|
||
|
def generateGlobalCode(self, file):
|
||
|
self.outputHeader(file)
|
||
|
self.outputBody(file)
|
||
|
self.outputFooter(file)
|
||
|
|
||
|
# Use generateCode when creating a global (non-class) function
|
||
|
def generateGlobalDowncastCode(self, file):
|
||
|
self.outputHeader(file)
|
||
|
self.outputBody(file, 0, 0) # no downcast, no type checking
|
||
|
self.outputFooter(file)
|
||
|
|
||
|
# Use generateMethodCode when creating a global->class function
|
||
|
def generateMethodCode(self, methodClass, file, nesting):
|
||
|
self.outputMethodHeader(methodClass, file, nesting)
|
||
|
self.outputMethodBody(methodClass, file, nesting)
|
||
|
self.outputMethodFooter(methodClass, file, nesting)
|
||
|
|
||
|
##################################################
|
||
|
## Global Function Code Generation
|
||
|
##################################################
|
||
|
def outputHeader(self, file):
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
indent(file, 0, 'def ' + self.getFinalName() + '(')
|
||
|
for i in range(len(argTypes)):
|
||
|
file.write(argTypes[i].name)
|
||
|
if (i < (len(argTypes)-1)):
|
||
|
file.write(', ')
|
||
|
file.write('):\n')
|
||
|
|
||
|
def outputBody(self, file, needsDowncast=1, typeChecking=1):
|
||
|
# The method body will look something like
|
||
|
# returnValue = PandaGlobal.method(arg)
|
||
|
# returnObject = NodePath()
|
||
|
# returnObject.this = returnValue
|
||
|
# returnObject.userManagesMemory = 1 (optional)
|
||
|
# return returnObject
|
||
|
self.outputCFunctionComment(file, 1)
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
# The global downcast functions do not need type checking, and
|
||
|
# in fact have a problem where they assert you are downcasting
|
||
|
# from the immediate superclass when in fact you may be downcasting
|
||
|
# from a class way up the chain as long as their is single
|
||
|
# inheritance up to it
|
||
|
if typeChecking:
|
||
|
self.outputTypeChecking(None, argTypes, file, 1)
|
||
|
indent(file, 1, 'returnValue = ' + self.typeDescriptor.moduleName
|
||
|
+ '.' + self.typeDescriptor.wrapperName + '(')
|
||
|
for i in range(len(argTypes)):
|
||
|
file.write(argTypes[i].passName())
|
||
|
if (i < (len(argTypes)-1)):
|
||
|
file.write(', ')
|
||
|
file.write(')\n')
|
||
|
#indent(file, 1, 'if returnValue is None:\n')
|
||
|
#indent(file, 2, 'return None\n')
|
||
|
returnType = self.typeDescriptor.returnType.recursiveTypeDescriptor()
|
||
|
returnType.generateReturnValueWrapper(None, file,
|
||
|
self.typeDescriptor.userManagesMemory,
|
||
|
needsDowncast, 1)
|
||
|
|
||
|
def outputFooter(self, file):
|
||
|
indent(file, 0, '\n')
|
||
|
|
||
|
##################################################
|
||
|
## Class Method Code Generation
|
||
|
##################################################
|
||
|
def outputMethodHeader(self, methodClass, file, nesting):
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
indent(file, nesting, 'def ' + self.getFinalName() + '(')
|
||
|
for i in range(len(argTypes)):
|
||
|
# Instead of the first argument, put self
|
||
|
if (i == 0):
|
||
|
file.write('self')
|
||
|
else:
|
||
|
file.write(argTypes[i].name)
|
||
|
if (i < (len(argTypes)-1)):
|
||
|
file.write(', ')
|
||
|
file.write('):\n')
|
||
|
|
||
|
def outputMethodBody(self, methodClass, file, nesting):
|
||
|
# The method body will look something like
|
||
|
# returnValue = PandaGlobal.method(self.this, arg)
|
||
|
# returnValue.userManagesMemory = 1 (optional)
|
||
|
# return returnValue
|
||
|
self.outputCFunctionComment(file, nesting+2)
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
self.outputTypeChecking(methodClass, argTypes[1:], file, nesting+2)
|
||
|
indent(file, nesting+2, 'returnValue = ' + self.typeDescriptor.moduleName
|
||
|
+ '.' + self.typeDescriptor.wrapperName + '(')
|
||
|
for i in range(len(argTypes)):
|
||
|
# Instead of the first argument, put self.this
|
||
|
if (i == 0):
|
||
|
file.write('self.this')
|
||
|
else:
|
||
|
file.write(argTypes[i].passName())
|
||
|
if (i < (len(argTypes)-1)):
|
||
|
file.write(', ')
|
||
|
file.write(')\n')
|
||
|
indent(file, 1, 'if returnValue is None:\n')
|
||
|
indent(file, 2, 'return None\n')
|
||
|
|
||
|
returnType = self.typeDescriptor.returnType.recursiveTypeDescriptor()
|
||
|
returnType.generateReturnValueWrapper(methodClass, file,
|
||
|
self.typeDescriptor.userManagesMemory,
|
||
|
1, nesting+2)
|
||
|
|
||
|
def outputMethodFooter(self, methodClass, file, nesting):
|
||
|
indent(file, nesting+1, '\n')
|
||
|
|
||
|
|
||
|
class MethodSpecification(FunctionSpecification):
|
||
|
def __init__(self):
|
||
|
FunctionSpecification.__init__(self)
|
||
|
|
||
|
def generateConstructorCode(self, methodClass, file, nesting):
|
||
|
self.outputConstructorHeader(methodClass, file, nesting)
|
||
|
self.outputConstructorBody(methodClass, file, nesting)
|
||
|
self.outputConstructorFooter(methodClass, file, nesting)
|
||
|
|
||
|
def generateDestructorCode(self, methodClass, file, nesting):
|
||
|
self.outputDestructorHeader(methodClass, file, nesting)
|
||
|
self.outputDestructorBody(methodClass, file, nesting)
|
||
|
self.outputDestructorFooter(methodClass, file, nesting)
|
||
|
|
||
|
def generateMethodCode(self, methodClass, file, nesting):
|
||
|
self.outputMethodHeader(methodClass, file, nesting)
|
||
|
self.outputMethodBody(methodClass, file, nesting)
|
||
|
self.outputMethodFooter(methodClass, file, nesting)
|
||
|
|
||
|
def generateStaticCode(self, methodClass, file, nesting):
|
||
|
self.outputStaticHeader(methodClass, file, nesting)
|
||
|
self.outputStaticBody(methodClass, file, nesting)
|
||
|
self.outputStaticFooter(methodClass, file, nesting)
|
||
|
|
||
|
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 generateUpcastMethodCode(self, methodClass, file, nesting):
|
||
|
# The upcast method code is just like regular code, but the
|
||
|
# return value wrapper does not have downcasting instructions
|
||
|
self.outputMethodHeader(methodClass, file, nesting)
|
||
|
self.outputMethodBody(methodClass, file, nesting, 0) # no downcast
|
||
|
self.outputMethodFooter(methodClass, file, nesting)
|
||
|
|
||
|
##################################################
|
||
|
## Constructor Code Generation
|
||
|
##################################################
|
||
|
def outputConstructorHeader(self, methodClass, file, nesting):
|
||
|
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')
|
||
|
self.outputCFunctionComment(file, nesting+2)
|
||
|
|
||
|
|
||
|
def outputConstructorBody(self, methodClass, file, nesting):
|
||
|
# The method body will look something like
|
||
|
# self.this = panda.Class_constructor(arg)
|
||
|
# self.userManagesMemory = 1 (optional)
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
thislessArgTypes = self.typeDescriptor.thislessArgTypes()
|
||
|
self.outputTypeChecking(methodClass, thislessArgTypes, file, nesting+2)
|
||
|
indent(file, nesting+2, 'self.this = ' + self.typeDescriptor.moduleName + '.'
|
||
|
+ self.typeDescriptor.wrapperName + '(')
|
||
|
# Do not pass self into the constructor
|
||
|
for i in range(len(thislessArgTypes)):
|
||
|
file.write(thislessArgTypes[i].passName())
|
||
|
if (i < (len(thislessArgTypes)-1)):
|
||
|
file.write(', ')
|
||
|
file.write(')\n')
|
||
|
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')
|
||
|
|
||
|
|
||
|
##################################################
|
||
|
## Destructor Code Generation
|
||
|
##################################################
|
||
|
def outputDestructorHeader(self, methodClass, file, nesting):
|
||
|
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')
|
||
|
self.outputCFunctionComment(file, nesting+2)
|
||
|
|
||
|
def outputDestructorBody(self, methodClass, file, nesting):
|
||
|
# The method body will look something like
|
||
|
# panda.Class_destructor(self.this)
|
||
|
functionName = (self.typeDescriptor.moduleName + '.'
|
||
|
+ self.typeDescriptor.wrapperName)
|
||
|
# Make sure the module and function have not been deleted first
|
||
|
# This only happens during shutdown
|
||
|
indent(file, nesting+2, 'if (' + self.typeDescriptor.moduleName + ' and ' +
|
||
|
functionName + '):\n')
|
||
|
indent(file, nesting+3, functionName + '(self.this)\n')
|
||
|
|
||
|
def outputDestructorFooter(self, methodClass, file, nesting):
|
||
|
indent(file, nesting+1, '\n')
|
||
|
|
||
|
##################################################
|
||
|
## Method Code Generation
|
||
|
##################################################
|
||
|
def outputMethodHeader(self, methodClass, file, nesting):
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
thislessArgTypes = self.typeDescriptor.thislessArgTypes()
|
||
|
indent(file, nesting, '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 outputMethodBody(self, methodClass, file, nesting, needsDowncast=1):
|
||
|
# The method body will look something like
|
||
|
# returnValue = panda.Class_method(self.this, 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)
|
||
|
indent(file, nesting+2, 'returnValue = ' + self.typeDescriptor.moduleName + '.'
|
||
|
+ self.typeDescriptor.wrapperName + '(')
|
||
|
file.write('self.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')
|
||
|
# If this is an augmented assignment operator like +=, we have special rules
|
||
|
# In this case we simply call the C++ function, make sure we got the same
|
||
|
# return value back, then return self. Otherwise if you let it go through the
|
||
|
# normal system, it actually deletes the old Python object causing the C++ memory
|
||
|
# to be deleted then returns a new Python shadow object with the old C++ pointer... BAD!
|
||
|
if self.getFinalName() in augmentedAssignments:
|
||
|
indent(file, nesting+2, 'assert self.this == returnValue\n')
|
||
|
indent(file, nesting+2, 'return self\n')
|
||
|
else:
|
||
|
returnType = self.typeDescriptor.returnType.recursiveTypeDescriptor()
|
||
|
returnType.generateReturnValueWrapper(methodClass, file,
|
||
|
self.typeDescriptor.userManagesMemory,
|
||
|
needsDowncast, nesting+2)
|
||
|
|
||
|
def outputMethodFooter(self, methodClass, file, nesting):
|
||
|
indent(file, nesting, 'FFIExternalObject.funcToMethod(' +self.getFinalName()+ ',' + methodClass.foreignTypeName + ",'" +self.getFinalName() +"')\n")
|
||
|
indent(file, nesting, 'del ' + self.getFinalName()+' \n')
|
||
|
indent(file, nesting+1,'\n')
|
||
|
#indent(file, nesting, methodClass.foreignTypeName +'.'+ self.getFinalName() + ' = staticmethod(' + self.getFinalName() + ')\n')
|
||
|
#indent(file, nesting,'del ' + self.getFinalName()+' \n')
|
||
|
#indent(file, nesting+1, '\n')
|
||
|
indent(file, nesting+1, '\n')
|
||
|
|
||
|
|
||
|
##################################################
|
||
|
## Static Method Code Generation
|
||
|
##################################################
|
||
|
def outputStaticHeader(self, methodClass, file, nesting):
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
indent(file, nesting, 'def ' + self.getFinalName() + '(')
|
||
|
for i in range(len(argTypes)):
|
||
|
file.write(argTypes[i].name)
|
||
|
if (i < (len(argTypes)-1)):
|
||
|
file.write(', ')
|
||
|
file.write('):\n')
|
||
|
|
||
|
|
||
|
def outputStaticBody(self, methodClass, file, nesting):
|
||
|
# The method body will look something like
|
||
|
# returnValue = panda.class_method(self.this, 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)
|
||
|
indent(file, nesting+2, 'returnValue = ' + self.typeDescriptor.moduleName + '.'
|
||
|
+ self.typeDescriptor.wrapperName + '(')
|
||
|
# Static methods do not take the this parameter
|
||
|
if (len(thislessArgTypes) > 0):
|
||
|
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()
|
||
|
returnType.generateReturnValueWrapper(methodClass, file,
|
||
|
self.typeDescriptor.userManagesMemory,
|
||
|
1, nesting+2)
|
||
|
|
||
|
def outputStaticFooter(self, methodClass, file, nesting):
|
||
|
indent(file, nesting, methodClass.foreignTypeName +'.'+ self.getFinalName() + ' = staticmethod(' + self.getFinalName() + ')\n')
|
||
|
indent(file, nesting,'del ' + self.getFinalName()+' \n')
|
||
|
indent(file, nesting+1, '\n')
|
||
|
|
||
|
##################################################
|
||
|
## Upcast Method Code Generation
|
||
|
##################################################
|
||
|
def outputInheritedMethodHeader(self, methodClass, parentList, file, nesting, needsDowncast):
|
||
|
argTypes = self.typeDescriptor.argumentTypes
|
||
|
thislessArgTypes = self.typeDescriptor.thislessArgTypes()
|
||
|
indent(file, nesting, '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, parentList, file, nesting, needsDowncast):
|
||
|
# The method body will look something like
|
||
|
# upcastSelf = self.upcastToParentClass()
|
||
|
# returnValue = libpanda.method(upcastSelf.this, 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)
|
||
|
indent(file, nesting+2, 'upcastSelf = self\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 = upcastSelf.' + methodName + '()\n')
|
||
|
else:
|
||
|
indent(file, nesting+2, '# upcastSelf = upcastSelf.' + methodName + '()\n')
|
||
|
else:
|
||
|
if methodClass.hasMethodNamed(methodName):
|
||
|
indent(file, nesting+2, 'upcastSelf = upcastSelf.' + methodName + '()\n')
|
||
|
else:
|
||
|
indent(file, nesting+2, '# upcastSelf = upcastSelf.' + methodName + '()\n')
|
||
|
|
||
|
indent(file, nesting+2, 'returnValue = ' + self.typeDescriptor.moduleName
|
||
|
+ '.' + 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(methodClass, file,
|
||
|
self.typeDescriptor.userManagesMemory,
|
||
|
needsDowncast, nesting+2)
|
||
|
|
||
|
def outputInheritedMethodFooter(self, methodClass, parentList, file, nesting, needsDowncast):
|
||
|
indent(file, nesting, 'FFIExternalObject.funcToMethod(' +self.getFinalName()+ ',' + methodClass.foreignTypeName + ",'" +self.getFinalName() +"')\n")
|
||
|
indent(file, nesting, 'del ' + self.getFinalName()+' \n')
|
||
|
indent(file, nesting+1,'\n')
|
||
|
|
||
|
|
||
|
class GlobalValueSpecification:
|
||
|
def __init__(self):
|
||
|
self.name = ''
|
||
|
# We really do not need the descriptor for the value, just
|
||
|
# the getter and setter
|
||
|
# self.typeDescriptor = None
|
||
|
# To be filled in with a GlobalFunctionSpecification
|
||
|
self.getter = None
|
||
|
# To be filled in with a GlobalFunctionSpecification
|
||
|
self.setter = None
|
||
|
|
||
|
def generateGlobalCode(self, file):
|
||
|
indent(file, 0, '# Global value: ' + self.name + '\n')
|
||
|
if self.getter:
|
||
|
self.getter.generateGlobalCode(file)
|
||
|
if self.setter:
|
||
|
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 + ' = ' + repr(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 = ''
|
||
|
self.typeDescriptor = None
|
||
|
# By default it is not the this pointer
|
||
|
self.isThis = 0
|
||
|
|
||
|
def passName(self):
|
||
|
if (self.typeDescriptor.recursiveTypeDescriptor().__class__ == \
|
||
|
FFITypes.ClassTypeDescriptor):
|
||
|
return self.name + '.this'
|
||
|
else:
|
||
|
return self.name
|