func2subr.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #!/usr/bin/env python3
  2. """
  3. Rules for building C/API module with f2py2e.
  4. Copyright 1999,2000 Pearu Peterson all rights reserved,
  5. Pearu Peterson <pearu@ioc.ee>
  6. Permission to use, modify, and distribute this software is given under the
  7. terms of the NumPy License.
  8. NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  9. $Date: 2004/11/26 11:13:06 $
  10. Pearu Peterson
  11. """
  12. import copy
  13. from .auxfuncs import (
  14. getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in,
  15. isintent_out, islogicalfunction, ismoduleroutine, isscalar,
  16. issubroutine, issubroutine_wrap, outmess, show
  17. )
  18. from ._isocbind import isoc_kindmap
  19. def var2fixfortran(vars, a, fa=None, f90mode=None):
  20. if fa is None:
  21. fa = a
  22. if a not in vars:
  23. show(vars)
  24. outmess('var2fixfortran: No definition for argument "%s".\n' % a)
  25. return ''
  26. if 'typespec' not in vars[a]:
  27. show(vars[a])
  28. outmess('var2fixfortran: No typespec for argument "%s".\n' % a)
  29. return ''
  30. vardef = vars[a]['typespec']
  31. if vardef == 'type' and 'typename' in vars[a]:
  32. vardef = '%s(%s)' % (vardef, vars[a]['typename'])
  33. selector = {}
  34. lk = ''
  35. if 'kindselector' in vars[a]:
  36. selector = vars[a]['kindselector']
  37. lk = 'kind'
  38. elif 'charselector' in vars[a]:
  39. selector = vars[a]['charselector']
  40. lk = 'len'
  41. if '*' in selector:
  42. if f90mode:
  43. if selector['*'] in ['*', ':', '(*)']:
  44. vardef = '%s(len=*)' % (vardef)
  45. else:
  46. vardef = '%s(%s=%s)' % (vardef, lk, selector['*'])
  47. else:
  48. if selector['*'] in ['*', ':']:
  49. vardef = '%s*(%s)' % (vardef, selector['*'])
  50. else:
  51. vardef = '%s*%s' % (vardef, selector['*'])
  52. else:
  53. if 'len' in selector:
  54. vardef = '%s(len=%s' % (vardef, selector['len'])
  55. if 'kind' in selector:
  56. vardef = '%s,kind=%s)' % (vardef, selector['kind'])
  57. else:
  58. vardef = '%s)' % (vardef)
  59. elif 'kind' in selector:
  60. vardef = '%s(kind=%s)' % (vardef, selector['kind'])
  61. vardef = '%s %s' % (vardef, fa)
  62. if 'dimension' in vars[a]:
  63. vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension']))
  64. return vardef
  65. def useiso_c_binding(rout):
  66. useisoc = False
  67. for key, value in rout['vars'].items():
  68. kind_value = value.get('kindselector', {}).get('kind')
  69. if kind_value in isoc_kindmap:
  70. return True
  71. return useisoc
  72. def createfuncwrapper(rout, signature=0):
  73. assert isfunction(rout)
  74. extra_args = []
  75. vars = rout['vars']
  76. for a in rout['args']:
  77. v = rout['vars'][a]
  78. for i, d in enumerate(v.get('dimension', [])):
  79. if d == ':':
  80. dn = 'f2py_%s_d%s' % (a, i)
  81. dv = dict(typespec='integer', intent=['hide'])
  82. dv['='] = 'shape(%s, %s)' % (a, i)
  83. extra_args.append(dn)
  84. vars[dn] = dv
  85. v['dimension'][i] = dn
  86. rout['args'].extend(extra_args)
  87. need_interface = bool(extra_args)
  88. ret = ['']
  89. def add(line, ret=ret):
  90. ret[0] = '%s\n %s' % (ret[0], line)
  91. name = rout['name']
  92. fortranname = getfortranname(rout)
  93. f90mode = ismoduleroutine(rout)
  94. newname = '%sf2pywrap' % (name)
  95. if newname not in vars:
  96. vars[newname] = vars[name]
  97. args = [newname] + rout['args'][1:]
  98. else:
  99. args = [newname] + rout['args']
  100. l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
  101. if l_tmpl[:13] == 'character*(*)':
  102. if f90mode:
  103. l_tmpl = 'character(len=10)' + l_tmpl[13:]
  104. else:
  105. l_tmpl = 'character*10' + l_tmpl[13:]
  106. charselect = vars[name]['charselector']
  107. if charselect.get('*', '') == '(*)':
  108. charselect['*'] = '10'
  109. l1 = l_tmpl.replace('@@@NAME@@@', newname)
  110. rl = None
  111. useisoc = useiso_c_binding(rout)
  112. sargs = ', '.join(args)
  113. if f90mode:
  114. # gh-23598 fix warning
  115. # Essentially, this gets called again with modules where the name of the
  116. # function is added to the arguments, which is not required, and removed
  117. sargs = sargs.replace(f"{name}, ", '')
  118. args = [arg for arg in args if arg != name]
  119. rout['args'] = args
  120. add('subroutine f2pywrap_%s_%s (%s)' %
  121. (rout['modulename'], name, sargs))
  122. if not signature:
  123. add('use %s, only : %s' % (rout['modulename'], fortranname))
  124. if useisoc:
  125. add('use iso_c_binding')
  126. else:
  127. add('subroutine f2pywrap%s (%s)' % (name, sargs))
  128. if useisoc:
  129. add('use iso_c_binding')
  130. if not need_interface:
  131. add('external %s' % (fortranname))
  132. rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname
  133. if need_interface:
  134. for line in rout['saved_interface'].split('\n'):
  135. if line.lstrip().startswith('use ') and '__user__' not in line:
  136. add(line)
  137. args = args[1:]
  138. dumped_args = []
  139. for a in args:
  140. if isexternal(vars[a]):
  141. add('external %s' % (a))
  142. dumped_args.append(a)
  143. for a in args:
  144. if a in dumped_args:
  145. continue
  146. if isscalar(vars[a]):
  147. add(var2fixfortran(vars, a, f90mode=f90mode))
  148. dumped_args.append(a)
  149. for a in args:
  150. if a in dumped_args:
  151. continue
  152. if isintent_in(vars[a]):
  153. add(var2fixfortran(vars, a, f90mode=f90mode))
  154. dumped_args.append(a)
  155. for a in args:
  156. if a in dumped_args:
  157. continue
  158. add(var2fixfortran(vars, a, f90mode=f90mode))
  159. add(l1)
  160. if rl is not None:
  161. add(rl)
  162. if need_interface:
  163. if f90mode:
  164. # f90 module already defines needed interface
  165. pass
  166. else:
  167. add('interface')
  168. add(rout['saved_interface'].lstrip())
  169. add('end interface')
  170. sargs = ', '.join([a for a in args if a not in extra_args])
  171. if not signature:
  172. if islogicalfunction(rout):
  173. add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs))
  174. else:
  175. add('%s = %s(%s)' % (newname, fortranname, sargs))
  176. if f90mode:
  177. add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
  178. else:
  179. add('end')
  180. return ret[0]
  181. def createsubrwrapper(rout, signature=0):
  182. assert issubroutine(rout)
  183. extra_args = []
  184. vars = rout['vars']
  185. for a in rout['args']:
  186. v = rout['vars'][a]
  187. for i, d in enumerate(v.get('dimension', [])):
  188. if d == ':':
  189. dn = 'f2py_%s_d%s' % (a, i)
  190. dv = dict(typespec='integer', intent=['hide'])
  191. dv['='] = 'shape(%s, %s)' % (a, i)
  192. extra_args.append(dn)
  193. vars[dn] = dv
  194. v['dimension'][i] = dn
  195. rout['args'].extend(extra_args)
  196. need_interface = bool(extra_args)
  197. ret = ['']
  198. def add(line, ret=ret):
  199. ret[0] = '%s\n %s' % (ret[0], line)
  200. name = rout['name']
  201. fortranname = getfortranname(rout)
  202. f90mode = ismoduleroutine(rout)
  203. args = rout['args']
  204. useisoc = useiso_c_binding(rout)
  205. sargs = ', '.join(args)
  206. if f90mode:
  207. add('subroutine f2pywrap_%s_%s (%s)' %
  208. (rout['modulename'], name, sargs))
  209. if useisoc:
  210. add('use iso_c_binding')
  211. if not signature:
  212. add('use %s, only : %s' % (rout['modulename'], fortranname))
  213. else:
  214. add('subroutine f2pywrap%s (%s)' % (name, sargs))
  215. if useisoc:
  216. add('use iso_c_binding')
  217. if not need_interface:
  218. add('external %s' % (fortranname))
  219. if need_interface:
  220. for line in rout['saved_interface'].split('\n'):
  221. if line.lstrip().startswith('use ') and '__user__' not in line:
  222. add(line)
  223. dumped_args = []
  224. for a in args:
  225. if isexternal(vars[a]):
  226. add('external %s' % (a))
  227. dumped_args.append(a)
  228. for a in args:
  229. if a in dumped_args:
  230. continue
  231. if isscalar(vars[a]):
  232. add(var2fixfortran(vars, a, f90mode=f90mode))
  233. dumped_args.append(a)
  234. for a in args:
  235. if a in dumped_args:
  236. continue
  237. add(var2fixfortran(vars, a, f90mode=f90mode))
  238. if need_interface:
  239. if f90mode:
  240. # f90 module already defines needed interface
  241. pass
  242. else:
  243. add('interface')
  244. for line in rout['saved_interface'].split('\n'):
  245. if line.lstrip().startswith('use ') and '__user__' in line:
  246. continue
  247. add(line)
  248. add('end interface')
  249. sargs = ', '.join([a for a in args if a not in extra_args])
  250. if not signature:
  251. add('call %s(%s)' % (fortranname, sargs))
  252. if f90mode:
  253. add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
  254. else:
  255. add('end')
  256. return ret[0]
  257. def assubr(rout):
  258. if isfunction_wrap(rout):
  259. fortranname = getfortranname(rout)
  260. name = rout['name']
  261. outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
  262. name, fortranname))
  263. rout = copy.copy(rout)
  264. fname = name
  265. rname = fname
  266. if 'result' in rout:
  267. rname = rout['result']
  268. rout['vars'][fname] = rout['vars'][rname]
  269. fvar = rout['vars'][fname]
  270. if not isintent_out(fvar):
  271. if 'intent' not in fvar:
  272. fvar['intent'] = []
  273. fvar['intent'].append('out')
  274. flag = 1
  275. for i in fvar['intent']:
  276. if i.startswith('out='):
  277. flag = 0
  278. break
  279. if flag:
  280. fvar['intent'].append('out=%s' % (rname))
  281. rout['args'][:] = [fname] + rout['args']
  282. return rout, createfuncwrapper(rout)
  283. if issubroutine_wrap(rout):
  284. fortranname = getfortranname(rout)
  285. name = rout['name']
  286. outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
  287. % (name, fortranname))
  288. rout = copy.copy(rout)
  289. return rout, createsubrwrapper(rout)
  290. return rout, ''