func2subr.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. def var2fixfortran(vars, a, fa=None, f90mode=None):
  19. if fa is None:
  20. fa = a
  21. if a not in vars:
  22. show(vars)
  23. outmess('var2fixfortran: No definition for argument "%s".\n' % a)
  24. return ''
  25. if 'typespec' not in vars[a]:
  26. show(vars[a])
  27. outmess('var2fixfortran: No typespec for argument "%s".\n' % a)
  28. return ''
  29. vardef = vars[a]['typespec']
  30. if vardef == 'type' and 'typename' in vars[a]:
  31. vardef = '%s(%s)' % (vardef, vars[a]['typename'])
  32. selector = {}
  33. lk = ''
  34. if 'kindselector' in vars[a]:
  35. selector = vars[a]['kindselector']
  36. lk = 'kind'
  37. elif 'charselector' in vars[a]:
  38. selector = vars[a]['charselector']
  39. lk = 'len'
  40. if '*' in selector:
  41. if f90mode:
  42. if selector['*'] in ['*', ':', '(*)']:
  43. vardef = '%s(len=*)' % (vardef)
  44. else:
  45. vardef = '%s(%s=%s)' % (vardef, lk, selector['*'])
  46. else:
  47. if selector['*'] in ['*', ':']:
  48. vardef = '%s*(%s)' % (vardef, selector['*'])
  49. else:
  50. vardef = '%s*%s' % (vardef, selector['*'])
  51. else:
  52. if 'len' in selector:
  53. vardef = '%s(len=%s' % (vardef, selector['len'])
  54. if 'kind' in selector:
  55. vardef = '%s,kind=%s)' % (vardef, selector['kind'])
  56. else:
  57. vardef = '%s)' % (vardef)
  58. elif 'kind' in selector:
  59. vardef = '%s(kind=%s)' % (vardef, selector['kind'])
  60. vardef = '%s %s' % (vardef, fa)
  61. if 'dimension' in vars[a]:
  62. vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension']))
  63. return vardef
  64. def createfuncwrapper(rout, signature=0):
  65. assert isfunction(rout)
  66. extra_args = []
  67. vars = rout['vars']
  68. for a in rout['args']:
  69. v = rout['vars'][a]
  70. for i, d in enumerate(v.get('dimension', [])):
  71. if d == ':':
  72. dn = 'f2py_%s_d%s' % (a, i)
  73. dv = dict(typespec='integer', intent=['hide'])
  74. dv['='] = 'shape(%s, %s)' % (a, i)
  75. extra_args.append(dn)
  76. vars[dn] = dv
  77. v['dimension'][i] = dn
  78. rout['args'].extend(extra_args)
  79. need_interface = bool(extra_args)
  80. ret = ['']
  81. def add(line, ret=ret):
  82. ret[0] = '%s\n %s' % (ret[0], line)
  83. name = rout['name']
  84. fortranname = getfortranname(rout)
  85. f90mode = ismoduleroutine(rout)
  86. newname = '%sf2pywrap' % (name)
  87. if newname not in vars:
  88. vars[newname] = vars[name]
  89. args = [newname] + rout['args'][1:]
  90. else:
  91. args = [newname] + rout['args']
  92. l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
  93. if l_tmpl[:13] == 'character*(*)':
  94. if f90mode:
  95. l_tmpl = 'character(len=10)' + l_tmpl[13:]
  96. else:
  97. l_tmpl = 'character*10' + l_tmpl[13:]
  98. charselect = vars[name]['charselector']
  99. if charselect.get('*', '') == '(*)':
  100. charselect['*'] = '10'
  101. l1 = l_tmpl.replace('@@@NAME@@@', newname)
  102. rl = None
  103. sargs = ', '.join(args)
  104. if f90mode:
  105. add('subroutine f2pywrap_%s_%s (%s)' %
  106. (rout['modulename'], name, sargs))
  107. if not signature:
  108. add('use %s, only : %s' % (rout['modulename'], fortranname))
  109. else:
  110. add('subroutine f2pywrap%s (%s)' % (name, sargs))
  111. if not need_interface:
  112. add('external %s' % (fortranname))
  113. rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname
  114. if need_interface:
  115. for line in rout['saved_interface'].split('\n'):
  116. if line.lstrip().startswith('use ') and '__user__' not in line:
  117. add(line)
  118. args = args[1:]
  119. dumped_args = []
  120. for a in args:
  121. if isexternal(vars[a]):
  122. add('external %s' % (a))
  123. dumped_args.append(a)
  124. for a in args:
  125. if a in dumped_args:
  126. continue
  127. if isscalar(vars[a]):
  128. add(var2fixfortran(vars, a, f90mode=f90mode))
  129. dumped_args.append(a)
  130. for a in args:
  131. if a in dumped_args:
  132. continue
  133. if isintent_in(vars[a]):
  134. add(var2fixfortran(vars, a, f90mode=f90mode))
  135. dumped_args.append(a)
  136. for a in args:
  137. if a in dumped_args:
  138. continue
  139. add(var2fixfortran(vars, a, f90mode=f90mode))
  140. add(l1)
  141. if rl is not None:
  142. add(rl)
  143. if need_interface:
  144. if f90mode:
  145. # f90 module already defines needed interface
  146. pass
  147. else:
  148. add('interface')
  149. add(rout['saved_interface'].lstrip())
  150. add('end interface')
  151. sargs = ', '.join([a for a in args if a not in extra_args])
  152. if not signature:
  153. if islogicalfunction(rout):
  154. add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs))
  155. else:
  156. add('%s = %s(%s)' % (newname, fortranname, sargs))
  157. if f90mode:
  158. add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
  159. else:
  160. add('end')
  161. return ret[0]
  162. def createsubrwrapper(rout, signature=0):
  163. assert issubroutine(rout)
  164. extra_args = []
  165. vars = rout['vars']
  166. for a in rout['args']:
  167. v = rout['vars'][a]
  168. for i, d in enumerate(v.get('dimension', [])):
  169. if d == ':':
  170. dn = 'f2py_%s_d%s' % (a, i)
  171. dv = dict(typespec='integer', intent=['hide'])
  172. dv['='] = 'shape(%s, %s)' % (a, i)
  173. extra_args.append(dn)
  174. vars[dn] = dv
  175. v['dimension'][i] = dn
  176. rout['args'].extend(extra_args)
  177. need_interface = bool(extra_args)
  178. ret = ['']
  179. def add(line, ret=ret):
  180. ret[0] = '%s\n %s' % (ret[0], line)
  181. name = rout['name']
  182. fortranname = getfortranname(rout)
  183. f90mode = ismoduleroutine(rout)
  184. args = rout['args']
  185. sargs = ', '.join(args)
  186. if f90mode:
  187. add('subroutine f2pywrap_%s_%s (%s)' %
  188. (rout['modulename'], name, sargs))
  189. if not signature:
  190. add('use %s, only : %s' % (rout['modulename'], fortranname))
  191. else:
  192. add('subroutine f2pywrap%s (%s)' % (name, sargs))
  193. if not need_interface:
  194. add('external %s' % (fortranname))
  195. if need_interface:
  196. for line in rout['saved_interface'].split('\n'):
  197. if line.lstrip().startswith('use ') and '__user__' not in line:
  198. add(line)
  199. dumped_args = []
  200. for a in args:
  201. if isexternal(vars[a]):
  202. add('external %s' % (a))
  203. dumped_args.append(a)
  204. for a in args:
  205. if a in dumped_args:
  206. continue
  207. if isscalar(vars[a]):
  208. add(var2fixfortran(vars, a, f90mode=f90mode))
  209. dumped_args.append(a)
  210. for a in args:
  211. if a in dumped_args:
  212. continue
  213. add(var2fixfortran(vars, a, f90mode=f90mode))
  214. if need_interface:
  215. if f90mode:
  216. # f90 module already defines needed interface
  217. pass
  218. else:
  219. add('interface')
  220. for line in rout['saved_interface'].split('\n'):
  221. if line.lstrip().startswith('use ') and '__user__' in line:
  222. continue
  223. add(line)
  224. add('end interface')
  225. sargs = ', '.join([a for a in args if a not in extra_args])
  226. if not signature:
  227. add('call %s(%s)' % (fortranname, sargs))
  228. if f90mode:
  229. add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
  230. else:
  231. add('end')
  232. return ret[0]
  233. def assubr(rout):
  234. if isfunction_wrap(rout):
  235. fortranname = getfortranname(rout)
  236. name = rout['name']
  237. outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
  238. name, fortranname))
  239. rout = copy.copy(rout)
  240. fname = name
  241. rname = fname
  242. if 'result' in rout:
  243. rname = rout['result']
  244. rout['vars'][fname] = rout['vars'][rname]
  245. fvar = rout['vars'][fname]
  246. if not isintent_out(fvar):
  247. if 'intent' not in fvar:
  248. fvar['intent'] = []
  249. fvar['intent'].append('out')
  250. flag = 1
  251. for i in fvar['intent']:
  252. if i.startswith('out='):
  253. flag = 0
  254. break
  255. if flag:
  256. fvar['intent'].append('out=%s' % (rname))
  257. rout['args'][:] = [fname] + rout['args']
  258. return rout, createfuncwrapper(rout)
  259. if issubroutine_wrap(rout):
  260. fortranname = getfortranname(rout)
  261. name = rout['name']
  262. outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
  263. % (name, fortranname))
  264. rout = copy.copy(rout)
  265. return rout, createsubrwrapper(rout)
  266. return rout, ''