1from bgenOutput import * 2from bgenType import * 3from bgenVariable import * 4 5 6Error = "bgenGenerator.Error" 7 8DEBUG=0 9 10# Strings to specify argument transfer modes in generator calls 11IN = "in" 12OUT = "out" 13INOUT = IN_OUT = "in-out" 14 15 16class BaseFunctionGenerator: 17 18 def __init__(self, name, condition=None, callname=None, modifiers=None): 19 if DEBUG: print "<--", name 20 self.name = name 21 if callname: 22 self.callname = callname 23 else: 24 self.callname = name 25 self.prefix = name 26 self.objecttype = "PyObject" # Type of _self argument to function 27 self.condition = condition 28 self.modifiers = modifiers 29 30 def setprefix(self, prefix): 31 self.prefix = prefix 32 33 def checkgenerate(self): 34 return True 35 36 def generate(self): 37 if not self.checkgenerate(): 38 return 39 if DEBUG: print "-->", self.name 40 if self.condition: 41 Output() 42 Output(self.condition) 43 self.functionheader() 44 self.functionbody() 45 self.functiontrailer() 46 if self.condition: 47 Output("#endif") 48 49 def functionheader(self): 50 Output() 51 Output("static PyObject *%s_%s(%s *_self, PyObject *_args)", 52 self.prefix, self.name, self.objecttype) 53 OutLbrace() 54 Output("PyObject *_res = NULL;") 55 56 def functionbody(self): 57 Output("/* XXX To be provided */") 58 59 def functiontrailer(self): 60 OutRbrace() 61 62 def reference(self, name = None): 63 if not self.checkgenerate(): 64 return 65 if name is None: 66 name = self.name 67 docstring = self.docstring() 68 if self.condition: 69 Output() 70 Output(self.condition) 71 Output("{\"%s\", (PyCFunction)%s_%s, 1,", name, self.prefix, self.name) 72 Output(" PyDoc_STR(%s)},", stringify(docstring)) 73 if self.condition: 74 Output("#endif") 75 76 def docstring(self): 77 return None 78 79 def __cmp__(self, other): 80 if not hasattr(other, 'name'): 81 return cmp(id(self), id(other)) 82 return cmp(self.name, other.name) 83 84_stringify_map = {'\n': '\\n', '\t': '\\t', '\r': '\\r', '\b': '\\b', 85 '\e': '\\e', '\a': '\\a', '\f': '\\f', '"': '\\"'} 86def stringify(str): 87 if str is None: return "NULL" 88 res = '"' 89 map = _stringify_map 90 for c in str: 91 if map.has_key(c): res = res + map[c] 92 elif ' ' <= c <= '~': res = res + c 93 else: res = res + '\\%03o' % ord(c) 94 res = res + '"' 95 return res 96 97 98class ManualGenerator(BaseFunctionGenerator): 99 100 def __init__(self, name, body, condition=None): 101 BaseFunctionGenerator.__init__(self, name, condition=condition) 102 self.body = body 103 104 def functionbody(self): 105 Output("%s", self.body) 106 107 def setselftype(self, selftype, itselftype): 108 self.objecttype = selftype 109 self.itselftype = itselftype 110 111 112class FunctionGenerator(BaseFunctionGenerator): 113 114 def __init__(self, returntype, name, *argumentList, **conditionlist): 115 BaseFunctionGenerator.__init__(self, name, **conditionlist) 116 self.returntype = returntype 117 self.argumentList = [] 118 self.setreturnvar() 119 self.parseArgumentList(argumentList) 120 self.prefix = "XXX" # Will be changed by setprefix() call 121 self.itselftype = None # Type of _self->ob_itself, if defined 122 123 def setreturnvar(self): 124 if self.returntype: 125 self.rv = self.makereturnvar() 126 self.argumentList.append(self.rv) 127 else: 128 self.rv = None 129 130 def makereturnvar(self): 131 return Variable(self.returntype, "_rv", OutMode) 132 133 def setselftype(self, selftype, itselftype): 134 self.objecttype = selftype 135 self.itselftype = itselftype 136 137 def parseArgumentList(self, argumentList): 138 iarg = 0 139 for type, name, mode in argumentList: 140 iarg = iarg + 1 141 if name is None: name = "_arg%d" % iarg 142 arg = Variable(type, name, mode) 143 self.argumentList.append(arg) 144 145 def docstring(self): 146 input = [] 147 output = [] 148 for arg in self.argumentList: 149 if arg.flags == ErrorMode or arg.flags == SelfMode: 150 continue 151 if arg.type is None: 152 str = 'void' 153 else: 154 if hasattr(arg.type, 'typeName'): 155 typeName = arg.type.typeName 156 if typeName is None: # Suppressed type 157 continue 158 else: 159 typeName = "?" 160 print "Nameless type", arg.type 161 162 str = typeName + ' ' + arg.name 163 if arg.mode in (InMode, InOutMode): 164 input.append(str) 165 if arg.mode in (InOutMode, OutMode): 166 output.append(str) 167 if not input: 168 instr = "()" 169 else: 170 instr = "(%s)" % ", ".join(input) 171 if not output or output == ["void"]: 172 outstr = "None" 173 else: 174 outstr = "(%s)" % ", ".join(output) 175 return instr + " -> " + outstr 176 177 def functionbody(self): 178 self.declarations() 179 self.precheck() 180 self.getargs() 181 self.callit() 182 self.checkit() 183 self.returnvalue() 184 185 def declarations(self): 186 for arg in self.argumentList: 187 arg.declare() 188 189 def getargs(self): 190 sep = ",\n" + ' '*len("if (!PyArg_ParseTuple(") 191 fmt, lst = self.getargsFormatArgs(sep) 192 Output("if (!PyArg_ParseTuple(_args, \"%s\"%s))", fmt, lst) 193 IndentLevel() 194 Output("return NULL;") 195 DedentLevel() 196 for arg in self.argumentList: 197 if arg.flags == SelfMode: 198 continue 199 if arg.mode in (InMode, InOutMode): 200 arg.getargsCheck() 201 202 def getargsFormatArgs(self, sep): 203 fmt = "" 204 lst = "" 205 for arg in self.argumentList: 206 if arg.flags == SelfMode: 207 continue 208 if arg.mode in (InMode, InOutMode): 209 arg.getargsPreCheck() 210 fmt = fmt + arg.getargsFormat() 211 args = arg.getargsArgs() 212 if args: 213 lst = lst + sep + args 214 return fmt, lst 215 216 def precheck(self): 217 pass 218 219 def beginallowthreads(self): 220 pass 221 222 def endallowthreads(self): 223 pass 224 225 def callit(self): 226 args = "" 227 s = "%s%s(" % (self.getrvforcallit(), self.callname) 228 sep = ",\n" + ' '*len(s) 229 for arg in self.argumentList: 230 if arg is self.rv: 231 continue 232 s = arg.passArgument() 233 if args: s = sep + s 234 args = args + s 235 self.beginallowthreads() 236 Output("%s%s(%s);", 237 self.getrvforcallit(), self.callname, args) 238 self.endallowthreads() 239 240 def getrvforcallit(self): 241 if self.rv: 242 return "%s = " % self.rv.name 243 else: 244 return "" 245 246 def checkit(self): 247 for arg in self.argumentList: 248 arg.errorCheck() 249 250 def returnvalue(self): 251 sep = ",\n" + ' '*len("return Py_BuildValue(") 252 fmt, lst = self.mkvalueFormatArgs(sep) 253 if fmt == "": 254 Output("Py_INCREF(Py_None);") 255 Output("_res = Py_None;"); 256 else: 257 Output("_res = Py_BuildValue(\"%s\"%s);", fmt, lst) 258 tmp = self.argumentList[:] 259 tmp.reverse() 260 for arg in tmp: 261 if not arg: continue 262 arg.cleanup() 263 Output("return _res;") 264 265 def mkvalueFormatArgs(self, sep): 266 fmt = "" 267 lst = "" 268 for arg in self.argumentList: 269 if not arg: continue 270 if arg.flags == ErrorMode: continue 271 if arg.mode in (OutMode, InOutMode): 272 arg.mkvaluePreCheck() 273 fmt = fmt + arg.mkvalueFormat() 274 lst = lst + sep + arg.mkvalueArgs() 275 return fmt, lst 276 277class MethodGenerator(FunctionGenerator): 278 279 def parseArgumentList(self, args): 280 a0, args = args[0], args[1:] 281 t0, n0, m0 = a0 282 if m0 != InMode: 283 raise ValueError, "method's 'self' must be 'InMode'" 284 self.itself = Variable(t0, "_self->ob_itself", SelfMode) 285 self.argumentList.append(self.itself) 286 FunctionGenerator.parseArgumentList(self, args) 287 288def _test(): 289 void = None 290 eggs = FunctionGenerator(void, "eggs", 291 (stringptr, 'cmd', InMode), 292 (int, 'x', InMode), 293 (double, 'y', InOutMode), 294 (int, 'status', ErrorMode), 295 ) 296 eggs.setprefix("spam") 297 print "/* START */" 298 eggs.generate() 299 300 301if __name__ == "__main__": 302 _test() 303