from bgenOutput import * | |
from bgenType import * | |
from bgenVariable import * | |
Error = "bgenGenerator.Error" | |
DEBUG=0 | |
# Strings to specify argument transfer modes in generator calls | |
IN = "in" | |
OUT = "out" | |
INOUT = IN_OUT = "in-out" | |
class BaseFunctionGenerator: | |
def __init__(self, name, condition=None, callname=None, modifiers=None): | |
if DEBUG: print "<--", name | |
self.name = name | |
if callname: | |
self.callname = callname | |
else: | |
self.callname = name | |
self.prefix = name | |
self.objecttype = "PyObject" # Type of _self argument to function | |
self.condition = condition | |
self.modifiers = modifiers | |
def setprefix(self, prefix): | |
self.prefix = prefix | |
def checkgenerate(self): | |
return True | |
def generate(self): | |
if not self.checkgenerate(): | |
return | |
if DEBUG: print "-->", self.name | |
if self.condition: | |
Output() | |
Output(self.condition) | |
self.functionheader() | |
self.functionbody() | |
self.functiontrailer() | |
if self.condition: | |
Output("#endif") | |
def functionheader(self): | |
Output() | |
Output("static PyObject *%s_%s(%s *_self, PyObject *_args)", | |
self.prefix, self.name, self.objecttype) | |
OutLbrace() | |
Output("PyObject *_res = NULL;") | |
def functionbody(self): | |
Output("/* XXX To be provided */") | |
def functiontrailer(self): | |
OutRbrace() | |
def reference(self, name = None): | |
if not self.checkgenerate(): | |
return | |
if name is None: | |
name = self.name | |
docstring = self.docstring() | |
if self.condition: | |
Output() | |
Output(self.condition) | |
Output("{\"%s\", (PyCFunction)%s_%s, 1,", name, self.prefix, self.name) | |
Output(" PyDoc_STR(%s)},", stringify(docstring)) | |
if self.condition: | |
Output("#endif") | |
def docstring(self): | |
return None | |
def __cmp__(self, other): | |
if not hasattr(other, 'name'): | |
return cmp(id(self), id(other)) | |
return cmp(self.name, other.name) | |
_stringify_map = {'\n': '\\n', '\t': '\\t', '\r': '\\r', '\b': '\\b', | |
'\e': '\\e', '\a': '\\a', '\f': '\\f', '"': '\\"'} | |
def stringify(str): | |
if str is None: return "NULL" | |
res = '"' | |
map = _stringify_map | |
for c in str: | |
if map.has_key(c): res = res + map[c] | |
elif ' ' <= c <= '~': res = res + c | |
else: res = res + '\\%03o' % ord(c) | |
res = res + '"' | |
return res | |
class ManualGenerator(BaseFunctionGenerator): | |
def __init__(self, name, body, condition=None): | |
BaseFunctionGenerator.__init__(self, name, condition=condition) | |
self.body = body | |
def functionbody(self): | |
Output("%s", self.body) | |
def setselftype(self, selftype, itselftype): | |
self.objecttype = selftype | |
self.itselftype = itselftype | |
class FunctionGenerator(BaseFunctionGenerator): | |
def __init__(self, returntype, name, *argumentList, **conditionlist): | |
BaseFunctionGenerator.__init__(self, name, **conditionlist) | |
self.returntype = returntype | |
self.argumentList = [] | |
self.setreturnvar() | |
self.parseArgumentList(argumentList) | |
self.prefix = "XXX" # Will be changed by setprefix() call | |
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 setselftype(self, selftype, itselftype): | |
self.objecttype = selftype | |
self.itselftype = itselftype | |
def parseArgumentList(self, argumentList): | |
iarg = 0 | |
for type, name, mode in argumentList: | |
iarg = iarg + 1 | |
if name is None: name = "_arg%d" % iarg | |
arg = Variable(type, name, mode) | |
self.argumentList.append(arg) | |
def docstring(self): | |
input = [] | |
output = [] | |
for arg in self.argumentList: | |
if arg.flags == ErrorMode or arg.flags == SelfMode: | |
continue | |
if arg.type is None: | |
str = 'void' | |
else: | |
if hasattr(arg.type, 'typeName'): | |
typeName = arg.type.typeName | |
if typeName is None: # Suppressed type | |
continue | |
else: | |
typeName = "?" | |
print "Nameless type", arg.type | |
str = typeName + ' ' + arg.name | |
if arg.mode in (InMode, InOutMode): | |
input.append(str) | |
if arg.mode in (InOutMode, OutMode): | |
output.append(str) | |
if not input: | |
instr = "()" | |
else: | |
instr = "(%s)" % ", ".join(input) | |
if not output or output == ["void"]: | |
outstr = "None" | |
else: | |
outstr = "(%s)" % ", ".join(output) | |
return instr + " -> " + outstr | |
def functionbody(self): | |
self.declarations() | |
self.precheck() | |
self.getargs() | |
self.callit() | |
self.checkit() | |
self.returnvalue() | |
def declarations(self): | |
for arg in self.argumentList: | |
arg.declare() | |
def getargs(self): | |
sep = ",\n" + ' '*len("if (!PyArg_ParseTuple(") | |
fmt, lst = self.getargsFormatArgs(sep) | |
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 getargsFormatArgs(self, sep): | |
fmt = "" | |
lst = "" | |
for arg in self.argumentList: | |
if arg.flags == SelfMode: | |
continue | |
if arg.mode in (InMode, InOutMode): | |
arg.getargsPreCheck() | |
fmt = fmt + arg.getargsFormat() | |
args = arg.getargsArgs() | |
if args: | |
lst = lst + sep + args | |
return fmt, lst | |
def precheck(self): | |
pass | |
def beginallowthreads(self): | |
pass | |
def endallowthreads(self): | |
pass | |
def callit(self): | |
args = "" | |
s = "%s%s(" % (self.getrvforcallit(), self.callname) | |
sep = ",\n" + ' '*len(s) | |
for arg in self.argumentList: | |
if arg is self.rv: | |
continue | |
s = arg.passArgument() | |
if args: s = sep + s | |
args = args + s | |
self.beginallowthreads() | |
Output("%s%s(%s);", | |
self.getrvforcallit(), self.callname, args) | |
self.endallowthreads() | |
def getrvforcallit(self): | |
if self.rv: | |
return "%s = " % self.rv.name | |
else: | |
return "" | |
def checkit(self): | |
for arg in self.argumentList: | |
arg.errorCheck() | |
def returnvalue(self): | |
sep = ",\n" + ' '*len("return Py_BuildValue(") | |
fmt, lst = self.mkvalueFormatArgs(sep) | |
if fmt == "": | |
Output("Py_INCREF(Py_None);") | |
Output("_res = Py_None;"); | |
else: | |
Output("_res = Py_BuildValue(\"%s\"%s);", fmt, lst) | |
tmp = self.argumentList[:] | |
tmp.reverse() | |
for arg in tmp: | |
if not arg: continue | |
arg.cleanup() | |
Output("return _res;") | |
def mkvalueFormatArgs(self, sep): | |
fmt = "" | |
lst = "" | |
for arg in self.argumentList: | |
if not arg: continue | |
if arg.flags == ErrorMode: continue | |
if arg.mode in (OutMode, InOutMode): | |
arg.mkvaluePreCheck() | |
fmt = fmt + arg.mkvalueFormat() | |
lst = lst + sep + arg.mkvalueArgs() | |
return fmt, lst | |
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) | |
def _test(): | |
void = None | |
eggs = FunctionGenerator(void, "eggs", | |
(stringptr, 'cmd', InMode), | |
(int, 'x', InMode), | |
(double, 'y', InOutMode), | |
(int, 'status', ErrorMode), | |
) | |
eggs.setprefix("spam") | |
print "/* START */" | |
eggs.generate() | |
if __name__ == "__main__": | |
_test() |