f90mod_rules.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #!/usr/bin/env python3
  2. """
  3. Build F90 module support for f2py2e.
  4. Copyright 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: 2005/02/03 19:30:23 $
  10. Pearu Peterson
  11. """
  12. __version__ = "$Revision: 1.27 $"[10:-1]
  13. f2py_version = 'See `f2py -v`'
  14. import numpy as np
  15. from . import capi_maps
  16. from . import func2subr
  17. from .crackfortran import undo_rmbadname, undo_rmbadname1
  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. options = {}
  23. def findf90modules(m):
  24. if ismodule(m):
  25. return [m]
  26. if not hasbody(m):
  27. return []
  28. ret = []
  29. for b in m['body']:
  30. if ismodule(b):
  31. ret.append(b)
  32. else:
  33. ret = ret + findf90modules(b)
  34. return ret
  35. fgetdims1 = """\
  36. external f2pysetdata
  37. logical ns
  38. integer r,i
  39. integer(%d) s(*)
  40. ns = .FALSE.
  41. if (allocated(d)) then
  42. do i=1,r
  43. if ((size(d,i).ne.s(i)).and.(s(i).ge.0)) then
  44. ns = .TRUE.
  45. end if
  46. end do
  47. if (ns) then
  48. deallocate(d)
  49. end if
  50. end if
  51. if ((.not.allocated(d)).and.(s(1).ge.1)) then""" % np.intp().itemsize
  52. fgetdims2 = """\
  53. end if
  54. if (allocated(d)) then
  55. do i=1,r
  56. s(i) = size(d,i)
  57. end do
  58. end if
  59. flag = 1
  60. call f2pysetdata(d,allocated(d))"""
  61. fgetdims2_sa = """\
  62. end if
  63. if (allocated(d)) then
  64. do i=1,r
  65. s(i) = size(d,i)
  66. end do
  67. !s(r) must be equal to len(d(1))
  68. end if
  69. flag = 2
  70. call f2pysetdata(d,allocated(d))"""
  71. def buildhooks(pymod):
  72. from . import rules
  73. ret = {'f90modhooks': [], 'initf90modhooks': [], 'body': [],
  74. 'need': ['F_FUNC', 'arrayobject.h'],
  75. 'separatorsfor': {'includes0': '\n', 'includes': '\n'},
  76. 'docs': ['"Fortran 90/95 modules:\\n"'],
  77. 'latexdoc': []}
  78. fhooks = ['']
  79. def fadd(line, s=fhooks):
  80. s[0] = '%s\n %s' % (s[0], line)
  81. doc = ['']
  82. def dadd(line, s=doc):
  83. s[0] = '%s\n%s' % (s[0], line)
  84. for m in findf90modules(pymod):
  85. sargs, fargs, efargs, modobjs, notvars, onlyvars = [], [], [], [], [
  86. m['name']], []
  87. sargsp = []
  88. ifargs = []
  89. mfargs = []
  90. if hasbody(m):
  91. for b in m['body']:
  92. notvars.append(b['name'])
  93. for n in m['vars'].keys():
  94. var = m['vars'][n]
  95. if (n not in notvars) and (not l_or(isintent_hide, isprivate)(var)):
  96. onlyvars.append(n)
  97. mfargs.append(n)
  98. outmess('\t\tConstructing F90 module support for "%s"...\n' %
  99. (m['name']))
  100. if onlyvars:
  101. outmess('\t\t Variables: %s\n' % (' '.join(onlyvars)))
  102. chooks = ['']
  103. def cadd(line, s=chooks):
  104. s[0] = '%s\n%s' % (s[0], line)
  105. ihooks = ['']
  106. def iadd(line, s=ihooks):
  107. s[0] = '%s\n%s' % (s[0], line)
  108. vrd = capi_maps.modsign2map(m)
  109. cadd('static FortranDataDef f2py_%s_def[] = {' % (m['name']))
  110. dadd('\\subsection{Fortran 90/95 module \\texttt{%s}}\n' % (m['name']))
  111. if hasnote(m):
  112. note = m['note']
  113. if isinstance(note, list):
  114. note = '\n'.join(note)
  115. dadd(note)
  116. if onlyvars:
  117. dadd('\\begin{description}')
  118. for n in onlyvars:
  119. var = m['vars'][n]
  120. modobjs.append(n)
  121. ct = capi_maps.getctype(var)
  122. at = capi_maps.c2capi_map[ct]
  123. dm = capi_maps.getarrdims(n, var)
  124. dms = dm['dims'].replace('*', '-1').strip()
  125. dms = dms.replace(':', '-1').strip()
  126. if not dms:
  127. dms = '-1'
  128. use_fgetdims2 = fgetdims2
  129. if isstringarray(var):
  130. if 'charselector' in var and 'len' in var['charselector']:
  131. cadd('\t{"%s",%s,{{%s,%s}},%s},'
  132. % (undo_rmbadname1(n), dm['rank'], dms, var['charselector']['len'], at))
  133. use_fgetdims2 = fgetdims2_sa
  134. else:
  135. cadd('\t{"%s",%s,{{%s}},%s},' %
  136. (undo_rmbadname1(n), dm['rank'], dms, at))
  137. else:
  138. cadd('\t{"%s",%s,{{%s}},%s},' %
  139. (undo_rmbadname1(n), dm['rank'], dms, at))
  140. dadd('\\item[]{{}\\verb@%s@{}}' %
  141. (capi_maps.getarrdocsign(n, var)))
  142. if hasnote(var):
  143. note = var['note']
  144. if isinstance(note, list):
  145. note = '\n'.join(note)
  146. dadd('--- %s' % (note))
  147. if isallocatable(var):
  148. fargs.append('f2py_%s_getdims_%s' % (m['name'], n))
  149. efargs.append(fargs[-1])
  150. sargs.append(
  151. 'void (*%s)(int*,int*,void(*)(char*,int*),int*)' % (n))
  152. sargsp.append('void (*)(int*,int*,void(*)(char*,int*),int*)')
  153. iadd('\tf2py_%s_def[i_f2py++].func = %s;' % (m['name'], n))
  154. fadd('subroutine %s(r,s,f2pysetdata,flag)' % (fargs[-1]))
  155. fadd('use %s, only: d => %s\n' %
  156. (m['name'], undo_rmbadname1(n)))
  157. fadd('integer flag\n')
  158. fhooks[0] = fhooks[0] + fgetdims1
  159. dms = range(1, int(dm['rank']) + 1)
  160. fadd(' allocate(d(%s))\n' %
  161. (','.join(['s(%s)' % i for i in dms])))
  162. fhooks[0] = fhooks[0] + use_fgetdims2
  163. fadd('end subroutine %s' % (fargs[-1]))
  164. else:
  165. fargs.append(n)
  166. sargs.append('char *%s' % (n))
  167. sargsp.append('char*')
  168. iadd('\tf2py_%s_def[i_f2py++].data = %s;' % (m['name'], n))
  169. if onlyvars:
  170. dadd('\\end{description}')
  171. if hasbody(m):
  172. for b in m['body']:
  173. if not isroutine(b):
  174. print('Skipping', b['block'], b['name'])
  175. continue
  176. modobjs.append('%s()' % (b['name']))
  177. b['modulename'] = m['name']
  178. api, wrap = rules.buildapi(b)
  179. if isfunction(b):
  180. fhooks[0] = fhooks[0] + wrap
  181. fargs.append('f2pywrap_%s_%s' % (m['name'], b['name']))
  182. ifargs.append(func2subr.createfuncwrapper(b, signature=1))
  183. else:
  184. if wrap:
  185. fhooks[0] = fhooks[0] + wrap
  186. fargs.append('f2pywrap_%s_%s' % (m['name'], b['name']))
  187. ifargs.append(
  188. func2subr.createsubrwrapper(b, signature=1))
  189. else:
  190. fargs.append(b['name'])
  191. mfargs.append(fargs[-1])
  192. api['externroutines'] = []
  193. ar = applyrules(api, vrd)
  194. ar['docs'] = []
  195. ar['docshort'] = []
  196. ret = dictappend(ret, ar)
  197. cadd('\t{"%s",-1,{{-1}},0,NULL,(void *)f2py_rout_#modulename#_%s_%s,doc_f2py_rout_#modulename#_%s_%s},' %
  198. (b['name'], m['name'], b['name'], m['name'], b['name']))
  199. sargs.append('char *%s' % (b['name']))
  200. sargsp.append('char *')
  201. iadd('\tf2py_%s_def[i_f2py++].data = %s;' %
  202. (m['name'], b['name']))
  203. cadd('\t{NULL}\n};\n')
  204. iadd('}')
  205. ihooks[0] = 'static void f2py_setup_%s(%s) {\n\tint i_f2py=0;%s' % (
  206. m['name'], ','.join(sargs), ihooks[0])
  207. if '_' in m['name']:
  208. F_FUNC = 'F_FUNC_US'
  209. else:
  210. F_FUNC = 'F_FUNC'
  211. iadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void (*)(%s));'
  212. % (F_FUNC, m['name'], m['name'].upper(), ','.join(sargsp)))
  213. iadd('static void f2py_init_%s(void) {' % (m['name']))
  214. iadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);'
  215. % (F_FUNC, m['name'], m['name'].upper(), m['name']))
  216. iadd('}\n')
  217. ret['f90modhooks'] = ret['f90modhooks'] + chooks + ihooks
  218. ret['initf90modhooks'] = ['\tPyDict_SetItemString(d, "%s", PyFortranObject_New(f2py_%s_def,f2py_init_%s));' % (
  219. m['name'], m['name'], m['name'])] + ret['initf90modhooks']
  220. fadd('')
  221. fadd('subroutine f2pyinit%s(f2pysetupfunc)' % (m['name']))
  222. if mfargs:
  223. for a in undo_rmbadname(mfargs):
  224. fadd('use %s, only : %s' % (m['name'], a))
  225. if ifargs:
  226. fadd(' '.join(['interface'] + ifargs))
  227. fadd('end interface')
  228. fadd('external f2pysetupfunc')
  229. if efargs:
  230. for a in undo_rmbadname(efargs):
  231. fadd('external %s' % (a))
  232. fadd('call f2pysetupfunc(%s)' % (','.join(undo_rmbadname(fargs))))
  233. fadd('end subroutine f2pyinit%s\n' % (m['name']))
  234. dadd('\n'.join(ret['latexdoc']).replace(
  235. r'\subsection{', r'\subsubsection{'))
  236. ret['latexdoc'] = []
  237. ret['docs'].append('"\t%s --- %s"' % (m['name'],
  238. ','.join(undo_rmbadname(modobjs))))
  239. ret['routine_defs'] = ''
  240. ret['doc'] = []
  241. ret['docshort'] = []
  242. ret['latexdoc'] = doc[0]
  243. if len(ret['docs']) <= 1:
  244. ret['docs'] = ''
  245. return ret, fhooks[0]