capi_maps.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. #!/usr/bin/env python3
  2. """
  3. Copyright 1999,2000 Pearu Peterson all rights reserved,
  4. Pearu Peterson <pearu@ioc.ee>
  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. $Date: 2005/05/06 10:57:33 $
  9. Pearu Peterson
  10. """
  11. from . import __version__
  12. f2py_version = __version__.version
  13. import copy
  14. import re
  15. import os
  16. from .crackfortran import markoutercomma
  17. from . import cb_rules
  18. # The environment provided by auxfuncs.py is needed for some calls to eval.
  19. # As the needed functions cannot be determined by static inspection of the
  20. # code, it is safest to use import * pending a major refactoring of f2py.
  21. from .auxfuncs import *
  22. __all__ = [
  23. 'getctype', 'getstrlength', 'getarrdims', 'getpydocsign',
  24. 'getarrdocsign', 'getinit', 'sign2map', 'routsign2map', 'modsign2map',
  25. 'cb_sign2map', 'cb_routsign2map', 'common_sign2map'
  26. ]
  27. # Numarray and Numeric users should set this False
  28. using_newcore = True
  29. depargs = []
  30. lcb_map = {}
  31. lcb2_map = {}
  32. # forced casting: mainly caused by the fact that Python or Numeric
  33. # C/APIs do not support the corresponding C types.
  34. c2py_map = {'double': 'float',
  35. 'float': 'float', # forced casting
  36. 'long_double': 'float', # forced casting
  37. 'char': 'int', # forced casting
  38. 'signed_char': 'int', # forced casting
  39. 'unsigned_char': 'int', # forced casting
  40. 'short': 'int', # forced casting
  41. 'unsigned_short': 'int', # forced casting
  42. 'int': 'int', # forced casting
  43. 'long': 'int',
  44. 'long_long': 'long',
  45. 'unsigned': 'int', # forced casting
  46. 'complex_float': 'complex', # forced casting
  47. 'complex_double': 'complex',
  48. 'complex_long_double': 'complex', # forced casting
  49. 'string': 'string',
  50. 'character': 'bytes',
  51. }
  52. c2capi_map = {'double': 'NPY_DOUBLE',
  53. 'float': 'NPY_FLOAT',
  54. 'long_double': 'NPY_DOUBLE', # forced casting
  55. 'char': 'NPY_STRING',
  56. 'unsigned_char': 'NPY_UBYTE',
  57. 'signed_char': 'NPY_BYTE',
  58. 'short': 'NPY_SHORT',
  59. 'unsigned_short': 'NPY_USHORT',
  60. 'int': 'NPY_INT',
  61. 'unsigned': 'NPY_UINT',
  62. 'long': 'NPY_LONG',
  63. 'long_long': 'NPY_LONG', # forced casting
  64. 'complex_float': 'NPY_CFLOAT',
  65. 'complex_double': 'NPY_CDOUBLE',
  66. 'complex_long_double': 'NPY_CDOUBLE', # forced casting
  67. 'string': 'NPY_STRING',
  68. 'character': 'NPY_CHAR'}
  69. # These new maps aren't used anywhere yet, but should be by default
  70. # unless building numeric or numarray extensions.
  71. if using_newcore:
  72. c2capi_map = {'double': 'NPY_DOUBLE',
  73. 'float': 'NPY_FLOAT',
  74. 'long_double': 'NPY_LONGDOUBLE',
  75. 'char': 'NPY_BYTE',
  76. 'unsigned_char': 'NPY_UBYTE',
  77. 'signed_char': 'NPY_BYTE',
  78. 'short': 'NPY_SHORT',
  79. 'unsigned_short': 'NPY_USHORT',
  80. 'int': 'NPY_INT',
  81. 'unsigned': 'NPY_UINT',
  82. 'long': 'NPY_LONG',
  83. 'unsigned_long': 'NPY_ULONG',
  84. 'long_long': 'NPY_LONGLONG',
  85. 'unsigned_long_long': 'NPY_ULONGLONG',
  86. 'complex_float': 'NPY_CFLOAT',
  87. 'complex_double': 'NPY_CDOUBLE',
  88. 'complex_long_double': 'NPY_CDOUBLE',
  89. 'string': 'NPY_STRING',
  90. 'character': 'NPY_STRING'}
  91. c2pycode_map = {'double': 'd',
  92. 'float': 'f',
  93. 'long_double': 'd', # forced casting
  94. 'char': '1',
  95. 'signed_char': '1',
  96. 'unsigned_char': 'b',
  97. 'short': 's',
  98. 'unsigned_short': 'w',
  99. 'int': 'i',
  100. 'unsigned': 'u',
  101. 'long': 'l',
  102. 'long_long': 'L',
  103. 'complex_float': 'F',
  104. 'complex_double': 'D',
  105. 'complex_long_double': 'D', # forced casting
  106. 'string': 'c',
  107. 'character': 'c'
  108. }
  109. if using_newcore:
  110. c2pycode_map = {'double': 'd',
  111. 'float': 'f',
  112. 'long_double': 'g',
  113. 'char': 'b',
  114. 'unsigned_char': 'B',
  115. 'signed_char': 'b',
  116. 'short': 'h',
  117. 'unsigned_short': 'H',
  118. 'int': 'i',
  119. 'unsigned': 'I',
  120. 'long': 'l',
  121. 'unsigned_long': 'L',
  122. 'long_long': 'q',
  123. 'unsigned_long_long': 'Q',
  124. 'complex_float': 'F',
  125. 'complex_double': 'D',
  126. 'complex_long_double': 'G',
  127. 'string': 'S',
  128. 'character': 'c'}
  129. # https://docs.python.org/3/c-api/arg.html#building-values
  130. # c2buildvalue_map is NumPy agnostic, so no need to bother with using_newcore
  131. c2buildvalue_map = {'double': 'd',
  132. 'float': 'f',
  133. 'char': 'b',
  134. 'signed_char': 'b',
  135. 'short': 'h',
  136. 'int': 'i',
  137. 'long': 'l',
  138. 'long_long': 'L',
  139. 'complex_float': 'N',
  140. 'complex_double': 'N',
  141. 'complex_long_double': 'N',
  142. 'string': 'y',
  143. 'character': 'c'}
  144. f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
  145. '12': 'long_double', '16': 'long_double'},
  146. 'integer': {'': 'int', '1': 'signed_char', '2': 'short',
  147. '4': 'int', '8': 'long_long',
  148. '-1': 'unsigned_char', '-2': 'unsigned_short',
  149. '-4': 'unsigned', '-8': 'unsigned_long_long'},
  150. 'complex': {'': 'complex_float', '8': 'complex_float',
  151. '16': 'complex_double', '24': 'complex_long_double',
  152. '32': 'complex_long_double'},
  153. 'complexkind': {'': 'complex_float', '4': 'complex_float',
  154. '8': 'complex_double', '12': 'complex_long_double',
  155. '16': 'complex_long_double'},
  156. 'logical': {'': 'int', '1': 'char', '2': 'short', '4': 'int',
  157. '8': 'long_long'},
  158. 'double complex': {'': 'complex_double'},
  159. 'double precision': {'': 'double'},
  160. 'byte': {'': 'char'},
  161. }
  162. f2cmap_default = copy.deepcopy(f2cmap_all)
  163. f2cmap_mapped = []
  164. def load_f2cmap_file(f2cmap_file):
  165. global f2cmap_all
  166. f2cmap_all = copy.deepcopy(f2cmap_default)
  167. if f2cmap_file is None:
  168. # Default value
  169. f2cmap_file = '.f2py_f2cmap'
  170. if not os.path.isfile(f2cmap_file):
  171. return
  172. # User defined additions to f2cmap_all.
  173. # f2cmap_file must contain a dictionary of dictionaries, only. For
  174. # example, {'real':{'low':'float'}} means that Fortran 'real(low)' is
  175. # interpreted as C 'float'. This feature is useful for F90/95 users if
  176. # they use PARAMETERS in type specifications.
  177. try:
  178. outmess('Reading f2cmap from {!r} ...\n'.format(f2cmap_file))
  179. with open(f2cmap_file, 'r') as f:
  180. d = eval(f.read().lower(), {}, {})
  181. for k, d1 in d.items():
  182. for k1 in d1.keys():
  183. d1[k1.lower()] = d1[k1]
  184. d[k.lower()] = d[k]
  185. for k in d.keys():
  186. if k not in f2cmap_all:
  187. f2cmap_all[k] = {}
  188. for k1 in d[k].keys():
  189. if d[k][k1] in c2py_map:
  190. if k1 in f2cmap_all[k]:
  191. outmess(
  192. "\tWarning: redefinition of {'%s':{'%s':'%s'->'%s'}}\n" % (k, k1, f2cmap_all[k][k1], d[k][k1]))
  193. f2cmap_all[k][k1] = d[k][k1]
  194. outmess('\tMapping "%s(kind=%s)" to "%s"\n' %
  195. (k, k1, d[k][k1]))
  196. f2cmap_mapped.append(d[k][k1])
  197. else:
  198. errmess("\tIgnoring map {'%s':{'%s':'%s'}}: '%s' must be in %s\n" % (
  199. k, k1, d[k][k1], d[k][k1], list(c2py_map.keys())))
  200. outmess('Successfully applied user defined f2cmap changes\n')
  201. except Exception as msg:
  202. errmess(
  203. 'Failed to apply user defined f2cmap changes: %s. Skipping.\n' % (msg))
  204. cformat_map = {'double': '%g',
  205. 'float': '%g',
  206. 'long_double': '%Lg',
  207. 'char': '%d',
  208. 'signed_char': '%d',
  209. 'unsigned_char': '%hhu',
  210. 'short': '%hd',
  211. 'unsigned_short': '%hu',
  212. 'int': '%d',
  213. 'unsigned': '%u',
  214. 'long': '%ld',
  215. 'unsigned_long': '%lu',
  216. 'long_long': '%ld',
  217. 'complex_float': '(%g,%g)',
  218. 'complex_double': '(%g,%g)',
  219. 'complex_long_double': '(%Lg,%Lg)',
  220. 'string': '\\"%s\\"',
  221. 'character': "'%c'",
  222. }
  223. # Auxiliary functions
  224. def getctype(var):
  225. """
  226. Determines C type
  227. """
  228. ctype = 'void'
  229. if isfunction(var):
  230. if 'result' in var:
  231. a = var['result']
  232. else:
  233. a = var['name']
  234. if a in var['vars']:
  235. return getctype(var['vars'][a])
  236. else:
  237. errmess('getctype: function %s has no return value?!\n' % a)
  238. elif issubroutine(var):
  239. return ctype
  240. elif ischaracter_or_characterarray(var):
  241. return 'character'
  242. elif isstring_or_stringarray(var):
  243. return 'string'
  244. elif 'typespec' in var and var['typespec'].lower() in f2cmap_all:
  245. typespec = var['typespec'].lower()
  246. f2cmap = f2cmap_all[typespec]
  247. ctype = f2cmap[''] # default type
  248. if 'kindselector' in var:
  249. if '*' in var['kindselector']:
  250. try:
  251. ctype = f2cmap[var['kindselector']['*']]
  252. except KeyError:
  253. errmess('getctype: "%s %s %s" not supported.\n' %
  254. (var['typespec'], '*', var['kindselector']['*']))
  255. elif 'kind' in var['kindselector']:
  256. if typespec + 'kind' in f2cmap_all:
  257. f2cmap = f2cmap_all[typespec + 'kind']
  258. try:
  259. ctype = f2cmap[var['kindselector']['kind']]
  260. except KeyError:
  261. if typespec in f2cmap_all:
  262. f2cmap = f2cmap_all[typespec]
  263. try:
  264. ctype = f2cmap[str(var['kindselector']['kind'])]
  265. except KeyError:
  266. errmess('getctype: "%s(kind=%s)" is mapped to C "%s" (to override define dict(%s = dict(%s="<C typespec>")) in %s/.f2py_f2cmap file).\n'
  267. % (typespec, var['kindselector']['kind'], ctype,
  268. typespec, var['kindselector']['kind'], os.getcwd()))
  269. else:
  270. if not isexternal(var):
  271. errmess('getctype: No C-type found in "%s", assuming void.\n' % var)
  272. return ctype
  273. def f2cexpr(expr):
  274. """Rewrite Fortran expression as f2py supported C expression.
  275. Due to the lack of a proper expression parser in f2py, this
  276. function uses a heuristic approach that assumes that Fortran
  277. arithmetic expressions are valid C arithmetic expressions when
  278. mapping Fortran function calls to the corresponding C function/CPP
  279. macros calls.
  280. """
  281. # TODO: support Fortran `len` function with optional kind parameter
  282. expr = re.sub(r'\blen\b', 'f2py_slen', expr)
  283. return expr
  284. def getstrlength(var):
  285. if isstringfunction(var):
  286. if 'result' in var:
  287. a = var['result']
  288. else:
  289. a = var['name']
  290. if a in var['vars']:
  291. return getstrlength(var['vars'][a])
  292. else:
  293. errmess('getstrlength: function %s has no return value?!\n' % a)
  294. if not isstring(var):
  295. errmess(
  296. 'getstrlength: expected a signature of a string but got: %s\n' % (repr(var)))
  297. len = '1'
  298. if 'charselector' in var:
  299. a = var['charselector']
  300. if '*' in a:
  301. len = a['*']
  302. elif 'len' in a:
  303. len = f2cexpr(a['len'])
  304. if re.match(r'\(\s*(\*|:)\s*\)', len) or re.match(r'(\*|:)', len):
  305. if isintent_hide(var):
  306. errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n' % (
  307. repr(var)))
  308. len = '-1'
  309. return len
  310. def getarrdims(a, var, verbose=0):
  311. ret = {}
  312. if isstring(var) and not isarray(var):
  313. ret['size'] = getstrlength(var)
  314. ret['rank'] = '0'
  315. ret['dims'] = ''
  316. elif isscalar(var):
  317. ret['size'] = '1'
  318. ret['rank'] = '0'
  319. ret['dims'] = ''
  320. elif isarray(var):
  321. dim = copy.copy(var['dimension'])
  322. ret['size'] = '*'.join(dim)
  323. try:
  324. ret['size'] = repr(eval(ret['size']))
  325. except Exception:
  326. pass
  327. ret['dims'] = ','.join(dim)
  328. ret['rank'] = repr(len(dim))
  329. ret['rank*[-1]'] = repr(len(dim) * [-1])[1:-1]
  330. for i in range(len(dim)): # solve dim for dependencies
  331. v = []
  332. if dim[i] in depargs:
  333. v = [dim[i]]
  334. else:
  335. for va in depargs:
  336. if re.match(r'.*?\b%s\b.*' % va, dim[i]):
  337. v.append(va)
  338. for va in v:
  339. if depargs.index(va) > depargs.index(a):
  340. dim[i] = '*'
  341. break
  342. ret['setdims'], i = '', -1
  343. for d in dim:
  344. i = i + 1
  345. if d not in ['*', ':', '(*)', '(:)']:
  346. ret['setdims'] = '%s#varname#_Dims[%d]=%s,' % (
  347. ret['setdims'], i, d)
  348. if ret['setdims']:
  349. ret['setdims'] = ret['setdims'][:-1]
  350. ret['cbsetdims'], i = '', -1
  351. for d in var['dimension']:
  352. i = i + 1
  353. if d not in ['*', ':', '(*)', '(:)']:
  354. ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
  355. ret['cbsetdims'], i, d)
  356. elif isintent_in(var):
  357. outmess('getarrdims:warning: assumed shape array, using 0 instead of %r\n'
  358. % (d))
  359. ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
  360. ret['cbsetdims'], i, 0)
  361. elif verbose:
  362. errmess(
  363. 'getarrdims: If in call-back function: array argument %s must have bounded dimensions: got %s\n' % (repr(a), repr(d)))
  364. if ret['cbsetdims']:
  365. ret['cbsetdims'] = ret['cbsetdims'][:-1]
  366. # if not isintent_c(var):
  367. # var['dimension'].reverse()
  368. return ret
  369. def getpydocsign(a, var):
  370. global lcb_map
  371. if isfunction(var):
  372. if 'result' in var:
  373. af = var['result']
  374. else:
  375. af = var['name']
  376. if af in var['vars']:
  377. return getpydocsign(af, var['vars'][af])
  378. else:
  379. errmess('getctype: function %s has no return value?!\n' % af)
  380. return '', ''
  381. sig, sigout = a, a
  382. opt = ''
  383. if isintent_in(var):
  384. opt = 'input'
  385. elif isintent_inout(var):
  386. opt = 'in/output'
  387. out_a = a
  388. if isintent_out(var):
  389. for k in var['intent']:
  390. if k[:4] == 'out=':
  391. out_a = k[4:]
  392. break
  393. init = ''
  394. ctype = getctype(var)
  395. if hasinitvalue(var):
  396. init, showinit = getinit(a, var)
  397. init = ', optional\\n Default: %s' % showinit
  398. if isscalar(var):
  399. if isintent_inout(var):
  400. sig = '%s : %s rank-0 array(%s,\'%s\')%s' % (a, opt, c2py_map[ctype],
  401. c2pycode_map[ctype], init)
  402. else:
  403. sig = '%s : %s %s%s' % (a, opt, c2py_map[ctype], init)
  404. sigout = '%s : %s' % (out_a, c2py_map[ctype])
  405. elif isstring(var):
  406. if isintent_inout(var):
  407. sig = '%s : %s rank-0 array(string(len=%s),\'c\')%s' % (
  408. a, opt, getstrlength(var), init)
  409. else:
  410. sig = '%s : %s string(len=%s)%s' % (
  411. a, opt, getstrlength(var), init)
  412. sigout = '%s : string(len=%s)' % (out_a, getstrlength(var))
  413. elif isarray(var):
  414. dim = var['dimension']
  415. rank = repr(len(dim))
  416. sig = '%s : %s rank-%s array(\'%s\') with bounds (%s)%s' % (a, opt, rank,
  417. c2pycode_map[
  418. ctype],
  419. ','.join(dim), init)
  420. if a == out_a:
  421. sigout = '%s : rank-%s array(\'%s\') with bounds (%s)'\
  422. % (a, rank, c2pycode_map[ctype], ','.join(dim))
  423. else:
  424. sigout = '%s : rank-%s array(\'%s\') with bounds (%s) and %s storage'\
  425. % (out_a, rank, c2pycode_map[ctype], ','.join(dim), a)
  426. elif isexternal(var):
  427. ua = ''
  428. if a in lcb_map and lcb_map[a] in lcb2_map and 'argname' in lcb2_map[lcb_map[a]]:
  429. ua = lcb2_map[lcb_map[a]]['argname']
  430. if not ua == a:
  431. ua = ' => %s' % ua
  432. else:
  433. ua = ''
  434. sig = '%s : call-back function%s' % (a, ua)
  435. sigout = sig
  436. else:
  437. errmess(
  438. 'getpydocsign: Could not resolve docsignature for "%s".\n' % a)
  439. return sig, sigout
  440. def getarrdocsign(a, var):
  441. ctype = getctype(var)
  442. if isstring(var) and (not isarray(var)):
  443. sig = '%s : rank-0 array(string(len=%s),\'c\')' % (a,
  444. getstrlength(var))
  445. elif isscalar(var):
  446. sig = '%s : rank-0 array(%s,\'%s\')' % (a, c2py_map[ctype],
  447. c2pycode_map[ctype],)
  448. elif isarray(var):
  449. dim = var['dimension']
  450. rank = repr(len(dim))
  451. sig = '%s : rank-%s array(\'%s\') with bounds (%s)' % (a, rank,
  452. c2pycode_map[
  453. ctype],
  454. ','.join(dim))
  455. return sig
  456. def getinit(a, var):
  457. if isstring(var):
  458. init, showinit = '""', "''"
  459. else:
  460. init, showinit = '', ''
  461. if hasinitvalue(var):
  462. init = var['=']
  463. showinit = init
  464. if iscomplex(var) or iscomplexarray(var):
  465. ret = {}
  466. try:
  467. v = var["="]
  468. if ',' in v:
  469. ret['init.r'], ret['init.i'] = markoutercomma(
  470. v[1:-1]).split('@,@')
  471. else:
  472. v = eval(v, {}, {})
  473. ret['init.r'], ret['init.i'] = str(v.real), str(v.imag)
  474. except Exception:
  475. raise ValueError(
  476. 'getinit: expected complex number `(r,i)\' but got `%s\' as initial value of %r.' % (init, a))
  477. if isarray(var):
  478. init = '(capi_c.r=%s,capi_c.i=%s,capi_c)' % (
  479. ret['init.r'], ret['init.i'])
  480. elif isstring(var):
  481. if not init:
  482. init, showinit = '""', "''"
  483. if init[0] == "'":
  484. init = '"%s"' % (init[1:-1].replace('"', '\\"'))
  485. if init[0] == '"':
  486. showinit = "'%s'" % (init[1:-1])
  487. return init, showinit
  488. def get_elsize(var):
  489. if isstring(var) or isstringarray(var):
  490. elsize = getstrlength(var)
  491. # override with user-specified length when available:
  492. elsize = var['charselector'].get('f2py_len', elsize)
  493. return elsize
  494. if ischaracter(var) or ischaracterarray(var):
  495. return '1'
  496. # for numerical types, PyArray_New* functions ignore specified
  497. # elsize, so we just return 1 and let elsize be determined at
  498. # runtime, see fortranobject.c
  499. return '1'
  500. def sign2map(a, var):
  501. """
  502. varname,ctype,atype
  503. init,init.r,init.i,pytype
  504. vardebuginfo,vardebugshowvalue,varshowvalue
  505. varrformat
  506. intent
  507. """
  508. out_a = a
  509. if isintent_out(var):
  510. for k in var['intent']:
  511. if k[:4] == 'out=':
  512. out_a = k[4:]
  513. break
  514. ret = {'varname': a, 'outvarname': out_a, 'ctype': getctype(var)}
  515. intent_flags = []
  516. for f, s in isintent_dict.items():
  517. if f(var):
  518. intent_flags.append('F2PY_%s' % s)
  519. if intent_flags:
  520. # TODO: Evaluate intent_flags here.
  521. ret['intent'] = '|'.join(intent_flags)
  522. else:
  523. ret['intent'] = 'F2PY_INTENT_IN'
  524. if isarray(var):
  525. ret['varrformat'] = 'N'
  526. elif ret['ctype'] in c2buildvalue_map:
  527. ret['varrformat'] = c2buildvalue_map[ret['ctype']]
  528. else:
  529. ret['varrformat'] = 'O'
  530. ret['init'], ret['showinit'] = getinit(a, var)
  531. if hasinitvalue(var) and iscomplex(var) and not isarray(var):
  532. ret['init.r'], ret['init.i'] = markoutercomma(
  533. ret['init'][1:-1]).split('@,@')
  534. if isexternal(var):
  535. ret['cbnamekey'] = a
  536. if a in lcb_map:
  537. ret['cbname'] = lcb_map[a]
  538. ret['maxnofargs'] = lcb2_map[lcb_map[a]]['maxnofargs']
  539. ret['nofoptargs'] = lcb2_map[lcb_map[a]]['nofoptargs']
  540. ret['cbdocstr'] = lcb2_map[lcb_map[a]]['docstr']
  541. ret['cblatexdocstr'] = lcb2_map[lcb_map[a]]['latexdocstr']
  542. else:
  543. ret['cbname'] = a
  544. errmess('sign2map: Confused: external %s is not in lcb_map%s.\n' % (
  545. a, list(lcb_map.keys())))
  546. if isstring(var):
  547. ret['length'] = getstrlength(var)
  548. if isarray(var):
  549. ret = dictappend(ret, getarrdims(a, var))
  550. dim = copy.copy(var['dimension'])
  551. if ret['ctype'] in c2capi_map:
  552. ret['atype'] = c2capi_map[ret['ctype']]
  553. ret['elsize'] = get_elsize(var)
  554. # Debug info
  555. if debugcapi(var):
  556. il = [isintent_in, 'input', isintent_out, 'output',
  557. isintent_inout, 'inoutput', isrequired, 'required',
  558. isoptional, 'optional', isintent_hide, 'hidden',
  559. iscomplex, 'complex scalar',
  560. l_and(isscalar, l_not(iscomplex)), 'scalar',
  561. isstring, 'string', isarray, 'array',
  562. iscomplexarray, 'complex array', isstringarray, 'string array',
  563. iscomplexfunction, 'complex function',
  564. l_and(isfunction, l_not(iscomplexfunction)), 'function',
  565. isexternal, 'callback',
  566. isintent_callback, 'callback',
  567. isintent_aux, 'auxiliary',
  568. ]
  569. rl = []
  570. for i in range(0, len(il), 2):
  571. if il[i](var):
  572. rl.append(il[i + 1])
  573. if isstring(var):
  574. rl.append('slen(%s)=%s' % (a, ret['length']))
  575. if isarray(var):
  576. ddim = ','.join(
  577. map(lambda x, y: '%s|%s' % (x, y), var['dimension'], dim))
  578. rl.append('dims(%s)' % ddim)
  579. if isexternal(var):
  580. ret['vardebuginfo'] = 'debug-capi:%s=>%s:%s' % (
  581. a, ret['cbname'], ','.join(rl))
  582. else:
  583. ret['vardebuginfo'] = 'debug-capi:%s %s=%s:%s' % (
  584. ret['ctype'], a, ret['showinit'], ','.join(rl))
  585. if isscalar(var):
  586. if ret['ctype'] in cformat_map:
  587. ret['vardebugshowvalue'] = 'debug-capi:%s=%s' % (
  588. a, cformat_map[ret['ctype']])
  589. if isstring(var):
  590. ret['vardebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
  591. a, a)
  592. if isexternal(var):
  593. ret['vardebugshowvalue'] = 'debug-capi:%s=%%p' % (a)
  594. if ret['ctype'] in cformat_map:
  595. ret['varshowvalue'] = '#name#:%s=%s' % (a, cformat_map[ret['ctype']])
  596. ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
  597. if isstring(var):
  598. ret['varshowvalue'] = '#name#:slen(%s)=%%d %s=\\"%%s\\"' % (a, a)
  599. ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
  600. if hasnote(var):
  601. ret['note'] = var['note']
  602. return ret
  603. def routsign2map(rout):
  604. """
  605. name,NAME,begintitle,endtitle
  606. rname,ctype,rformat
  607. routdebugshowvalue
  608. """
  609. global lcb_map
  610. name = rout['name']
  611. fname = getfortranname(rout)
  612. ret = {'name': name,
  613. 'texname': name.replace('_', '\\_'),
  614. 'name_lower': name.lower(),
  615. 'NAME': name.upper(),
  616. 'begintitle': gentitle(name),
  617. 'endtitle': gentitle('end of %s' % name),
  618. 'fortranname': fname,
  619. 'FORTRANNAME': fname.upper(),
  620. 'callstatement': getcallstatement(rout) or '',
  621. 'usercode': getusercode(rout) or '',
  622. 'usercode1': getusercode1(rout) or '',
  623. }
  624. if '_' in fname:
  625. ret['F_FUNC'] = 'F_FUNC_US'
  626. else:
  627. ret['F_FUNC'] = 'F_FUNC'
  628. if '_' in name:
  629. ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC_US'
  630. else:
  631. ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC'
  632. lcb_map = {}
  633. if 'use' in rout:
  634. for u in rout['use'].keys():
  635. if u in cb_rules.cb_map:
  636. for un in cb_rules.cb_map[u]:
  637. ln = un[0]
  638. if 'map' in rout['use'][u]:
  639. for k in rout['use'][u]['map'].keys():
  640. if rout['use'][u]['map'][k] == un[0]:
  641. ln = k
  642. break
  643. lcb_map[ln] = un[1]
  644. elif 'externals' in rout and rout['externals']:
  645. errmess('routsign2map: Confused: function %s has externals %s but no "use" statement.\n' % (
  646. ret['name'], repr(rout['externals'])))
  647. ret['callprotoargument'] = getcallprotoargument(rout, lcb_map) or ''
  648. if isfunction(rout):
  649. if 'result' in rout:
  650. a = rout['result']
  651. else:
  652. a = rout['name']
  653. ret['rname'] = a
  654. ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
  655. ret['ctype'] = getctype(rout['vars'][a])
  656. if hasresultnote(rout):
  657. ret['resultnote'] = rout['vars'][a]['note']
  658. rout['vars'][a]['note'] = ['See elsewhere.']
  659. if ret['ctype'] in c2buildvalue_map:
  660. ret['rformat'] = c2buildvalue_map[ret['ctype']]
  661. else:
  662. ret['rformat'] = 'O'
  663. errmess('routsign2map: no c2buildvalue key for type %s\n' %
  664. (repr(ret['ctype'])))
  665. if debugcapi(rout):
  666. if ret['ctype'] in cformat_map:
  667. ret['routdebugshowvalue'] = 'debug-capi:%s=%s' % (
  668. a, cformat_map[ret['ctype']])
  669. if isstringfunction(rout):
  670. ret['routdebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
  671. a, a)
  672. if isstringfunction(rout):
  673. ret['rlength'] = getstrlength(rout['vars'][a])
  674. if ret['rlength'] == '-1':
  675. errmess('routsign2map: expected explicit specification of the length of the string returned by the fortran function %s; taking 10.\n' % (
  676. repr(rout['name'])))
  677. ret['rlength'] = '10'
  678. if hasnote(rout):
  679. ret['note'] = rout['note']
  680. rout['note'] = ['See elsewhere.']
  681. return ret
  682. def modsign2map(m):
  683. """
  684. modulename
  685. """
  686. if ismodule(m):
  687. ret = {'f90modulename': m['name'],
  688. 'F90MODULENAME': m['name'].upper(),
  689. 'texf90modulename': m['name'].replace('_', '\\_')}
  690. else:
  691. ret = {'modulename': m['name'],
  692. 'MODULENAME': m['name'].upper(),
  693. 'texmodulename': m['name'].replace('_', '\\_')}
  694. ret['restdoc'] = getrestdoc(m) or []
  695. if hasnote(m):
  696. ret['note'] = m['note']
  697. ret['usercode'] = getusercode(m) or ''
  698. ret['usercode1'] = getusercode1(m) or ''
  699. if m['body']:
  700. ret['interface_usercode'] = getusercode(m['body'][0]) or ''
  701. else:
  702. ret['interface_usercode'] = ''
  703. ret['pymethoddef'] = getpymethoddef(m) or ''
  704. if 'coutput' in m:
  705. ret['coutput'] = m['coutput']
  706. if 'f2py_wrapper_output' in m:
  707. ret['f2py_wrapper_output'] = m['f2py_wrapper_output']
  708. return ret
  709. def cb_sign2map(a, var, index=None):
  710. ret = {'varname': a}
  711. ret['varname_i'] = ret['varname']
  712. ret['ctype'] = getctype(var)
  713. if ret['ctype'] in c2capi_map:
  714. ret['atype'] = c2capi_map[ret['ctype']]
  715. ret['elsize'] = get_elsize(var)
  716. if ret['ctype'] in cformat_map:
  717. ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
  718. if isarray(var):
  719. ret = dictappend(ret, getarrdims(a, var))
  720. ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
  721. if hasnote(var):
  722. ret['note'] = var['note']
  723. var['note'] = ['See elsewhere.']
  724. return ret
  725. def cb_routsign2map(rout, um):
  726. """
  727. name,begintitle,endtitle,argname
  728. ctype,rctype,maxnofargs,nofoptargs,returncptr
  729. """
  730. ret = {'name': 'cb_%s_in_%s' % (rout['name'], um),
  731. 'returncptr': ''}
  732. if isintent_callback(rout):
  733. if '_' in rout['name']:
  734. F_FUNC = 'F_FUNC_US'
  735. else:
  736. F_FUNC = 'F_FUNC'
  737. ret['callbackname'] = '%s(%s,%s)' \
  738. % (F_FUNC,
  739. rout['name'].lower(),
  740. rout['name'].upper(),
  741. )
  742. ret['static'] = 'extern'
  743. else:
  744. ret['callbackname'] = ret['name']
  745. ret['static'] = 'static'
  746. ret['argname'] = rout['name']
  747. ret['begintitle'] = gentitle(ret['name'])
  748. ret['endtitle'] = gentitle('end of %s' % ret['name'])
  749. ret['ctype'] = getctype(rout)
  750. ret['rctype'] = 'void'
  751. if ret['ctype'] == 'string':
  752. ret['rctype'] = 'void'
  753. else:
  754. ret['rctype'] = ret['ctype']
  755. if ret['rctype'] != 'void':
  756. if iscomplexfunction(rout):
  757. ret['returncptr'] = """
  758. #ifdef F2PY_CB_RETURNCOMPLEX
  759. return_value=
  760. #endif
  761. """
  762. else:
  763. ret['returncptr'] = 'return_value='
  764. if ret['ctype'] in cformat_map:
  765. ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
  766. if isstringfunction(rout):
  767. ret['strlength'] = getstrlength(rout)
  768. if isfunction(rout):
  769. if 'result' in rout:
  770. a = rout['result']
  771. else:
  772. a = rout['name']
  773. if hasnote(rout['vars'][a]):
  774. ret['note'] = rout['vars'][a]['note']
  775. rout['vars'][a]['note'] = ['See elsewhere.']
  776. ret['rname'] = a
  777. ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
  778. if iscomplexfunction(rout):
  779. ret['rctype'] = """
  780. #ifdef F2PY_CB_RETURNCOMPLEX
  781. #ctype#
  782. #else
  783. void
  784. #endif
  785. """
  786. else:
  787. if hasnote(rout):
  788. ret['note'] = rout['note']
  789. rout['note'] = ['See elsewhere.']
  790. nofargs = 0
  791. nofoptargs = 0
  792. if 'args' in rout and 'vars' in rout:
  793. for a in rout['args']:
  794. var = rout['vars'][a]
  795. if l_or(isintent_in, isintent_inout)(var):
  796. nofargs = nofargs + 1
  797. if isoptional(var):
  798. nofoptargs = nofoptargs + 1
  799. ret['maxnofargs'] = repr(nofargs)
  800. ret['nofoptargs'] = repr(nofoptargs)
  801. if hasnote(rout) and isfunction(rout) and 'result' in rout:
  802. ret['routnote'] = rout['note']
  803. rout['note'] = ['See elsewhere.']
  804. return ret
  805. def common_sign2map(a, var): # obsolute
  806. ret = {'varname': a, 'ctype': getctype(var)}
  807. if isstringarray(var):
  808. ret['ctype'] = 'char'
  809. if ret['ctype'] in c2capi_map:
  810. ret['atype'] = c2capi_map[ret['ctype']]
  811. ret['elsize'] = get_elsize(var)
  812. if ret['ctype'] in cformat_map:
  813. ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
  814. if isarray(var):
  815. ret = dictappend(ret, getarrdims(a, var))
  816. elif isstring(var):
  817. ret['size'] = getstrlength(var)
  818. ret['rank'] = '1'
  819. ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
  820. if hasnote(var):
  821. ret['note'] = var['note']
  822. var['note'] = ['See elsewhere.']
  823. # for strings this returns 0-rank but actually is 1-rank
  824. ret['arrdocstr'] = getarrdocsign(a, var)
  825. return ret