summaryrefslogtreecommitdiffstats
path: root/Tools/bgen
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1995-01-22 18:35:09 (GMT)
committerGuido van Rossum <guido@python.org>1995-01-22 18:35:09 (GMT)
commitf8de0685c91ab947abc444d43f4a91b5edd2829c (patch)
treefe1c697551de0ee97abb833e7a793a767c729251 /Tools/bgen
parent7cbf4803a93f8c4e7bf84dbdb02b390ca51e9751 (diff)
downloadcpython-f8de0685c91ab947abc444d43f4a91b5edd2829c.zip
cpython-f8de0685c91ab947abc444d43f4a91b5edd2829c.tar.gz
cpython-f8de0685c91ab947abc444d43f4a91b5edd2829c.tar.bz2
Lots of changes.
Renamed some things. Added support for methods directly to bgenGenerator.py. Completely reworked buffer, string and and structure types.
Diffstat (limited to 'Tools/bgen')
-rw-r--r--Tools/bgen/bgen/bgenGenerator.py89
-rw-r--r--Tools/bgen/bgen/bgenGeneratorGroup.py2
-rw-r--r--Tools/bgen/bgen/bgenObjectDefinition.py8
-rw-r--r--Tools/bgen/bgen/bgenType.py424
4 files changed, 376 insertions, 147 deletions
diff --git a/Tools/bgen/bgen/bgenGenerator.py b/Tools/bgen/bgen/bgenGenerator.py
index d2db9f1..62aab1c 100644
--- a/Tools/bgen/bgen/bgenGenerator.py
+++ b/Tools/bgen/bgen/bgenGenerator.py
@@ -11,20 +11,28 @@ OUT = "out"
INOUT = IN_OUT = "in-out"
-class Generator:
+class FunctionGenerator:
- # XXX There are some funny things with the argument list.
- # XXX It would be better to get rid of this and require
- # XXX each argument to be a type object or a tuple of the form
- # XXX (inoutmode, typeobject, argumentname)
- # XXX or possibly even a Variable() instance...
-
- def __init__(self, *argumentList):
- apply(self.parseArguments, argumentList)
+ def __init__(self, returntype, name, *argumentList):
+ self.returntype = returntype
+ self.name = name
+ self.argumentList = []
+ self.setreturnvar()
+ self.parseArgumentList(argumentList)
self.prefix = "XXX" # Will be changed by setprefix() call
self.objecttype = "PyObject" # Type of _self argument to function
self.itselftype = None # Type of _self->ob_itself, if defined
+ def setreturnvar(self):
+ if self.returntype:
+ self.rv = self.makereturnvar()
+ self.argumentList.append(self.rv)
+ else:
+ self.rv = None
+
+ def makereturnvar(self):
+ return Variable(self.returntype, "_rv", OutMode)
+
def setprefix(self, prefix):
self.prefix = prefix
@@ -32,32 +40,12 @@ class Generator:
self.objecttype = selftype
self.itselftype = itselftype
- def parseArguments(self, returnType, name, *argumentList):
- if returnType:
- self.rv = Variable(returnType, "_rv", OutMode)
- else:
- self.rv = None
- self.name = name
- self.argumentList = []
- if self.rv:
- self.argumentList.append(rv)
- self.parseArgumentList(argumentList)
-
def parseArgumentList(self, argumentList):
- from types import *
iarg = 0
- for arg in argumentList:
- # Arguments can either be:
- # - a type
- # - a tuple (type, [name, [mode]])
- # - a variable
+ for type, name, mode in argumentList:
iarg = iarg + 1
- if hasattr(arg, 'typeName'):
- arg = Variable(arg)
- elif type(arg) == TupleType:
- arg = apply(Variable, arg)
- if arg.name is None:
- arg.name = "_arg%d" % iarg
+ if name is None: name = "_arg%d" % iarg
+ arg = Variable(type, name, mode)
self.argumentList.append(arg)
def reference(self, name = None):
@@ -67,6 +55,7 @@ class Generator:
name, self.prefix, self.name)
def generate(self):
+ print "-->", self.name
self.functionheader()
self.declarations()
self.getargs()
@@ -84,6 +73,7 @@ class Generator:
Output("PyObject *_args;")
DedentLevel()
OutLbrace()
+ Output("PyObject *_res = NULL;")
def declarations(self):
for arg in self.argumentList:
@@ -98,7 +88,9 @@ class Generator:
continue
if arg.mode in (InMode, InOutMode):
fmt = fmt + arg.getargsFormat()
- lst = lst + sep + arg.getargsArgs()
+ args = arg.getargsArgs()
+ if args:
+ lst = lst + sep + args
Output("if (!PyArg_ParseTuple(_args, \"%s\"%s))", fmt, lst)
IndentLevel()
Output("return NULL;")
@@ -111,7 +103,11 @@ class Generator:
def callit(self):
args = ""
- sep = ",\n" + ' '*len("%s = %s(" % (self.rv.name, self.name))
+ if self.rv:
+ s = "%s = %s(" % (self.rv.name, self.name)
+ else:
+ s = "%s(" % self.name
+ sep = ",\n" + ' '*len(s)
for arg in self.argumentList:
if arg is self.rv:
continue
@@ -140,15 +136,34 @@ class Generator:
lst = lst + sep + arg.mkvalueArgs()
if fmt == "":
Output("Py_INCREF(Py_None);")
- Output("return Py_None;");
+ Output("_res = Py_None;");
else:
- Output("return Py_BuildValue(\"%s\"%s);", fmt, lst)
+ Output("_res = Py_BuildValue(\"%s\"%s);", fmt, lst)
+ tmp = self.argumentList[:]
+ tmp.reverse()
+ for arg in tmp:
+ if not arg: continue
+ if arg.flags == ErrorMode: continue
+ if arg.mode in (OutMode, InOutMode):
+ arg.mkvalueCleanup()
+ Output("return _res;")
def functiontrailer(self):
OutRbrace()
-class ManualGenerator(Generator):
+class MethodGenerator(FunctionGenerator):
+
+ def parseArgumentList(self, args):
+ a0, args = args[0], args[1:]
+ t0, n0, m0 = a0
+ if m0 != InMode:
+ raise ValueError, "method's 'self' must be 'InMode'"
+ self.itself = Variable(t0, "_self->ob_itself", SelfMode)
+ self.argumentList.append(self.itself)
+ FunctionGenerator.parseArgumentList(self, args)
+
+class ManualGenerator(FunctionGenerator):
def __init__(self, name, body):
self.name = name
diff --git a/Tools/bgen/bgen/bgenGeneratorGroup.py b/Tools/bgen/bgen/bgenGeneratorGroup.py
index 294828f..e7d617e 100644
--- a/Tools/bgen/bgen/bgenGeneratorGroup.py
+++ b/Tools/bgen/bgen/bgenGeneratorGroup.py
@@ -13,7 +13,6 @@ class GeneratorGroup:
def generate(self):
for g in self.generators:
g.generate()
- Output()
Output("static PyMethodDef %s_methods[] = {", self.prefix)
IndentLevel()
for g in self.generators:
@@ -21,6 +20,7 @@ class GeneratorGroup:
Output("{NULL, NULL, 0}")
DedentLevel()
Output("};")
+ Output()
def _test():
diff --git a/Tools/bgen/bgen/bgenObjectDefinition.py b/Tools/bgen/bgen/bgenObjectDefinition.py
index d84dffe..10a4468 100644
--- a/Tools/bgen/bgen/bgenObjectDefinition.py
+++ b/Tools/bgen/bgen/bgenObjectDefinition.py
@@ -57,18 +57,22 @@ class ObjectDefinition(GeneratorGroup):
OutHeader2("End object type " + self.name)
def outputNew(self):
- Output("static %s *%s_New(itself)", self.objecttype, self.prefix)
+ Output("static PyObject *%s_New(itself)", self.prefix)
IndentLevel()
Output("const %s %sitself;", self.itselftype, self.argref)
DedentLevel()
OutLbrace()
Output("%s *it;", self.objecttype)
+ self.outputCheckNewArg()
Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename)
Output("if (it == NULL) return NULL;")
Output("it->ob_itself = %sitself;", self.argref)
- Output("return it;")
+ Output("return (PyObject *)it;")
OutRbrace()
Output()
+
+ def outputCheckNewArg(self):
+ pass
def outputConvert(self):
Output("""\
diff --git a/Tools/bgen/bgen/bgenType.py b/Tools/bgen/bgen/bgenType.py
index a1a4ba5..6518509 100644
--- a/Tools/bgen/bgen/bgenType.py
+++ b/Tools/bgen/bgen/bgenType.py
@@ -106,16 +106,53 @@ class Type:
"""
return name
+ def mkvalueCleanup(self, name):
+ """Clean up if necessary after mkvalue().
+
+ This is normally empty; it may deallocate buffers etc.
+ """
+ pass
+
+
+# Sometimes it's useful to define a type that's only usable as input or output parameter
+
+class InputOnlyMixIn:
+
+ "Mix-in class to boobytrap passOutput"
+
+ def passOutput(self):
+ raise RuntimeError, "this type can only be used for input parameters"
+
+class InputOnlyType(InputOnlyMixIn, Type):
+
+ "Same as Type, but only usable for input parameters -- passOutput is boobytrapped"
+
+class OutputOnlyMixIn:
+
+ "Mix-in class to boobytrap passInput"
+
+ def passInput(self):
+ raise RuntimeError, "this type can only be used for output parameters"
+
+class OutputOnlyType(OutputOnlyMixIn, Type):
+
+ "Same as Type, but only usable for output parameters -- passInput is boobytrapped"
+
# A modest collection of standard C types.
void = None
+char = Type("char", "c")
short = Type("short", "h")
int = Type("int", "i")
long = Type("long", "l")
float = Type("float", "f")
double = Type("double", "d")
-stringptr = Type("char*", "s")
-char = Type("char", "c")
+
+
+# The most common use of character pointers is a null-terminated string.
+# For input, this is easy. For output, and for other uses of char *,
+# see the various Buffer types below.
+stringptr = InputOnlyType("char*", "s")
# Some Python related types.
@@ -124,20 +161,69 @@ stringobjectptr = Type("PyStringObject*", "S")
# Etc.
-# Buffers are character arrays that may contain null bytes.
-# Their length is either Fixed or Sized (i.e. given by a separate argument).
+class FakeType(InputOnlyType):
-class SizedInputBuffer:
+ """A type that is not represented in the Python version of the interface.
- "Sized input buffer -- buffer size is an input parameter"
+ Instantiate with a value to pass in the call.
+ """
- def __init__(self, size = ''):
- self.size = size
+ def __init__(self, substitute):
+ self.substitute = substitute
def declare(self, name):
- Output("char *%s;", name)
+ pass
+
+ def getargsFormat(self):
+ return ""
+
+ def getargsArgs(self, name):
+ return None
+
+ def passInput(self, name):
+ return self.substitute
+
+
+class AbstractBufferType:
+ """Buffers are character arrays that may contain null bytes.
+
+ There are a number of variants depending on:
+ - how the buffer is allocated (for output buffers), and
+ - whether and how the size is passed into and/or out of the called function.
+
+ The AbstractbufferType only serves as a placeholder for this doc string.
+ """
+
+ def declare(self, name):
+ self.declareBuffer(name)
+ self.declareSize(name)
+
+
+class FixedBufferType(AbstractBufferType):
+
+ """Fixed size buffer -- passed without size information.
+
+ Instantiate with the size as parameter.
+ THIS IS STILL AN ABSTRACT BASE CLASS -- DO NOT INSTANTIATE.
+ """
+
+ def __init__(self, size):
+ self.size = str(size)
+
+ def declareSize(self, name):
Output("int %s__len__;", name)
+
+class FixedInputBufferType(InputOnlyMixIn, FixedBufferType):
+
+ """Fixed size input buffer -- passed without size information.
+
+ Instantiate with the size as parameter.
+ """
+
+ def declareBuffer(self, name):
+ Output("char *%s;", name)
+
def getargsFormat(self):
return "s#"
@@ -145,126 +231,221 @@ class SizedInputBuffer:
return "&%s, &%s__len__" % (name, name)
def getargsCheck(self, name):
- pass
+ Output("if (%s__len__ != %s)", name, self.size)
+ OutLbrace()
+ Output('PyErr_SetString(PyExc_TypeError, "buffer length should be %s");',
+ self.size)
+ Output('return NULL;') # XXX should do a goto
+ OutRbrace()
def passInput(self, name):
- return "%s, %s__len__" % (name, name)
+ return name
-class FixedInputBuffer(SizedInputBuffer):
+class FixedOutputBufferType(OutputOnlyMixIn, FixedBufferType):
- "Fixed input buffer -- buffer size is a constant"
+ """Fixed size output buffer -- passed without size information.
- def getargsCheck(self, name):
- Output("if (%s__len__ != %s)", name, str(self.size))
- OutLbrace()
- Output('PyErr_SetString(PyExc_TypeError, "bad string length");')
- Output('return NULL;')
- OutRbrace()
+ Instantiate with the size as parameter.
+ """
- def passInput(self, name):
+ def declareBuffer(self, name):
+ Output("char %s[%s];", name, self.size)
+
+ def passOutput(self, name):
return name
+ def mkvalueFormat(self):
+ return "s#"
+
+ def mkvalueArgs(self):
+ return "%s, %s" % (name, self.size)
+
-class RecordBuffer(FixedInputBuffer):
+class StructBufferType(FixedBufferType):
- "Like fixed input buffer -- but declared as a record type pointer"
+ """Structure buffer -- passed as a structure pointer.
+
+ Instantiate with the struct type as parameter.
+ """
def __init__(self, type):
+ FixedBufferType.__init__(self, "sizeof(%s)" % type)
self.type = type
- self.size = "sizeof(%s)" % type
- def declare(self, name):
+
+class StructInputBufferType(StructBufferType, FixedInputBufferType):
+
+ """Fixed size input buffer -- passed as a pointer to a structure.
+
+ Instantiate with the struct type as parameter.
+ """
+
+ def declareBuffer(self, name):
Output("%s *%s;", self.type, name)
- Output("int %s__len__;", name)
-
-class SizedOutputBuffer:
- "Sized output buffer -- buffer size is an input-output parameter"
+class StructByValueBufferType(StructInputBufferType):
- def __init__(self, maxsize):
- self.maxsize = maxsize
+ """Fixed size input buffer -- passed as a structure BY VALUE.
+
+ Instantiate with the struct type as parameter.
+ """
+
+ def passInput(self, name):
+ return "*%s" % name
- def declare(self, name):
- Output("char %s[%s];", name, str(self.maxsize))
- Output("int %s__len__ = %s;", name, str(self.maxsize))
+
+class StructOutputBufferType(StructBufferType, FixedOutputBufferType):
+
+ """Fixed size output buffer -- passed as a pointer to a structure.
+
+ Instantiate with the struct type as parameter.
+ """
+
+ def declareBuffer(self, name):
+ Output("%s %s;", self.type, name)
def passOutput(self, name):
- return "%s, &%s__len__" % (name, name)
+ return "&%s" % name
- def errorCheck(self, name):
+ def mkvalueArgs(self, name):
+ return "(char *)&%s" % name
+
+
+class VarInputBufferType(InputOnlyMixIn, FixedInputBufferType):
+
+ """Input buffer -- passed as (buffer, size).
+
+ Instantiate without parameters.
+ """
+
+ def __init__(self):
pass
- def mkvalueFormat(self):
- return "s#"
+ def getargsCheck(self, name):
+ pass
+
+ def passInput(self, name):
+ return "%s, %s__len__" % (name, name)
+
+
+class StackOutputBufferType(OutputOnlyMixIn, FixedOutputBufferType):
+
+ """Output buffer -- passed as (buffer, size).
+
+ Instantiate with the buffer size as parameter.
+ """
+
+ def passOutput(self, name):
+ return "%s, %s" % (name, self.size)
+
+
+class VarStackOutputBufferType(StackOutputBufferType):
+
+ """Output buffer allocated on the stack -- passed as (buffer, &size).
+
+ Instantiate with the buffer size as parameter.
+ """
+
+ def declareSize(self, name):
+ Output("int %s__len__ = %s;", name, self.size)
+
+ def passOutput(self, name):
+ return "%s, &%s__len__" % (name, name)
def mkvalueArgs(self, name):
return "%s, %s__len__" % (name, name)
-class VarSizedOutputBuffer(SizedOutputBuffer):
+class VarVarStackOutputBufferType(VarStackOutputBufferType):
+
+ """Output buffer allocated on the stack -- passed as (buffer, size, &size).
+
+ Instantiate with the buffer size as parameter.
+ """
+
+ def passOutput(self, name):
+ return "%s, %s__len__, &%s__len__" % (name, name, name)
+
+
+class HeapOutputBufferType(FixedOutputBufferType):
+
+ """Output buffer allocated on the heap -- passed as (buffer, size).
+
+ Instantiate without parameters.
+ Call from Python with buffer size.
+ """
+
+ def __init__(self):
+ pass
- "Variable Sized output buffer -- buffer size is an input and an output parameter"
+ def declareBuffer(self, name):
+ Output("char *%s;", name)
def getargsFormat(self):
return "i"
-
+
def getargsArgs(self, name):
return "&%s__len__" % name
-
+
def getargsCheck(self, name):
- pass
+ Output("if ((%s = malloc(%s__len__)) == NULL) goto %s__error__;",
+ name, name, name)
def passOutput(self, name):
- return "%s, %s__len__, &%s__len__" % (name, name, name)
-
+ return "%s, %s__len__" % (name, name)
-class FixedOutputBuffer:
+ def mkvalueArgs(self, name):
+ return "%s, %s__len__" % (name, name)
- "Fixed output buffer -- buffer size is a constant"
+ def mkvalueCleanup(self, name):
+ Output("free(%s);", name)
+ DedentLevel()
+ Output(" %s__error__: ;", name);
+ IndentLevel()
- def __init__(self, size):
- self.size = size
- def declare(self, name):
- Output("char %s[%s];", name, str(self.size))
+class VarHeapOutputBufferType(HeapOutputBufferType):
- def passOutput(self, name):
- return name
+ """Output buffer allocated on the heap -- passed as (buffer, &size).
- def errorCheck(self, name):
- pass
+ Instantiate without parameters.
+ Call from Python with buffer size.
+ """
- def mkvalueFormat(self):
- return "s#"
+ def passOutput(self, name):
+ return "%s, &%s__len__" % (name, name)
- def mkvalueArgs(self, name):
- return "%s, %s" % (name, str(self.size))
+class VarVarHeapOutputBufferType(VarHeapOutputBufferType):
-# Strings are character arrays terminated by a null byte.
-# For input, this is covered by stringptr.
-# For output, there are again two variants: Fixed (size is a constant
-# given in the documentation) or Sized (size is given by a variable).
-# (Note that this doesn't cover output parameters in which a string
-# pointer is returned.)
+ """Output buffer allocated on the heap -- passed as (buffer, size, &size).
-class SizedOutputString:
+ Instantiate without parameters.
+ Call from Python with buffer size.
+ """
- "Null-terminated output string -- buffer size is an input parameter"
+ def passOutput(self, name):
+ return "%s, %s__len__, &%s__len__" % (name, name, name)
- def __init__(self, bufsize):
- self.bufsize = bufsize
- def declare(self, name):
- Output("char %s[%s];", name, str(self.bufsize))
+class StringBufferType:
- def passOutput(self, name):
- return "%s, %s" % (name, str(self.bufsize))
+ """Mix-in class to create various string buffer types.
- def errorCheck(self, name):
- pass
+ Strings are character arrays terminated by a null byte.
+ For input, this is already covered by stringptr.
+ For output, there are again three variants:
+ - Fixed (size is a constant given in the documentation),
+ - Stack (size is passed to the C function but we decide on a size at
+ code generation time so we can still allocate on the heap), or
+ - Heap (size is passed to the C function and we let the Python caller
+ pass a size.
+ (Note that this doesn't cover output parameters in which a string
+ pointer is returned. These are actually easier (no allocation) but far
+ less common. I'll write the classes when there is demand.)
+ """
def mkvalueFormat(self):
return "s"
@@ -273,61 +454,86 @@ class SizedOutputString:
return name
-class FixedOutputString(SizedOutputString):
+class FixedOutputStringType(StringBufferType, FixedOutputBufferType):
- "Null-terminated output string -- buffer size is a constant"
+ """Null-terminated output string -- passed without size.
- def passOutput(self, name):
- return name
+ Instantiate with buffer size as parameter.
+ """
-class StructureByValue:
+class StackOutputStringType(StringBufferType, StackOutputBufferType):
- "Structure passed by value -- mapped to a Python string (for now)"
+ """Null-terminated output string -- passed as (buffer, size).
- def __init__(self, typeName):
- self.typeName = typeName
+ Instantiate with buffer size as parameter.
+ """
- def declare(self, name):
- n = len(self.typeName)
- Output("%-*s %s;", n, self.typeName, name)
- Output("%-*s*%s__str__;", n, "char", name)
- Output("%-*s %s__len__;", n, "int", name)
+class HeapOutputStringType(StringBufferType, HeapOutputBufferType):
+
+ """Null-terminated output string -- passed as (buffer, size).
+
+ Instantiate without parameters.
+ Call from Python with buffer size.
+ """
+
+
+class OpaqueType(Type):
+
+ """A type represented by an opaque object type, always passed by address.
+
+ Instantiate with the type name, and optional an object type name whose
+ New/Convert functions will be used.
+ """
+
+ def __init__(self, name, sameAs = None):
+ self.typeName = name
+ self.sameAs = sameAs or name
def getargsFormat(self):
- return "s#"
+ return 'O&'
def getargsArgs(self, name):
- return "&%s__str__, &%s__len__" % (name, name)
-
- def getargsCheck(self, name):
- Output("if (%s__len__ != sizeof %s)", name, name)
- IndentLevel()
- Output('PyErr_SetString(PyExc_TypeError, "bad structure length");')
- DedentLevel()
- Output("memcpy(&%s, %s__str__, %s__len__);",
- name, name, name)
+ return "%s_Convert, &%s" % (self.sameAs, name)
def passInput(self, name):
- return "%s" % name
-
- def passOutput(self, name):
return "&%s" % name
- def errorCheck(self, name):
- pass
-
def mkvalueFormat(self):
- return "s#"
+ return 'O&'
def mkvalueArgs(self, name):
- return "(char *)&%s, (int)sizeof %s" % (name, name)
+ return "%s_New, &%s" % (self.sameAs, name)
+
+
+class OpaqueByValueType(OpaqueType):
+ """A type represented by an opaque object type, on input passed BY VALUE.
-class StructureByAddress(StructureByValue):
+ Instantiate with the type name, and optional an object type name whose
+ New/Convert functions will be used.
+ """
def passInput(self, name):
- return "&%s" % name
+ return name
+
+ def mkvalueArgs(self, name):
+ return "%s_New, %s" % (self.sameAs, name)
+
+
+class OpaqueArrayType(OpaqueByValueType):
+
+ """A type represented by an opaque object type, with ARRAY passing semantics.
+
+ Instantiate with the type name, and optional an object type name whose
+ New/Convert functions will be used.
+ """
+
+ def getargsArgs(self, name):
+ return "%s_Convert, &%s" % (self.sameAs, name)
+
+ def passOutput(self, name):
+ return name
class Variable:
@@ -397,3 +603,7 @@ class Variable:
def mkvalueArgs(self):
"""Call the type's mkvalueArgs method."""
return self.type.mkvalueArgs(self.name)
+
+ def mkvalueCleanup(self):
+ """Call the type's mkvalueCleanup method."""
+ return self.type.mkvalueCleanup(self.name)