cb_rules.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. """
  2. Build call-back mechanism for f2py2e.
  3. Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
  4. Copyright 2011 -- present NumPy Developers.
  5. Permission to use, modify, and distribute this software is given under the
  6. terms of the NumPy License.
  7. NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  8. """
  9. from . import __version__, cfuncs
  10. from .auxfuncs import (
  11. applyrules,
  12. debugcapi,
  13. dictappend,
  14. errmess,
  15. getargs,
  16. hasnote,
  17. isarray,
  18. iscomplex,
  19. iscomplexarray,
  20. iscomplexfunction,
  21. isfunction,
  22. isintent_c,
  23. isintent_hide,
  24. isintent_in,
  25. isintent_inout,
  26. isintent_nothide,
  27. isintent_out,
  28. isoptional,
  29. isrequired,
  30. isscalar,
  31. isstring,
  32. isstringfunction,
  33. issubroutine,
  34. l_and,
  35. l_not,
  36. l_or,
  37. outmess,
  38. replace,
  39. stripcomma,
  40. throw_error,
  41. )
  42. f2py_version = __version__.version
  43. ################## Rules for callback function ##############
  44. cb_routine_rules = {
  45. 'cbtypedefs': 'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);',
  46. 'body': """
  47. #begintitle#
  48. typedef struct {
  49. PyObject *capi;
  50. PyTupleObject *args_capi;
  51. int nofargs;
  52. jmp_buf jmpbuf;
  53. } #name#_t;
  54. #if defined(F2PY_THREAD_LOCAL_DECL) && !defined(F2PY_USE_PYTHON_TLS)
  55. static F2PY_THREAD_LOCAL_DECL #name#_t *_active_#name# = NULL;
  56. static #name#_t *swap_active_#name#(#name#_t *ptr) {
  57. #name#_t *prev = _active_#name#;
  58. _active_#name# = ptr;
  59. return prev;
  60. }
  61. static #name#_t *get_active_#name#(void) {
  62. return _active_#name#;
  63. }
  64. #else
  65. static #name#_t *swap_active_#name#(#name#_t *ptr) {
  66. char *key = "__f2py_cb_#name#";
  67. return (#name#_t *)F2PySwapThreadLocalCallbackPtr(key, ptr);
  68. }
  69. static #name#_t *get_active_#name#(void) {
  70. char *key = "__f2py_cb_#name#";
  71. return (#name#_t *)F2PyGetThreadLocalCallbackPtr(key);
  72. }
  73. #endif
  74. /*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/
  75. #static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) {
  76. #name#_t cb_local = { NULL, NULL, 0 };
  77. #name#_t *cb = NULL;
  78. PyTupleObject *capi_arglist = NULL;
  79. PyObject *capi_return = NULL;
  80. PyObject *capi_tmp = NULL;
  81. PyObject *capi_arglist_list = NULL;
  82. int capi_j,capi_i = 0;
  83. int capi_longjmp_ok = 1;
  84. #decl#
  85. #ifdef F2PY_REPORT_ATEXIT
  86. f2py_cb_start_clock();
  87. #endif
  88. cb = get_active_#name#();
  89. if (cb == NULL) {
  90. capi_longjmp_ok = 0;
  91. cb = &cb_local;
  92. }
  93. capi_arglist = cb->args_capi;
  94. CFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
  95. CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
  96. if (cb->capi==NULL) {
  97. capi_longjmp_ok = 0;
  98. cb->capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
  99. CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
  100. }
  101. if (cb->capi==NULL) {
  102. PyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
  103. goto capi_fail;
  104. }
  105. if (F2PyCapsule_Check(cb->capi)) {
  106. #name#_typedef #name#_cptr;
  107. #name#_cptr = F2PyCapsule_AsVoidPtr(cb->capi);
  108. #returncptr#(*#name#_cptr)(#optargs_nm##args_nm##strarglens_nm#);
  109. #return#
  110. }
  111. if (capi_arglist==NULL) {
  112. capi_longjmp_ok = 0;
  113. capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\");
  114. if (capi_tmp) {
  115. capi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp);
  116. Py_DECREF(capi_tmp);
  117. if (capi_arglist==NULL) {
  118. PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\");
  119. goto capi_fail;
  120. }
  121. } else {
  122. PyErr_Clear();
  123. capi_arglist = (PyTupleObject *)Py_BuildValue(\"()\");
  124. }
  125. }
  126. if (capi_arglist == NULL) {
  127. PyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\");
  128. goto capi_fail;
  129. }
  130. #setdims#
  131. #ifdef PYPY_VERSION
  132. #define CAPI_ARGLIST_SETITEM(idx, value) PyList_SetItem((PyObject *)capi_arglist_list, idx, value)
  133. capi_arglist_list = PySequence_List((PyObject *)capi_arglist);
  134. if (capi_arglist_list == NULL) goto capi_fail;
  135. #else
  136. #define CAPI_ARGLIST_SETITEM(idx, value) PyTuple_SetItem((PyObject *)capi_arglist, idx, value)
  137. #endif
  138. #pyobjfrom#
  139. #undef CAPI_ARGLIST_SETITEM
  140. #ifdef PYPY_VERSION
  141. CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist_list);
  142. #else
  143. CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist);
  144. #endif
  145. CFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\");
  146. #ifdef F2PY_REPORT_ATEXIT
  147. f2py_cb_start_call_clock();
  148. #endif
  149. #ifdef PYPY_VERSION
  150. capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist_list);
  151. Py_DECREF(capi_arglist_list);
  152. capi_arglist_list = NULL;
  153. #else
  154. capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist);
  155. #endif
  156. #ifdef F2PY_REPORT_ATEXIT
  157. f2py_cb_stop_call_clock();
  158. #endif
  159. CFUNCSMESSPY(\"cb:capi_return=\",capi_return);
  160. if (capi_return == NULL) {
  161. fprintf(stderr,\"capi_return is NULL\\n\");
  162. goto capi_fail;
  163. }
  164. if (capi_return == Py_None) {
  165. Py_DECREF(capi_return);
  166. capi_return = Py_BuildValue(\"()\");
  167. }
  168. else if (!PyTuple_Check(capi_return)) {
  169. capi_return = Py_BuildValue(\"(N)\",capi_return);
  170. }
  171. capi_j = PyTuple_Size(capi_return);
  172. capi_i = 0;
  173. #frompyobj#
  174. CFUNCSMESS(\"cb:#name#:successful\\n\");
  175. Py_DECREF(capi_return);
  176. #ifdef F2PY_REPORT_ATEXIT
  177. f2py_cb_stop_clock();
  178. #endif
  179. goto capi_return_pt;
  180. capi_fail:
  181. fprintf(stderr,\"Call-back #name# failed.\\n\");
  182. Py_XDECREF(capi_return);
  183. Py_XDECREF(capi_arglist_list);
  184. if (capi_longjmp_ok) {
  185. longjmp(cb->jmpbuf,-1);
  186. }
  187. capi_return_pt:
  188. ;
  189. #return#
  190. }
  191. #endtitle#
  192. """,
  193. 'need': ['setjmp.h', 'CFUNCSMESS', 'F2PY_THREAD_LOCAL_DECL'],
  194. 'maxnofargs': '#maxnofargs#',
  195. 'nofoptargs': '#nofoptargs#',
  196. 'docstr': """\
  197. def #argname#(#docsignature#): return #docreturn#\\n\\
  198. #docstrsigns#""",
  199. 'latexdocstr': """
  200. {{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}}
  201. #routnote#
  202. #latexdocstrsigns#""",
  203. 'docstrshort': 'def #argname#(#docsignature#): return #docreturn#'
  204. }
  205. cb_rout_rules = [
  206. { # Init
  207. 'separatorsfor': {'decl': '\n',
  208. 'args': ',', 'optargs': '', 'pyobjfrom': '\n', 'freemem': '\n',
  209. 'args_td': ',', 'optargs_td': '',
  210. 'args_nm': ',', 'optargs_nm': '',
  211. 'frompyobj': '\n', 'setdims': '\n',
  212. 'docstrsigns': '\\n"\n"',
  213. 'latexdocstrsigns': '\n',
  214. 'latexdocstrreq': '\n', 'latexdocstropt': '\n',
  215. 'latexdocstrout': '\n', 'latexdocstrcbs': '\n',
  216. },
  217. 'decl': '/*decl*/', 'pyobjfrom': '/*pyobjfrom*/', 'frompyobj': '/*frompyobj*/',
  218. 'args': [], 'optargs': '', 'return': '', 'strarglens': '', 'freemem': '/*freemem*/',
  219. 'args_td': [], 'optargs_td': '', 'strarglens_td': '',
  220. 'args_nm': [], 'optargs_nm': '', 'strarglens_nm': '',
  221. 'noargs': '',
  222. 'setdims': '/*setdims*/',
  223. 'docstrsigns': '', 'latexdocstrsigns': '',
  224. 'docstrreq': ' Required arguments:',
  225. 'docstropt': ' Optional arguments:',
  226. 'docstrout': ' Return objects:',
  227. 'docstrcbs': ' Call-back functions:',
  228. 'docreturn': '', 'docsign': '', 'docsignopt': '',
  229. 'latexdocstrreq': '\\noindent Required arguments:',
  230. 'latexdocstropt': '\\noindent Optional arguments:',
  231. 'latexdocstrout': '\\noindent Return objects:',
  232. 'latexdocstrcbs': '\\noindent Call-back functions:',
  233. 'routnote': {hasnote: '--- #note#', l_not(hasnote): ''},
  234. }, { # Function
  235. 'decl': ' #ctype# return_value = 0;',
  236. 'frompyobj': [
  237. {debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
  238. '''\
  239. if (capi_j>capi_i) {
  240. GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,
  241. "#ctype#_from_pyobj failed in converting return_value of"
  242. " call-back function #name# to C #ctype#\\n");
  243. } else {
  244. fprintf(stderr,"Warning: call-back function #name# did not provide"
  245. " return value (index=%d, type=#ctype#)\\n",capi_i);
  246. }''',
  247. {debugcapi:
  248. ' fprintf(stderr,"#showvalueformat#.\\n",return_value);'}
  249. ],
  250. 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, 'GETSCALARFROMPYTUPLE'],
  251. 'return': ' return return_value;',
  252. '_check': l_and(isfunction, l_not(isstringfunction), l_not(iscomplexfunction))
  253. },
  254. { # String function
  255. 'pyobjfrom': {debugcapi: ' fprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'},
  256. 'args': '#ctype# return_value,int return_value_len',
  257. 'args_nm': 'return_value,&return_value_len',
  258. 'args_td': '#ctype# ,int',
  259. 'frompyobj': [
  260. {debugcapi: ' CFUNCSMESS("cb:Getting return_value->\\"");'},
  261. """\
  262. if (capi_j>capi_i) {
  263. GETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);
  264. } else {
  265. fprintf(stderr,"Warning: call-back function #name# did not provide"
  266. " return value (index=%d, type=#ctype#)\\n",capi_i);
  267. }""",
  268. {debugcapi:
  269. ' fprintf(stderr,"#showvalueformat#\\".\\n",return_value);'}
  270. ],
  271. 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
  272. 'string.h', 'GETSTRFROMPYTUPLE'],
  273. 'return': 'return;',
  274. '_check': isstringfunction
  275. },
  276. { # Complex function
  277. 'optargs': """
  278. #ifndef F2PY_CB_RETURNCOMPLEX
  279. #ctype# *return_value
  280. #endif
  281. """,
  282. 'optargs_nm': """
  283. #ifndef F2PY_CB_RETURNCOMPLEX
  284. return_value
  285. #endif
  286. """,
  287. 'optargs_td': """
  288. #ifndef F2PY_CB_RETURNCOMPLEX
  289. #ctype# *
  290. #endif
  291. """,
  292. 'decl': """
  293. #ifdef F2PY_CB_RETURNCOMPLEX
  294. #ctype# return_value = {0, 0};
  295. #endif
  296. """,
  297. 'frompyobj': [
  298. {debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
  299. """\
  300. if (capi_j>capi_i) {
  301. #ifdef F2PY_CB_RETURNCOMPLEX
  302. GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,
  303. \"#ctype#_from_pyobj failed in converting return_value of call-back\"
  304. \" function #name# to C #ctype#\\n\");
  305. #else
  306. GETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,
  307. \"#ctype#_from_pyobj failed in converting return_value of call-back\"
  308. \" function #name# to C #ctype#\\n\");
  309. #endif
  310. } else {
  311. fprintf(stderr,
  312. \"Warning: call-back function #name# did not provide\"
  313. \" return value (index=%d, type=#ctype#)\\n\",capi_i);
  314. }""",
  315. {debugcapi: """\
  316. #ifdef F2PY_CB_RETURNCOMPLEX
  317. fprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i);
  318. #else
  319. fprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i);
  320. #endif
  321. """}
  322. ],
  323. 'return': """
  324. #ifdef F2PY_CB_RETURNCOMPLEX
  325. return return_value;
  326. #else
  327. return;
  328. #endif
  329. """,
  330. 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
  331. 'string.h', 'GETSCALARFROMPYTUPLE', '#ctype#'],
  332. '_check': iscomplexfunction
  333. },
  334. {'docstrout': ' #pydocsignout#',
  335. 'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}',
  336. {hasnote: '--- #note#'}],
  337. 'docreturn': '#rname#,',
  338. '_check': isfunction},
  339. {'_check': issubroutine, 'return': 'return;'}
  340. ]
  341. cb_arg_rules = [
  342. { # Doc
  343. 'docstropt': {l_and(isoptional, isintent_nothide): ' #pydocsign#'},
  344. 'docstrreq': {l_and(isrequired, isintent_nothide): ' #pydocsign#'},
  345. 'docstrout': {isintent_out: ' #pydocsignout#'},
  346. 'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
  347. {hasnote: '--- #note#'}]},
  348. 'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
  349. {hasnote: '--- #note#'}]},
  350. 'latexdocstrout': {isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}',
  351. {l_and(hasnote, isintent_hide): '--- #note#',
  352. l_and(hasnote, isintent_nothide): '--- See above.'}]},
  353. 'docsign': {l_and(isrequired, isintent_nothide): '#varname#,'},
  354. 'docsignopt': {l_and(isoptional, isintent_nothide): '#varname#,'},
  355. 'depend': ''
  356. },
  357. {
  358. 'args': {
  359. l_and(isscalar, isintent_c): '#ctype# #varname_i#',
  360. l_and(isscalar, l_not(isintent_c)): '#ctype# *#varname_i#_cb_capi',
  361. isarray: '#ctype# *#varname_i#',
  362. isstring: '#ctype# #varname_i#'
  363. },
  364. 'args_nm': {
  365. l_and(isscalar, isintent_c): '#varname_i#',
  366. l_and(isscalar, l_not(isintent_c)): '#varname_i#_cb_capi',
  367. isarray: '#varname_i#',
  368. isstring: '#varname_i#'
  369. },
  370. 'args_td': {
  371. l_and(isscalar, isintent_c): '#ctype#',
  372. l_and(isscalar, l_not(isintent_c)): '#ctype# *',
  373. isarray: '#ctype# *',
  374. isstring: '#ctype#'
  375. },
  376. 'need': {l_or(isscalar, isarray, isstring): '#ctype#'},
  377. # untested with multiple args
  378. 'strarglens': {isstring: ',int #varname_i#_cb_len'},
  379. 'strarglens_td': {isstring: ',int'}, # untested with multiple args
  380. # untested with multiple args
  381. 'strarglens_nm': {isstring: ',#varname_i#_cb_len'},
  382. },
  383. { # Scalars
  384. 'decl': {l_not(isintent_c): ' #ctype# #varname_i#=(*#varname_i#_cb_capi);'},
  385. 'error': {l_and(isintent_c, isintent_out,
  386. throw_error('intent(c,out) is forbidden for callback scalar arguments')):
  387. ''},
  388. 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
  389. {isintent_out:
  390. ' if (capi_j>capi_i)\n GETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname_i#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'},
  391. {l_and(debugcapi, l_and(l_not(iscomplex), isintent_c)):
  392. ' fprintf(stderr,"#showvalueformat#.\\n",#varname_i#);'},
  393. {l_and(debugcapi, l_and(l_not(iscomplex), l_not(isintent_c))):
  394. ' fprintf(stderr,"#showvalueformat#.\\n",*#varname_i#_cb_capi);'},
  395. {l_and(debugcapi, l_and(iscomplex, isintent_c)):
  396. ' fprintf(stderr,"#showvalueformat#.\\n",(#varname_i#).r,(#varname_i#).i);'},
  397. {l_and(debugcapi, l_and(iscomplex, l_not(isintent_c))):
  398. ' fprintf(stderr,"#showvalueformat#.\\n",(*#varname_i#_cb_capi).r,(*#varname_i#_cb_capi).i);'},
  399. ],
  400. 'need': [{isintent_out: ['#ctype#_from_pyobj', 'GETSCALARFROMPYTUPLE']},
  401. {debugcapi: 'CFUNCSMESS'}],
  402. '_check': isscalar
  403. }, {
  404. 'pyobjfrom': [{isintent_in: """\
  405. if (cb->nofargs>capi_i)
  406. if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1(#varname_i#)))
  407. goto capi_fail;"""},
  408. {isintent_inout: """\
  409. if (cb->nofargs>capi_i)
  410. if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#_cb_capi)))
  411. goto capi_fail;"""}],
  412. 'need': [{isintent_in: 'pyobj_from_#ctype#1'},
  413. {isintent_inout: 'pyarr_from_p_#ctype#1'},
  414. {iscomplex: '#ctype#'}],
  415. '_check': l_and(isscalar, isintent_nothide),
  416. '_optional': ''
  417. }, { # String
  418. 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->\\"");'},
  419. """ if (capi_j>capi_i)
  420. GETSTRFROMPYTUPLE(capi_return,capi_i++,#varname_i#,#varname_i#_cb_len);""",
  421. {debugcapi:
  422. ' fprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname_i#,#varname_i#_cb_len);'},
  423. ],
  424. 'need': ['#ctype#', 'GETSTRFROMPYTUPLE',
  425. {debugcapi: 'CFUNCSMESS'}, 'string.h'],
  426. '_check': l_and(isstring, isintent_out)
  427. }, {
  428. 'pyobjfrom': [
  429. {debugcapi:
  430. (' fprintf(stderr,"debug-capi:cb:#varname#=#showvalueformat#:'
  431. '%d:\\n",#varname_i#,#varname_i#_cb_len);')},
  432. {isintent_in: """\
  433. if (cb->nofargs>capi_i)
  434. if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1size(#varname_i#,#varname_i#_cb_len)))
  435. goto capi_fail;"""},
  436. {isintent_inout: """\
  437. if (cb->nofargs>capi_i) {
  438. int #varname_i#_cb_dims[] = {#varname_i#_cb_len};
  439. if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#,#varname_i#_cb_dims)))
  440. goto capi_fail;
  441. }"""}],
  442. 'need': [{isintent_in: 'pyobj_from_#ctype#1size'},
  443. {isintent_inout: 'pyarr_from_p_#ctype#1'}],
  444. '_check': l_and(isstring, isintent_nothide),
  445. '_optional': ''
  446. },
  447. # Array ...
  448. {
  449. 'decl': ' npy_intp #varname_i#_Dims[#rank#] = {#rank*[-1]#};',
  450. 'setdims': ' #cbsetdims#;',
  451. '_check': isarray,
  452. '_depend': ''
  453. },
  454. {
  455. 'pyobjfrom': [{debugcapi: ' fprintf(stderr,"debug-capi:cb:#varname#\\n");'},
  456. {isintent_c: """\
  457. if (cb->nofargs>capi_i) {
  458. /* tmp_arr will be inserted to capi_arglist_list that will be
  459. destroyed when leaving callback function wrapper together
  460. with tmp_arr. */
  461. PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,
  462. #rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,#elsize#,
  463. NPY_ARRAY_CARRAY,NULL);
  464. """,
  465. l_not(isintent_c): """\
  466. if (cb->nofargs>capi_i) {
  467. /* tmp_arr will be inserted to capi_arglist_list that will be
  468. destroyed when leaving callback function wrapper together
  469. with tmp_arr. */
  470. PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,
  471. #rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,#elsize#,
  472. NPY_ARRAY_FARRAY,NULL);
  473. """,
  474. },
  475. """
  476. if (tmp_arr==NULL)
  477. goto capi_fail;
  478. if (CAPI_ARGLIST_SETITEM(capi_i++,(PyObject *)tmp_arr))
  479. goto capi_fail;
  480. }"""],
  481. '_check': l_and(isarray, isintent_nothide, l_or(isintent_in, isintent_inout)),
  482. '_optional': '',
  483. }, {
  484. 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
  485. """ if (capi_j>capi_i) {
  486. PyArrayObject *rv_cb_arr = NULL;
  487. if ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail;
  488. rv_cb_arr = array_from_pyobj(#atype#,#varname_i#_Dims,#rank#,F2PY_INTENT_IN""",
  489. {isintent_c: '|F2PY_INTENT_C'},
  490. """,capi_tmp);
  491. if (rv_cb_arr == NULL) {
  492. fprintf(stderr,\"rv_cb_arr is NULL\\n\");
  493. goto capi_fail;
  494. }
  495. MEMCOPY(#varname_i#,PyArray_DATA(rv_cb_arr),PyArray_NBYTES(rv_cb_arr));
  496. if (capi_tmp != (PyObject *)rv_cb_arr) {
  497. Py_DECREF(rv_cb_arr);
  498. }
  499. }""",
  500. {debugcapi: ' fprintf(stderr,"<-.\\n");'},
  501. ],
  502. 'need': ['MEMCOPY', {iscomplexarray: '#ctype#'}],
  503. '_check': l_and(isarray, isintent_out)
  504. }, {
  505. 'docreturn': '#varname#,',
  506. '_check': isintent_out
  507. }
  508. ]
  509. ################## Build call-back module #############
  510. cb_map = {}
  511. def buildcallbacks(m):
  512. cb_map[m['name']] = []
  513. for bi in m['body']:
  514. if bi['block'] == 'interface':
  515. for b in bi['body']:
  516. if b:
  517. buildcallback(b, m['name'])
  518. else:
  519. errmess(f"warning: empty body for {m['name']}\n")
  520. def buildcallback(rout, um):
  521. from . import capi_maps
  522. outmess(f" Constructing call-back function \"cb_{rout['name']}_in_{um}\"\n")
  523. args, depargs = getargs(rout)
  524. capi_maps.depargs = depargs
  525. var = rout['vars']
  526. vrd = capi_maps.cb_routsign2map(rout, um)
  527. rd = dictappend({}, vrd)
  528. cb_map[um].append([rout['name'], rd['name']])
  529. for r in cb_rout_rules:
  530. if ('_check' in r and r['_check'](rout)) or ('_check' not in r):
  531. ar = applyrules(r, vrd, rout)
  532. rd = dictappend(rd, ar)
  533. savevrd = {}
  534. for i, a in enumerate(args):
  535. vrd = capi_maps.cb_sign2map(a, var[a], index=i)
  536. savevrd[a] = vrd
  537. for r in cb_arg_rules:
  538. if '_depend' in r:
  539. continue
  540. if '_optional' in r and isoptional(var[a]):
  541. continue
  542. if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
  543. ar = applyrules(r, vrd, var[a])
  544. rd = dictappend(rd, ar)
  545. if '_break' in r:
  546. break
  547. for a in args:
  548. vrd = savevrd[a]
  549. for r in cb_arg_rules:
  550. if '_depend' in r:
  551. continue
  552. if ('_optional' not in r) or ('_optional' in r and isrequired(var[a])):
  553. continue
  554. if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
  555. ar = applyrules(r, vrd, var[a])
  556. rd = dictappend(rd, ar)
  557. if '_break' in r:
  558. break
  559. for a in depargs:
  560. vrd = savevrd[a]
  561. for r in cb_arg_rules:
  562. if '_depend' not in r:
  563. continue
  564. if '_optional' in r:
  565. continue
  566. if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
  567. ar = applyrules(r, vrd, var[a])
  568. rd = dictappend(rd, ar)
  569. if '_break' in r:
  570. break
  571. if 'args' in rd and 'optargs' in rd:
  572. if isinstance(rd['optargs'], list):
  573. rd['optargs'] = rd['optargs'] + ["""
  574. #ifndef F2PY_CB_RETURNCOMPLEX
  575. ,
  576. #endif
  577. """]
  578. rd['optargs_nm'] = rd['optargs_nm'] + ["""
  579. #ifndef F2PY_CB_RETURNCOMPLEX
  580. ,
  581. #endif
  582. """]
  583. rd['optargs_td'] = rd['optargs_td'] + ["""
  584. #ifndef F2PY_CB_RETURNCOMPLEX
  585. ,
  586. #endif
  587. """]
  588. if isinstance(rd['docreturn'], list):
  589. rd['docreturn'] = stripcomma(
  590. replace('#docreturn#', {'docreturn': rd['docreturn']}))
  591. optargs = stripcomma(replace('#docsignopt#',
  592. {'docsignopt': rd['docsignopt']}
  593. ))
  594. if optargs == '':
  595. rd['docsignature'] = stripcomma(
  596. replace('#docsign#', {'docsign': rd['docsign']}))
  597. else:
  598. rd['docsignature'] = replace('#docsign#[#docsignopt#]',
  599. {'docsign': rd['docsign'],
  600. 'docsignopt': optargs,
  601. })
  602. rd['latexdocsignature'] = rd['docsignature'].replace('_', '\\_')
  603. rd['latexdocsignature'] = rd['latexdocsignature'].replace(',', ', ')
  604. rd['docstrsigns'] = []
  605. rd['latexdocstrsigns'] = []
  606. for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']:
  607. if k in rd and isinstance(rd[k], list):
  608. rd['docstrsigns'] = rd['docstrsigns'] + rd[k]
  609. k = 'latex' + k
  610. if k in rd and isinstance(rd[k], list):
  611. rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\
  612. ['\\begin{description}'] + rd[k][1:] +\
  613. ['\\end{description}']
  614. if 'args' not in rd:
  615. rd['args'] = ''
  616. rd['args_td'] = ''
  617. rd['args_nm'] = ''
  618. if not (rd.get('args') or rd.get('optargs') or rd.get('strarglens')):
  619. rd['noargs'] = 'void'
  620. ar = applyrules(cb_routine_rules, rd)
  621. cfuncs.callbacks[rd['name']] = ar['body']
  622. if isinstance(ar['need'], str):
  623. ar['need'] = [ar['need']]
  624. if 'need' in rd:
  625. for t in cfuncs.typedefs.keys():
  626. if t in rd['need']:
  627. ar['need'].append(t)
  628. cfuncs.typedefs_generated[rd['name'] + '_typedef'] = ar['cbtypedefs']
  629. ar['need'].append(rd['name'] + '_typedef')
  630. cfuncs.needs[rd['name']] = ar['need']
  631. capi_maps.lcb2_map[rd['name']] = {'maxnofargs': ar['maxnofargs'],
  632. 'nofoptargs': ar['nofoptargs'],
  633. 'docstr': ar['docstr'],
  634. 'latexdocstr': ar['latexdocstr'],
  635. 'argname': rd['argname']
  636. }
  637. outmess(f" {ar['docstrshort']}\n")
  638. ################## Build call-back function #############