mirror of
https://github.com/python/cpython.git
synced 2024-11-26 19:34:19 +08:00
initial version
This commit is contained in:
parent
84fa5ecfff
commit
8cfc4bfb9d
7
Tools/bgen/bgen/bgen.py
Normal file
7
Tools/bgen/bgen/bgen.py
Normal file
@ -0,0 +1,7 @@
|
||||
"Export everything in the various bgen submodules."
|
||||
|
||||
from bgenType import *
|
||||
from bgenOutput import *
|
||||
from bgenGenerator import *
|
||||
from bgenModule import *
|
||||
from bgenObjectDefinition import *
|
173
Tools/bgen/bgen/bgenGenerator.py
Normal file
173
Tools/bgen/bgen/bgenGenerator.py
Normal file
@ -0,0 +1,173 @@
|
||||
from bgenOutput import *
|
||||
from bgenType import *
|
||||
|
||||
|
||||
Error = "bgenGenerator.Error"
|
||||
|
||||
|
||||
# Strings to specify argument transfer modes in generator calls
|
||||
IN = "in"
|
||||
OUT = "out"
|
||||
INOUT = IN_OUT = "in-out"
|
||||
|
||||
|
||||
class Generator:
|
||||
|
||||
# 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)
|
||||
self.prefix = "XXX" # Will be changed by setprefix() call
|
||||
self.objecttype = "object" # Type of _self argument to function
|
||||
self.itselftype = None # Type of _self->ob_itself, if defined
|
||||
|
||||
def setprefix(self, prefix):
|
||||
self.prefix = prefix
|
||||
|
||||
def setselftype(self, selftype, itselftype):
|
||||
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
|
||||
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
|
||||
self.argumentList.append(arg)
|
||||
|
||||
def reference(self, name = None):
|
||||
if name is None:
|
||||
name = self.name
|
||||
Output("{\"%s\", (PyCFunction)%s_%s, 1},",
|
||||
name, self.prefix, self.name)
|
||||
|
||||
def generate(self):
|
||||
self.functionheader()
|
||||
self.declarations()
|
||||
self.getargs()
|
||||
self.callit()
|
||||
self.checkit()
|
||||
self.returnvalue()
|
||||
self.functiontrailer()
|
||||
|
||||
def functionheader(self):
|
||||
Output()
|
||||
Output("static PyObject *%s_%s(_self, _args)",
|
||||
self.prefix, self.name)
|
||||
IndentLevel()
|
||||
Output("%s *_self;", self.objecttype)
|
||||
Output("PyObject *_args;")
|
||||
DedentLevel()
|
||||
OutLbrace()
|
||||
|
||||
def declarations(self):
|
||||
for arg in self.argumentList:
|
||||
arg.declare()
|
||||
|
||||
def getargs(self):
|
||||
fmt = ""
|
||||
lst = ""
|
||||
for arg in self.argumentList:
|
||||
if arg.flags == SelfMode:
|
||||
continue
|
||||
if arg.mode in (InMode, InOutMode):
|
||||
fmt = fmt + arg.getargsFormat()
|
||||
lst = lst + ", " + arg.getargsArgs()
|
||||
Output("if (!PyArg_ParseTuple(_args, \"%s\"%s))", fmt, lst)
|
||||
IndentLevel()
|
||||
Output("return NULL;")
|
||||
DedentLevel()
|
||||
for arg in self.argumentList:
|
||||
if arg.flags == SelfMode:
|
||||
continue
|
||||
if arg.mode in (InMode, InOutMode):
|
||||
arg.getargsCheck()
|
||||
|
||||
def callit(self):
|
||||
args = ""
|
||||
for arg in self.argumentList:
|
||||
if arg is self.rv:
|
||||
continue
|
||||
s = arg.passArgument()
|
||||
if args: s = ", " + s
|
||||
args = args + s
|
||||
if self.rv:
|
||||
Output("%s = %s(%s);",
|
||||
self.rv.name, self.name, args)
|
||||
else:
|
||||
Output("%s(%s);", self.name, args)
|
||||
|
||||
def checkit(self):
|
||||
for arg in self.argumentList:
|
||||
arg.errorCheck()
|
||||
|
||||
def returnvalue(self):
|
||||
fmt = ""
|
||||
lst = ""
|
||||
for arg in self.argumentList:
|
||||
if not arg: continue
|
||||
if arg.flags == ErrorMode: continue
|
||||
if arg.mode in (OutMode, InOutMode):
|
||||
fmt = fmt + arg.mkvalueFormat()
|
||||
lst = lst + ", " + arg.mkvalueArgs()
|
||||
if fmt == "":
|
||||
Output("Py_INCREF(Py_None);")
|
||||
Output("return Py_None;");
|
||||
else:
|
||||
Output("return Py_BuildValue(\"%s\"%s);", fmt, lst)
|
||||
|
||||
def functiontrailer(self):
|
||||
OutRbrace()
|
||||
|
||||
|
||||
class ManualGenerator(Generator):
|
||||
|
||||
def __init__(self, name, body):
|
||||
self.name = name
|
||||
self.body = body
|
||||
|
||||
def definition(self):
|
||||
self.functionheader()
|
||||
Output("%s", self.body)
|
||||
self.functiontrailer()
|
||||
|
||||
|
||||
def _test():
|
||||
void = None
|
||||
eggs = Generator(void, "eggs",
|
||||
Variable(stringptr, 'cmd'),
|
||||
Variable(int, 'x'),
|
||||
Variable(double, 'y', InOutMode),
|
||||
Variable(int, 'status', ErrorMode),
|
||||
)
|
||||
eggs.setprefix("spam")
|
||||
print "/* START */"
|
||||
eggs.generate()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
35
Tools/bgen/bgen/bgenGeneratorGroup.py
Normal file
35
Tools/bgen/bgen/bgenGeneratorGroup.py
Normal file
@ -0,0 +1,35 @@
|
||||
from bgenOutput import *
|
||||
|
||||
class GeneratorGroup:
|
||||
|
||||
def __init__(self, prefix):
|
||||
self.prefix = prefix
|
||||
self.generators = []
|
||||
|
||||
def add(self, g):
|
||||
g.setprefix(self.prefix)
|
||||
self.generators.append(g)
|
||||
|
||||
def generate(self):
|
||||
for g in self.generators:
|
||||
g.generate()
|
||||
Output()
|
||||
Output("static struct methodlist %s_methods[] = {", self.prefix)
|
||||
IndentLevel()
|
||||
for g in self.generators:
|
||||
g.reference()
|
||||
Output("{NULL, NULL, 0}")
|
||||
DedentLevel()
|
||||
Output("};")
|
||||
|
||||
|
||||
def _test():
|
||||
from bgenGenerator import Generator
|
||||
group = GeneratorGroup("spam")
|
||||
eggs = Generator(void, "eggs")
|
||||
group.add(eggs)
|
||||
print "/* START */"
|
||||
group.generate()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
69
Tools/bgen/bgen/bgenModule.py
Normal file
69
Tools/bgen/bgen/bgenModule.py
Normal file
@ -0,0 +1,69 @@
|
||||
from bgenOutput import *
|
||||
from bgenGeneratorGroup import GeneratorGroup
|
||||
|
||||
class Module(GeneratorGroup):
|
||||
|
||||
def __init__(self, name, prefix = None,
|
||||
includestuff = None,
|
||||
initstuff = None):
|
||||
GeneratorGroup.__init__(self, prefix or name)
|
||||
self.name = name
|
||||
self.includestuff = includestuff
|
||||
self.initstuff = initstuff
|
||||
|
||||
def addobject(self, od):
|
||||
self.generators.append(od)
|
||||
|
||||
def generate(self):
|
||||
OutHeader1("Module " + self.name)
|
||||
Output("#include <Python.h>")
|
||||
Output()
|
||||
|
||||
if self.includestuff:
|
||||
Output()
|
||||
Output("%s", self.includestuff)
|
||||
|
||||
self.declareModuleVariables()
|
||||
|
||||
GeneratorGroup.generate(self)
|
||||
|
||||
Output()
|
||||
Output("void init%s()", self.name)
|
||||
OutLbrace()
|
||||
Output("object *m;")
|
||||
Output("object *d;")
|
||||
Output()
|
||||
|
||||
if self.initstuff:
|
||||
Output("%s", self.initstuff)
|
||||
Output()
|
||||
|
||||
Output("m = initmodule(\"%s\", %s_methods);",
|
||||
self.name, self.prefix)
|
||||
Output("d = getmoduledict(m);")
|
||||
self.createModuleVariables()
|
||||
OutRbrace()
|
||||
OutHeader1("End module " + self.name)
|
||||
|
||||
def declareModuleVariables(self):
|
||||
self.errorname = self.prefix + "_Error"
|
||||
Output("static object *%s;", self.errorname)
|
||||
|
||||
def createModuleVariables(self):
|
||||
Output("""if ((%s = newstringobject("%s.Error")) == NULL ||""",
|
||||
self.errorname, self.name)
|
||||
Output(""" dictinsert(d, "Error", %s) != 0)""",
|
||||
self.errorname)
|
||||
Output("""\tfatal("can't initialize %s.Error");""",
|
||||
self.name)
|
||||
|
||||
|
||||
def _test():
|
||||
from bgenGenerator import Generator
|
||||
m = Module("spam", "", "#include <stdio.h>")
|
||||
g = Generator(None, "bacon")
|
||||
m.add(g)
|
||||
m.generate()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
130
Tools/bgen/bgen/bgenObjectDefinition.py
Normal file
130
Tools/bgen/bgen/bgenObjectDefinition.py
Normal file
@ -0,0 +1,130 @@
|
||||
from bgenOutput import *
|
||||
from bgenGeneratorGroup import GeneratorGroup
|
||||
|
||||
class ObjectDefinition(GeneratorGroup):
|
||||
|
||||
def __init__(self, name, prefix, itselftype):
|
||||
import string
|
||||
GeneratorGroup.__init__(self, prefix or name)
|
||||
self.name = name
|
||||
self.itselftype = itselftype
|
||||
self.objecttype = name + 'Object'
|
||||
self.typename = self.prefix + '_' + \
|
||||
string.upper(name[:1]) + \
|
||||
string.lower(name[1:]) + '_Type'
|
||||
|
||||
def add(self, g):
|
||||
g.setselftype(self.objecttype, self.itselftype)
|
||||
GeneratorGroup.add(self, g)
|
||||
|
||||
def reference(self):
|
||||
# In case we are referenced from a module
|
||||
pass
|
||||
|
||||
def generate(self):
|
||||
# XXX This should use long strings and %(varname)s substitution!
|
||||
|
||||
OutHeader2("Object type " + self.name)
|
||||
|
||||
Output("staticforward PyTypeObject %s;", self.typename)
|
||||
Output()
|
||||
|
||||
Output("#define is_%sobject(x) ((x)->ob_type == %s)",
|
||||
self.name, self.typename)
|
||||
Output()
|
||||
|
||||
Output("typedef struct {")
|
||||
IndentLevel()
|
||||
Output("OB_HEAD")
|
||||
Output("%s ob_itself;", self.itselftype)
|
||||
DedentLevel()
|
||||
Output("} %s;", self.objecttype)
|
||||
Output()
|
||||
|
||||
Output("static %s *new%s(itself)", self.objecttype, self.objecttype)
|
||||
IndentLevel()
|
||||
Output("%s itself;", self.itselftype)
|
||||
DedentLevel()
|
||||
OutLbrace()
|
||||
Output("%s *it;", self.objecttype)
|
||||
Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename)
|
||||
Output("if (it == NULL) return NULL;")
|
||||
Output("it->ob_itself = itself;")
|
||||
Output("return it;")
|
||||
OutRbrace()
|
||||
Output()
|
||||
|
||||
Output("static void %s_dealloc(self)", self.prefix)
|
||||
IndentLevel()
|
||||
Output("%s *self;", self.objecttype)
|
||||
DedentLevel()
|
||||
OutLbrace()
|
||||
## Output("if (self->ob_itself != NULL)")
|
||||
## OutLbrace()
|
||||
## self.outputFreeIt("self->ob_itself")
|
||||
## OutRbrace()
|
||||
Output("DEL(self);")
|
||||
OutRbrace()
|
||||
Output()
|
||||
|
||||
## Output("static int %s_converter(p_itself, p_it)", self.prefix)
|
||||
## IndentLevel()
|
||||
## Output("%s *p_itself;", self.itselftype)
|
||||
## Output("%s **p_it;", self.objecttype)
|
||||
## DedentLevel()
|
||||
## OutLbrace()
|
||||
## Output("if (**p_it == NULL)")
|
||||
## OutLbrace()
|
||||
## Output("*p_it = new%s(*p_itself);", self.objecttype)
|
||||
## OutRbrace()
|
||||
## Output("else")
|
||||
## OutLbrace()
|
||||
## Output("*p_itself = (*p_it)->ob_itself;")
|
||||
## OutRbrace()
|
||||
## Output("return 1;")
|
||||
## OutRbrace()
|
||||
## Output()
|
||||
|
||||
GeneratorGroup.generate(self)
|
||||
|
||||
self.outputGetattr()
|
||||
|
||||
self.outputSetattr()
|
||||
|
||||
Output("static PyTypeObject %s = {", self.typename)
|
||||
IndentLevel()
|
||||
Output("PyObject_HEAD_INIT(&PyType_Type)")
|
||||
Output("0, /*ob_size*/")
|
||||
Output("\"%s\", /*tp_name*/", self.name)
|
||||
Output("sizeof(%s), /*tp_basicsize*/", self.objecttype)
|
||||
Output("0, /*tp_itemsize*/")
|
||||
Output("/* methods */")
|
||||
Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix)
|
||||
Output("0, /*tp_print*/")
|
||||
Output("(getattrfunc) %s_getattr, /*tp_getattr*/", self.prefix)
|
||||
Output("(setattrfunc) %s_setattr, /*tp_setattr*/", self.prefix)
|
||||
DedentLevel()
|
||||
Output("};")
|
||||
|
||||
OutHeader2("End object type " + self.name)
|
||||
|
||||
def outputFreeIt(self, name):
|
||||
Output("DEL(%s); /* XXX */", name)
|
||||
|
||||
def outputGetattr(self):
|
||||
Output("static PyObject *%s_getattr(self, name)", self.prefix)
|
||||
IndentLevel()
|
||||
Output("%s *self;", self.objecttype)
|
||||
Output("char *name;")
|
||||
DedentLevel()
|
||||
OutLbrace()
|
||||
self.outputGetattrBody()
|
||||
OutRbrace()
|
||||
Output()
|
||||
|
||||
def outputGetattrBody(self):
|
||||
Output("return findmethod(self, %s_methods, name);", self.prefix)
|
||||
|
||||
def outputSetattr(self):
|
||||
Output("#define %s_setattr NULL", self.prefix)
|
||||
Output()
|
129
Tools/bgen/bgen/bgenOutput.py
Normal file
129
Tools/bgen/bgen/bgenOutput.py
Normal file
@ -0,0 +1,129 @@
|
||||
"""Output primitives for the binding generator classes.
|
||||
|
||||
This should really be a class, but then everybody would be passing
|
||||
the output object to each other. I chose for the simpler approach
|
||||
of a module with a global variable. Use SetOutputFile() to change
|
||||
the output file.
|
||||
"""
|
||||
|
||||
def SetOutputFile(file = None):
|
||||
"""Call this with an open file object to make that the output file.
|
||||
|
||||
Call it without arguments to reset the output file to sys.stdout.
|
||||
"""
|
||||
global _File
|
||||
if file is None:
|
||||
import sys
|
||||
file = sys.stdout
|
||||
_File = file
|
||||
|
||||
SetOutputFile() # Initialize _File
|
||||
|
||||
_Level = 0 # Indentation level
|
||||
|
||||
def GetLevel():
|
||||
""""Return the current indentation level."""
|
||||
return _Level
|
||||
|
||||
def SetLevel(level):
|
||||
"""Set the current indentation level.
|
||||
|
||||
This does no type or range checking -- use at own risk.
|
||||
"""
|
||||
global _Level
|
||||
_Level = level
|
||||
|
||||
def Output(format = "", *args):
|
||||
"""Call this with a format string and arguments for the format.
|
||||
|
||||
A newline is always added. Each line in the output is indented
|
||||
to the proper indentation level -- even if the result of the
|
||||
format expansion contains embedded newlines. Exception: lines
|
||||
beginning with '#' are not indented -- these are assumed to be
|
||||
C preprprocessor lines.
|
||||
"""
|
||||
text = format % args
|
||||
if _Level > 0:
|
||||
indent = '\t' * _Level
|
||||
import string
|
||||
lines = string.splitfields(text, '\n')
|
||||
for i in range(len(lines)):
|
||||
if lines[i] and lines[i][0] != '#':
|
||||
lines[i] = indent + lines[i]
|
||||
text = string.joinfields(lines, '\n')
|
||||
_File.write(text + '\n')
|
||||
|
||||
def IndentLevel(by = 1):
|
||||
"""Increment the indentation level by one.
|
||||
|
||||
When called with an argument, adds it to the indentation level.
|
||||
"""
|
||||
global _Level
|
||||
if _Level+by < 0:
|
||||
raise Error, "indentation underflow (internal error)"
|
||||
_Level = _Level + by
|
||||
|
||||
def DedentLevel(by = 1):
|
||||
"""Decfrement the indentation level by one.
|
||||
|
||||
When called with an argument, subtracts it from the indentation level.
|
||||
"""
|
||||
IndentLevel(-by)
|
||||
|
||||
def OutLbrace():
|
||||
"""Output a '{' on a line by itself and increase the indentation level."""
|
||||
Output("{")
|
||||
IndentLevel()
|
||||
|
||||
def OutRbrace():
|
||||
"""Decrease the indentation level and output a '}' on a line by itself."""
|
||||
DedentLevel()
|
||||
Output("}")
|
||||
|
||||
def OutHeader(text, dash):
|
||||
"""Output a header comment using a given dash character."""
|
||||
n = 64 - len(text)
|
||||
Output()
|
||||
Output("/* %s %s %s */", dash * (n/2), text, dash * (n - n/2))
|
||||
Output()
|
||||
|
||||
def OutHeader1(text):
|
||||
"""Output a level 1 header comment (uses '=' dashes)."""
|
||||
OutHeader(text, "=")
|
||||
|
||||
def OutHeader2(text):
|
||||
"""Output a level 2 header comment (uses '-' dashes)."""
|
||||
OutHeader(text, "-")
|
||||
|
||||
|
||||
def _test():
|
||||
"""Test program. Run when the module is run as a script."""
|
||||
OutHeader1("test bgenOutput")
|
||||
Output("""
|
||||
#include <Python.h>
|
||||
#include <stdio.h>
|
||||
""")
|
||||
Output("main(argc, argv)")
|
||||
IndentLevel()
|
||||
Output("int argc;")
|
||||
Output("char **argv;")
|
||||
DedentLevel()
|
||||
OutLbrace()
|
||||
Output("int i;")
|
||||
Output()
|
||||
Output("""\
|
||||
/* Here are a few comment lines.
|
||||
Just to test indenting multiple lines.
|
||||
|
||||
End of the comment lines. */
|
||||
""")
|
||||
Output("for (i = 0; i < argc; i++)")
|
||||
OutLbrace()
|
||||
Output('printf("argv[%%d] = %%s\\n", i, argv[i]);')
|
||||
OutRbrace()
|
||||
Output("exit(0)")
|
||||
OutRbrace()
|
||||
OutHeader2("end test")
|
||||
|
||||
if __name__ == '__main__':
|
||||
_test()
|
362
Tools/bgen/bgen/bgenType.py
Normal file
362
Tools/bgen/bgen/bgenType.py
Normal file
@ -0,0 +1,362 @@
|
||||
"""Type and Variable classes and a modest collection of standard types."""
|
||||
|
||||
from bgenOutput import *
|
||||
|
||||
|
||||
# Values to represent argument transfer modes
|
||||
InMode = 1 # input-only argument
|
||||
OutMode = 2 # output-only argument
|
||||
InOutMode = 3 # input-output argument
|
||||
ModeMask = 3 # bits to keep for mode
|
||||
|
||||
|
||||
# Special cases for mode/flags argument
|
||||
# XXX This is still a mess!
|
||||
SelfMode = 4+InMode # this is 'self' -- don't declare it
|
||||
ReturnMode = 8+OutMode # this is the function return value
|
||||
ErrorMode = 16+OutMode # this is an error status -- turn it into an exception
|
||||
|
||||
|
||||
class Type:
|
||||
|
||||
"""Define the various things you can do with a C type.
|
||||
|
||||
Most methods are intended to be extended or overridden.
|
||||
"""
|
||||
|
||||
def __init__(self, typeName, fmt):
|
||||
"""Call with the C name and getargs format for the type.
|
||||
|
||||
Example: int = Type("int", "i")
|
||||
"""
|
||||
self.typeName = typeName
|
||||
self.fmt = fmt
|
||||
|
||||
def declare(self, name):
|
||||
"""Declare a variable of the type with a given name.
|
||||
|
||||
Example: int.declare('spam') prints "int spam;"
|
||||
"""
|
||||
Output("%s %s;", self.typeName, name)
|
||||
|
||||
def getargsFormat(self):
|
||||
"""Return the format for this type for use with [new]getargs().
|
||||
|
||||
Example: int.getargsFormat() returns the string "i".
|
||||
"""
|
||||
return self.fmt
|
||||
|
||||
def getargsArgs(self, name):
|
||||
"""Return an argument for use with [new]getargs().
|
||||
|
||||
Example: int.getargsArgs("spam") returns the string "&spam".
|
||||
"""
|
||||
return "&" + name
|
||||
|
||||
def getargsCheck(self, name):
|
||||
"""Perform any needed post-[new]getargs() checks.
|
||||
|
||||
This is type-dependent; the default does not check for errors.
|
||||
An example would be a check for a maximum string length."""
|
||||
|
||||
def passInput(self, name):
|
||||
"""Return an argument for passing a variable into a call.
|
||||
|
||||
Example: int.passInput("spam") returns the string "spam".
|
||||
"""
|
||||
return name
|
||||
|
||||
def passOutput(self, name):
|
||||
"""Return an argument for returning a variable out of a call.
|
||||
|
||||
Example: int.passOutput("spam") returns the string "&spam".
|
||||
"""
|
||||
return "&" + name
|
||||
|
||||
def errorCheck(self, name):
|
||||
"""Check for an error returned in the variable.
|
||||
|
||||
This is type-dependent; the default does not check for errors.
|
||||
An example would be a check for a NULL pointer.
|
||||
If an error is found, the generated routine should
|
||||
raise an exception and return NULL.
|
||||
|
||||
XXX There should be a way to add error clean-up code.
|
||||
"""
|
||||
Output("/* XXX no err check for %s %s */", self.typeName, name)
|
||||
|
||||
def mkvalueFormat(self):
|
||||
"""Return the format for this type for use with mkvalue().
|
||||
|
||||
This is normally the same as getargsFormat() but it is
|
||||
a separate function to allow future divergence.
|
||||
"""
|
||||
return self.getargsFormat()
|
||||
|
||||
def mkvalueArgs(self, name):
|
||||
"""Return an argument for use with mkvalue().
|
||||
|
||||
Example: int.mkvalueArgs("spam") returns the string "spam".
|
||||
"""
|
||||
return name
|
||||
|
||||
|
||||
# A modest collection of standard C types.
|
||||
void = None
|
||||
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")
|
||||
|
||||
|
||||
# Some Python related types.
|
||||
objectptr = Type("object*", "O")
|
||||
stringobjectptr = Type("stringobject*", "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 SizedInputBuffer:
|
||||
|
||||
"Sized input buffer -- buffer size is an input parameter"
|
||||
|
||||
def __init__(self, size):
|
||||
self.size = size
|
||||
|
||||
def declare(self, name):
|
||||
Output("char *%s;", name)
|
||||
Output("int %s__len__;", name)
|
||||
|
||||
def getargsFormat(self):
|
||||
return "s#"
|
||||
|
||||
def getargsArgs(self, name):
|
||||
return "%s, %s__len__" % (name, name)
|
||||
|
||||
def getargsCheck(self, name):
|
||||
pass
|
||||
|
||||
def passInput(self, name):
|
||||
return "%s, %s__len__" % (name, name)
|
||||
|
||||
|
||||
class FixedInputBuffer(SizedInputBuffer):
|
||||
|
||||
"Fixed input buffer -- buffer size is a constant"
|
||||
|
||||
def getargsCheck(self, name):
|
||||
Output("if (%s__len__ != %s)", name, str(self.size))
|
||||
IndentLevel()
|
||||
Output('err_setstr(TypeError, "bad string length");')
|
||||
DedentLevel()
|
||||
|
||||
def passInput(self, name):
|
||||
return name
|
||||
|
||||
|
||||
class SizedOutputBuffer:
|
||||
|
||||
"Sized output buffer -- buffer size is an input-output parameter"
|
||||
|
||||
def __init__(self, maxsize):
|
||||
self.maxsize = maxsize
|
||||
|
||||
def declare(self, name):
|
||||
Output("char %s[%s];", name, str(self.maxsize))
|
||||
Output("int %s__len__ = %s;", name, str(self.maxsize))
|
||||
|
||||
def passOutput(self, name):
|
||||
return "%s, &%s__len__" % (name, name)
|
||||
|
||||
def errorCheck(self, name):
|
||||
pass
|
||||
|
||||
def mkvalueFormat(self):
|
||||
return "s#"
|
||||
|
||||
def mkvalueArgs(self, name):
|
||||
return "%s, %s__len__" % (name, name)
|
||||
|
||||
|
||||
class FixedOutputBuffer:
|
||||
|
||||
"Fixed output buffer -- buffer size is a constant"
|
||||
|
||||
def __init__(self, size):
|
||||
self.size = size
|
||||
|
||||
def declare(self, name):
|
||||
Output("char %s[%s];", name, str(self.size))
|
||||
|
||||
def passOutput(self, name):
|
||||
return name
|
||||
|
||||
def errorCheck(self, name):
|
||||
pass
|
||||
|
||||
def mkvalueFormat(self):
|
||||
return "s#"
|
||||
|
||||
def mkvalueArgs(self, name):
|
||||
return "%s, %s" % (name, str(self.size))
|
||||
|
||||
|
||||
# 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.)
|
||||
|
||||
class SizedOutputString:
|
||||
|
||||
"Null-terminated output string -- buffer size is an input parameter"
|
||||
|
||||
def __init__(self, bufsize):
|
||||
self.bufsize = bufsize
|
||||
|
||||
def declare(self, name):
|
||||
Output("char %s[%s];", name, str(self.bufsize))
|
||||
|
||||
def passOutput(self, name):
|
||||
return "%s, %s" % (name, str(self.bufsize))
|
||||
|
||||
def errorCheck(self, name):
|
||||
pass
|
||||
|
||||
def mkvalueFormat(self):
|
||||
return "s"
|
||||
|
||||
def mkvalueArgs(self, name):
|
||||
return name
|
||||
|
||||
|
||||
class FixedOutputString(SizedOutputString):
|
||||
|
||||
"Null-terminated output string -- buffer size is a constant"
|
||||
|
||||
def passOutput(self, name):
|
||||
return name
|
||||
|
||||
|
||||
class StructureByValue:
|
||||
|
||||
"Structure passed by value -- mapped to a Python string (for now)"
|
||||
|
||||
def __init__(self, typeName):
|
||||
self.typeName = typeName
|
||||
|
||||
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)
|
||||
|
||||
def getargsFormat(self):
|
||||
return "s#"
|
||||
|
||||
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('err_setstr(TypeError, "bad structure length");')
|
||||
DedentLevel()
|
||||
Output("memcpy(&%s, %s__str__, %s__len__);",
|
||||
name, name, 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#"
|
||||
|
||||
def mkvalueArgs(self, name):
|
||||
return "(char *)&%s, (int)sizeof %s" % (name, name)
|
||||
|
||||
|
||||
class StructureByAddress(StructureByValue):
|
||||
|
||||
def passInput(self, name):
|
||||
return "&%s" % name
|
||||
|
||||
|
||||
class Variable:
|
||||
|
||||
"""A Variable holds a type, a name, a transfer mode and flags.
|
||||
|
||||
Most of its methods call the correponding type method with the
|
||||
variable name.
|
||||
"""
|
||||
|
||||
def __init__(self, type, name = None, flags = InMode):
|
||||
"""Call with a type, a name and flags.
|
||||
|
||||
If name is None, it muse be set later.
|
||||
flags defaults to InMode.
|
||||
"""
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.flags = flags
|
||||
self.mode = flags & ModeMask
|
||||
|
||||
def declare(self):
|
||||
"""Declare the variable if necessary.
|
||||
|
||||
If it is "self", it is not declared.
|
||||
"""
|
||||
if self.flags != SelfMode:
|
||||
self.type.declare(self.name)
|
||||
|
||||
def getargsFormat(self):
|
||||
"""Call the type's getargsFormatmethod."""
|
||||
return self.type.getargsFormat()
|
||||
|
||||
def getargsArgs(self):
|
||||
"""Call the type's getargsArgsmethod."""
|
||||
return self.type.getargsArgs(self.name)
|
||||
|
||||
def getargsCheck(self):
|
||||
return self.type.getargsCheck(self.name)
|
||||
|
||||
def passArgument(self):
|
||||
"""Return the string required to pass the variable as argument.
|
||||
|
||||
For "in" arguments, return the variable name.
|
||||
For "out" and "in out" arguments,
|
||||
return its name prefixed with "&".
|
||||
"""
|
||||
if self.mode == InMode:
|
||||
return self.type.passInput(self.name)
|
||||
if self.mode in (OutMode, InOutMode):
|
||||
return self.type.passOutput(self.name)
|
||||
# XXX Shouldn't get here
|
||||
return "/*mode?*/" + self.type.passInput(self.name)
|
||||
|
||||
def errorCheck(self):
|
||||
"""Check for an error if necessary.
|
||||
|
||||
This only generates code if the variable's mode is ErrorMode.
|
||||
"""
|
||||
if self.flags == ErrorMode:
|
||||
self.type.errorCheck(self.name)
|
||||
|
||||
def mkvalueFormat (self):
|
||||
"""Call the type's mkvalueFormatmethod."""
|
||||
return self.type.mkvalueFormat()
|
||||
|
||||
def mkvalueArgs(self):
|
||||
"""Call the type's mkvalueArgs method."""
|
||||
return self.type.mkvalueArgs(self.name)
|
Loading…
Reference in New Issue
Block a user