| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 1 | # This script generates the Sound interface for Python. |
| 2 | # It uses the "bgen" package to generate C code. |
| 3 | # It execs the file sndgen.py which contain the function definitions |
| 4 | # (sndgen.py was generated by sndscan.py, scanning the <Sound.h> header file). |
| 5 | |
| 6 | from macsupport import * |
| 7 | |
| 8 | |
| 9 | # define our own function and module generators |
| 10 | |
| 11 | class SndMixIn: pass |
| 12 | |
| 13 | class SndFunction(SndMixIn, OSErrFunctionGenerator): pass |
| 14 | class SndMethod(SndMixIn, OSErrMethodGenerator): pass |
| 15 | |
| 16 | |
| 17 | # includestuff etc. are imported from macsupport |
| 18 | |
| 19 | includestuff = includestuff + """ |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 20 | #ifdef WITHOUT_FRAMEWORKS |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 21 | #include <Sound.h> |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 22 | #include <OSUtils.h> /* for Set(Current)A5 */ |
| 23 | #else |
| 24 | #include <Carbon/Carbon.h> |
| 25 | #endif |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 26 | """ |
| 27 | |
| 28 | initstuff = initstuff + """ |
| 29 | """ |
| 30 | |
| 31 | |
| 32 | # define types used for arguments (in addition to standard and macsupport types) |
| 33 | |
| 34 | class SndChannelPtrType(OpaqueByValueType): |
| 35 | def declare(self, name): |
| 36 | # Initializing all SndChannelPtr objects to 0 saves |
| 37 | # special-casing NewSndChannel(), where it is formally an |
| 38 | # input-output parameter but we treat it as output-only |
| 39 | # (since Python users are not supposed to allocate memory) |
| 40 | Output("SndChannelPtr %s = 0;", name) |
| 41 | |
| 42 | SndChannelPtr = SndChannelPtrType('SndChannelPtr', 'SndCh') |
| 43 | |
| 44 | SndCommand = OpaqueType('SndCommand', 'SndCmd') |
| 45 | SndCommand_ptr = OpaqueType('SndCommand', 'SndCmd') |
| 46 | SndListHandle = OpaqueByValueType("SndListHandle", "ResObj") |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 47 | SPBPtr = OpaqueByValueType("SPBPtr", "SPBObj") |
| 48 | |
| 49 | # |
| 50 | # NOTE: the following is pretty dangerous. For void pointers we pass buffer addresses |
| 51 | # but we have no way to check that the buffer is big enough. This is the same problem |
| 52 | # as in C, though (but Pythoneers may not be suspecting this...) |
| 53 | void_ptr = Type("void *", "w") |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 54 | |
| 55 | class SndCallBackType(InputOnlyType): |
| 56 | def __init__(self): |
| 57 | Type.__init__(self, 'PyObject*', 'O') |
| 58 | def getargsCheck(self, name): |
| Guido van Rossum | 9784295 | 1995-02-19 15:59:49 +0000 | [diff] [blame] | 59 | Output("if (%s != Py_None && !PyCallable_Check(%s))", name, name) |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 60 | OutLbrace() |
| 61 | Output('PyErr_SetString(PyExc_TypeError, "callback must be callable");') |
| 62 | Output("goto %s__error__;", name) |
| 63 | OutRbrace() |
| 64 | def passInput(self, name): |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 65 | return "NewSndCallBackUPP(SndCh_UserRoutine)" |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 66 | def cleanup(self, name): |
| 67 | # XXX This knows it is executing inside the SndNewChannel wrapper |
| 68 | Output("if (_res != NULL && %s != Py_None)", name) |
| 69 | OutLbrace() |
| 70 | Output("SndChannelObject *p = (SndChannelObject *)_res;") |
| 71 | Output("p->ob_itself->userInfo = (long)p;") |
| 72 | Output("Py_INCREF(%s);", name) |
| 73 | Output("p->ob_callback = %s;", name) |
| 74 | OutRbrace() |
| 75 | DedentLevel() |
| 76 | Output(" %s__error__: ;", name) |
| 77 | IndentLevel() |
| 78 | |
| 79 | SndCallBackProcPtr = SndCallBackType() |
| Jack Jansen | b81cf9d | 1995-06-06 13:08:40 +0000 | [diff] [blame] | 80 | SndCallBackUPP = SndCallBackProcPtr |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 81 | |
| 82 | SndCompletionProcPtr = FakeType('(SndCompletionProcPtr)0') # XXX |
| Jack Jansen | b81cf9d | 1995-06-06 13:08:40 +0000 | [diff] [blame] | 83 | SndCompletionUPP = SndCompletionProcPtr |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 84 | |
| Jack Jansen | 7d0bc83 | 1995-06-09 20:56:31 +0000 | [diff] [blame] | 85 | ##InOutBuf128 = FixedInputOutputBufferType(128) |
| 86 | StateBlock = StructInputOutputBufferType('StateBlock') |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 87 | |
| 88 | AudioSelectionPtr = FakeType('0') # XXX |
| 89 | |
| 90 | ProcPtr = FakeType('0') # XXX |
| Jack Jansen | b81cf9d | 1995-06-06 13:08:40 +0000 | [diff] [blame] | 91 | FilePlayCompletionUPP = FakeType('0') # XXX |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 92 | |
| 93 | SCStatus = StructOutputBufferType('SCStatus') |
| 94 | SMStatus = StructOutputBufferType('SMStatus') |
| Jack Jansen | b81cf9d | 1995-06-06 13:08:40 +0000 | [diff] [blame] | 95 | CompressionInfo = StructOutputBufferType('CompressionInfo') |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 96 | |
| 97 | includestuff = includestuff + """ |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 98 | |
| 99 | /* Create a SndCommand object (an (int, int, int) tuple) */ |
| 100 | static PyObject * |
| 101 | SndCmd_New(SndCommand *pc) |
| 102 | { |
| 103 | return Py_BuildValue("hhl", pc->cmd, pc->param1, pc->param2); |
| 104 | } |
| 105 | |
| 106 | /* Convert a SndCommand argument */ |
| 107 | static int |
| 108 | SndCmd_Convert(PyObject *v, SndCommand *pc) |
| 109 | { |
| 110 | int len; |
| 111 | pc->param1 = 0; |
| 112 | pc->param2 = 0; |
| 113 | if (PyTuple_Check(v)) { |
| 114 | if (PyArg_ParseTuple(v, "h|hl", &pc->cmd, &pc->param1, &pc->param2)) |
| 115 | return 1; |
| 116 | PyErr_Clear(); |
| Jack Jansen | 0b13e7c | 2000-07-07 13:09:35 +0000 | [diff] [blame] | 117 | return PyArg_ParseTuple(v, "Hhs#", &pc->cmd, &pc->param1, &pc->param2, &len); |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 118 | } |
| Jack Jansen | 0b13e7c | 2000-07-07 13:09:35 +0000 | [diff] [blame] | 119 | return PyArg_Parse(v, "H", &pc->cmd); |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 120 | } |
| 121 | |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 122 | static pascal void SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd); /* Forward */ |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 123 | static pascal void SPB_completion(SPBPtr my_spb); /* Forward */ |
| Jack Jansen | 319c67b | 2001-01-12 23:39:59 +0000 | [diff] [blame] | 124 | #if !TARGET_API_MAC_CARBON |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 125 | static pascal void SPB_interrupt(SPBPtr my_spb); /* Forward */ |
| Jack Jansen | 319c67b | 2001-01-12 23:39:59 +0000 | [diff] [blame] | 126 | #endif |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 127 | """ |
| 128 | |
| 129 | |
| 130 | finalstuff = finalstuff + """ |
| 131 | /* Routine passed to Py_AddPendingCall -- call the Python callback */ |
| 132 | static int |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 133 | SndCh_CallCallBack(void *arg) |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 134 | { |
| 135 | SndChannelObject *p = (SndChannelObject *)arg; |
| 136 | PyObject *args; |
| 137 | PyObject *res; |
| 138 | args = Py_BuildValue("(O(hhl))", |
| 139 | p, p->ob_cmd.cmd, p->ob_cmd.param1, p->ob_cmd.param2); |
| 140 | res = PyEval_CallObject(p->ob_callback, args); |
| 141 | Py_DECREF(args); |
| 142 | if (res == NULL) |
| 143 | return -1; |
| 144 | Py_DECREF(res); |
| 145 | return 0; |
| 146 | } |
| 147 | |
| 148 | /* Routine passed to NewSndChannel -- schedule a call to SndCh_CallCallBack */ |
| 149 | static pascal void |
| 150 | SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd) |
| 151 | { |
| 152 | SndChannelObject *p = (SndChannelObject *)(chan->userInfo); |
| 153 | if (p->ob_callback != NULL) { |
| 154 | long A5 = SetA5(p->ob_A5); |
| 155 | p->ob_cmd = *cmd; |
| 156 | Py_AddPendingCall(SndCh_CallCallBack, (void *)p); |
| 157 | SetA5(A5); |
| 158 | } |
| 159 | } |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 160 | |
| 161 | /* SPB callbacks - Schedule callbacks to Python */ |
| 162 | static int |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 163 | SPB_CallCallBack(void *arg) |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 164 | { |
| 165 | SPBObject *p = (SPBObject *)arg; |
| 166 | PyObject *args; |
| 167 | PyObject *res; |
| 168 | |
| 169 | if ( p->ob_thiscallback == 0 ) return 0; |
| 170 | args = Py_BuildValue("(O)", p); |
| 171 | res = PyEval_CallObject(p->ob_thiscallback, args); |
| 172 | p->ob_thiscallback = 0; |
| 173 | Py_DECREF(args); |
| 174 | if (res == NULL) |
| 175 | return -1; |
| 176 | Py_DECREF(res); |
| 177 | return 0; |
| 178 | } |
| 179 | |
| 180 | static pascal void |
| 181 | SPB_completion(SPBPtr my_spb) |
| 182 | { |
| 183 | SPBObject *p = (SPBObject *)(my_spb->userLong); |
| 184 | |
| 185 | if (p && p->ob_completion) { |
| 186 | long A5 = SetA5(p->ob_A5); |
| 187 | p->ob_thiscallback = p->ob_completion; /* Hope we cannot get two at the same time */ |
| 188 | Py_AddPendingCall(SPB_CallCallBack, (void *)p); |
| 189 | SetA5(A5); |
| 190 | } |
| 191 | } |
| 192 | |
| Jack Jansen | 319c67b | 2001-01-12 23:39:59 +0000 | [diff] [blame] | 193 | #if !TARGET_API_MAC_CARBON |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 194 | static pascal void |
| 195 | SPB_interrupt(SPBPtr my_spb) |
| 196 | { |
| 197 | SPBObject *p = (SPBObject *)(my_spb->userLong); |
| 198 | |
| 199 | if (p && p->ob_interrupt) { |
| 200 | long A5 = SetA5(p->ob_A5); |
| 201 | p->ob_thiscallback = p->ob_interrupt; /* Hope we cannot get two at the same time */ |
| 202 | Py_AddPendingCall(SPB_CallCallBack, (void *)p); |
| 203 | SetA5(A5); |
| 204 | } |
| 205 | } |
| Jack Jansen | 319c67b | 2001-01-12 23:39:59 +0000 | [diff] [blame] | 206 | #endif |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 207 | """ |
| 208 | |
| 209 | |
| 210 | # create the module and object definition and link them |
| 211 | |
| 212 | class SndObjectDefinition(ObjectDefinition): |
| 213 | |
| 214 | def outputStructMembers(self): |
| 215 | ObjectDefinition.outputStructMembers(self) |
| 216 | Output("/* Members used to implement callbacks: */") |
| 217 | Output("PyObject *ob_callback;") |
| 218 | Output("long ob_A5;"); |
| 219 | Output("SndCommand ob_cmd;") |
| 220 | |
| 221 | def outputInitStructMembers(self): |
| 222 | ObjectDefinition.outputInitStructMembers(self) |
| 223 | Output("it->ob_callback = NULL;") |
| 224 | Output("it->ob_A5 = SetCurrentA5();"); |
| 225 | |
| 226 | def outputCleanupStructMembers(self): |
| 227 | ObjectDefinition.outputCleanupStructMembers(self) |
| 228 | Output("Py_XDECREF(self->ob_callback);") |
| 229 | |
| 230 | def outputFreeIt(self, itselfname): |
| 231 | Output("SndDisposeChannel(%s, 1);", itselfname) |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 232 | |
| 233 | # |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 234 | |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 235 | class SpbObjectDefinition(ObjectDefinition): |
| 236 | |
| 237 | def outputStructMembers(self): |
| 238 | Output("/* Members used to implement callbacks: */") |
| 239 | Output("PyObject *ob_completion;") |
| 240 | Output("PyObject *ob_interrupt;") |
| 241 | Output("PyObject *ob_thiscallback;"); |
| 242 | Output("long ob_A5;") |
| 243 | Output("SPB ob_spb;") |
| 244 | |
| 245 | def outputNew(self): |
| 246 | Output() |
| Jack Jansen | 3685a43 | 2001-06-20 21:22:23 +0000 | [diff] [blame] | 247 | Output("%sPyObject *%s_New(void)", self.static, self.prefix) |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 248 | OutLbrace() |
| 249 | Output("%s *it;", self.objecttype) |
| 250 | self.outputCheckNewArg() |
| 251 | Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename) |
| 252 | Output("if (it == NULL) return NULL;") |
| 253 | self.outputInitStructMembers() |
| 254 | Output("return (PyObject *)it;") |
| 255 | OutRbrace() |
| 256 | |
| 257 | def outputInitStructMembers(self): |
| 258 | Output("it->ob_completion = NULL;") |
| 259 | Output("it->ob_interrupt = NULL;") |
| 260 | Output("it->ob_thiscallback = NULL;") |
| 261 | Output("it->ob_A5 = SetCurrentA5();") |
| 262 | Output("memset((char *)&it->ob_spb, 0, sizeof(it->ob_spb));") |
| 263 | Output("it->ob_spb.userLong = (long)it;") |
| 264 | |
| 265 | def outputCleanupStructMembers(self): |
| 266 | ObjectDefinition.outputCleanupStructMembers(self) |
| 267 | Output("self->ob_spb.userLong = 0;") |
| 268 | Output("self->ob_thiscallback = 0;") |
| 269 | Output("Py_XDECREF(self->ob_completion);") |
| 270 | Output("Py_XDECREF(self->ob_interrupt);") |
| 271 | |
| 272 | def outputConvert(self): |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 273 | Output("%s%s_Convert(PyObject *v, %s *p_itself)", self.static, self.prefix, self.itselftype) |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 274 | OutLbrace() |
| 275 | self.outputCheckConvertArg() |
| 276 | Output("if (!%s_Check(v))", self.prefix) |
| 277 | OutLbrace() |
| 278 | Output('PyErr_SetString(PyExc_TypeError, "%s required");', self.name) |
| 279 | Output("return 0;") |
| 280 | OutRbrace() |
| 281 | Output("*p_itself = &((%s *)v)->ob_spb;", self.objecttype) |
| 282 | Output("return 1;") |
| 283 | OutRbrace() |
| 284 | |
| 285 | def outputSetattr(self): |
| 286 | Output() |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 287 | Output("static int %s_setattr(%s *self, char *name, PyObject *value)", |
| 288 | self.prefix, self.objecttype) |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 289 | OutLbrace() |
| 290 | self.outputSetattrBody() |
| 291 | OutRbrace() |
| 292 | |
| 293 | def outputSetattrBody(self): |
| 294 | Output(""" |
| Jack Jansen | a239a92 | 1998-04-15 14:08:28 +0000 | [diff] [blame] | 295 | int rv = 0; |
| 296 | |
| 297 | if (strcmp(name, "inRefNum") == 0) |
| 298 | rv = PyArg_Parse(value, "l", &self->ob_spb.inRefNum); |
| 299 | else if (strcmp(name, "count") == 0) |
| 300 | rv = PyArg_Parse(value, "l", &self->ob_spb.count); |
| 301 | else if (strcmp(name, "milliseconds") == 0) |
| 302 | rv = PyArg_Parse(value, "l", &self->ob_spb.milliseconds); |
| 303 | else if (strcmp(name, "buffer") == 0) |
| 304 | rv = PyArg_Parse(value, "w#", &self->ob_spb.bufferPtr, &self->ob_spb.bufferLength); |
| 305 | else if (strcmp(name, "completionRoutine") == 0) { |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 306 | self->ob_spb.completionRoutine = NewSICompletionUPP(SPB_completion); |
| Jack Jansen | a239a92 | 1998-04-15 14:08:28 +0000 | [diff] [blame] | 307 | self->ob_completion = value; |
| 308 | Py_INCREF(value); |
| 309 | rv = 1; |
| Jack Jansen | 319c67b | 2001-01-12 23:39:59 +0000 | [diff] [blame] | 310 | #if !TARGET_API_MAC_CARBON |
| Jack Jansen | a239a92 | 1998-04-15 14:08:28 +0000 | [diff] [blame] | 311 | } else if (strcmp(name, "interruptRoutine") == 0) { |
| Jack Jansen | fa77e1a | 2001-05-22 21:56:42 +0000 | [diff] [blame] | 312 | self->ob_spb.completionRoutine = NewSIInterruptUPP(SPB_interrupt); |
| Jack Jansen | a239a92 | 1998-04-15 14:08:28 +0000 | [diff] [blame] | 313 | self->ob_interrupt = value; |
| 314 | Py_INCREF(value); |
| 315 | rv = 1; |
| Jack Jansen | 8d929ae | 2000-06-21 22:07:06 +0000 | [diff] [blame] | 316 | #endif |
| Jack Jansen | a239a92 | 1998-04-15 14:08:28 +0000 | [diff] [blame] | 317 | } |
| 318 | if ( rv ) return 0; |
| 319 | else return -1;""") |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 320 | |
| 321 | def outputGetattrHook(self): |
| 322 | Output(""" |
| 323 | if (strcmp(name, "inRefNum") == 0) |
| 324 | return Py_BuildValue("l", self->ob_spb.inRefNum); |
| 325 | else if (strcmp(name, "count") == 0) |
| 326 | return Py_BuildValue("l", self->ob_spb.count); |
| 327 | else if (strcmp(name, "milliseconds") == 0) |
| 328 | return Py_BuildValue("l", self->ob_spb.milliseconds); |
| 329 | else if (strcmp(name, "error") == 0) |
| 330 | return Py_BuildValue("h", self->ob_spb.error);""") |
| 331 | |
| 332 | |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 333 | |
| 334 | sndobject = SndObjectDefinition('SndChannel', 'SndCh', 'SndChannelPtr') |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 335 | spbobject = SpbObjectDefinition('SPB', 'SPBObj', 'SPBPtr') |
| 336 | spbgenerator = ManualGenerator("SPB", "return SPBObj_New();") |
| Jack Jansen | 77105a9 | 2001-08-23 13:51:46 +0000 | [diff] [blame^] | 337 | module = MacModule('_Snd', 'Snd', includestuff, finalstuff, initstuff) |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 338 | module.addobject(sndobject) |
| Jack Jansen | 52b38b7 | 1998-02-25 15:47:51 +0000 | [diff] [blame] | 339 | module.addobject(spbobject) |
| 340 | module.add(spbgenerator) |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 341 | |
| 342 | |
| 343 | # create lists of functions and object methods |
| 344 | |
| 345 | functions = [] |
| 346 | sndmethods = [] |
| 347 | |
| 348 | |
| 349 | # populate the lists |
| 350 | |
| 351 | execfile('sndgen.py') |
| 352 | |
| 353 | |
| 354 | # add the functions and methods to the module and object, respectively |
| 355 | |
| 356 | for f in functions: module.add(f) |
| 357 | for f in sndmethods: sndobject.add(f) |
| 358 | |
| 359 | |
| 360 | # generate output |
| 361 | |
| Jack Jansen | 77105a9 | 2001-08-23 13:51:46 +0000 | [diff] [blame^] | 362 | SetOutputFileName('_Sndmodule.c') |
| Guido van Rossum | 17448e2 | 1995-01-30 11:53:55 +0000 | [diff] [blame] | 363 | module.generate() |