numpy 2.4.0__cp313-cp313t-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (915) hide show
  1. numpy/__config__.py +170 -0
  2. numpy/__config__.pyi +108 -0
  3. numpy/__init__.cython-30.pxd +1242 -0
  4. numpy/__init__.pxd +1155 -0
  5. numpy/__init__.py +942 -0
  6. numpy/__init__.pyi +6202 -0
  7. numpy/_array_api_info.py +346 -0
  8. numpy/_array_api_info.pyi +206 -0
  9. numpy/_configtool.py +39 -0
  10. numpy/_configtool.pyi +1 -0
  11. numpy/_core/__init__.py +201 -0
  12. numpy/_core/__init__.pyi +666 -0
  13. numpy/_core/_add_newdocs.py +7151 -0
  14. numpy/_core/_add_newdocs.pyi +2 -0
  15. numpy/_core/_add_newdocs_scalars.py +381 -0
  16. numpy/_core/_add_newdocs_scalars.pyi +16 -0
  17. numpy/_core/_asarray.py +130 -0
  18. numpy/_core/_asarray.pyi +43 -0
  19. numpy/_core/_dtype.py +366 -0
  20. numpy/_core/_dtype.pyi +56 -0
  21. numpy/_core/_dtype_ctypes.py +120 -0
  22. numpy/_core/_dtype_ctypes.pyi +83 -0
  23. numpy/_core/_exceptions.py +162 -0
  24. numpy/_core/_exceptions.pyi +54 -0
  25. numpy/_core/_internal.py +968 -0
  26. numpy/_core/_internal.pyi +61 -0
  27. numpy/_core/_methods.py +252 -0
  28. numpy/_core/_methods.pyi +22 -0
  29. numpy/_core/_multiarray_tests.cpython-313t-aarch64-linux-musl.so +0 -0
  30. numpy/_core/_multiarray_umath.cpython-313t-aarch64-linux-musl.so +0 -0
  31. numpy/_core/_operand_flag_tests.cpython-313t-aarch64-linux-musl.so +0 -0
  32. numpy/_core/_rational_tests.cpython-313t-aarch64-linux-musl.so +0 -0
  33. numpy/_core/_simd.cpython-313t-aarch64-linux-musl.so +0 -0
  34. numpy/_core/_simd.pyi +35 -0
  35. numpy/_core/_string_helpers.py +100 -0
  36. numpy/_core/_string_helpers.pyi +12 -0
  37. numpy/_core/_struct_ufunc_tests.cpython-313t-aarch64-linux-musl.so +0 -0
  38. numpy/_core/_type_aliases.py +131 -0
  39. numpy/_core/_type_aliases.pyi +86 -0
  40. numpy/_core/_ufunc_config.py +515 -0
  41. numpy/_core/_ufunc_config.pyi +69 -0
  42. numpy/_core/_umath_tests.cpython-313t-aarch64-linux-musl.so +0 -0
  43. numpy/_core/_umath_tests.pyi +47 -0
  44. numpy/_core/arrayprint.py +1779 -0
  45. numpy/_core/arrayprint.pyi +158 -0
  46. numpy/_core/cversions.py +13 -0
  47. numpy/_core/defchararray.py +1414 -0
  48. numpy/_core/defchararray.pyi +1150 -0
  49. numpy/_core/einsumfunc.py +1650 -0
  50. numpy/_core/einsumfunc.pyi +184 -0
  51. numpy/_core/fromnumeric.py +4233 -0
  52. numpy/_core/fromnumeric.pyi +1735 -0
  53. numpy/_core/function_base.py +547 -0
  54. numpy/_core/function_base.pyi +276 -0
  55. numpy/_core/getlimits.py +462 -0
  56. numpy/_core/getlimits.pyi +124 -0
  57. numpy/_core/include/numpy/__multiarray_api.c +376 -0
  58. numpy/_core/include/numpy/__multiarray_api.h +1628 -0
  59. numpy/_core/include/numpy/__ufunc_api.c +55 -0
  60. numpy/_core/include/numpy/__ufunc_api.h +349 -0
  61. numpy/_core/include/numpy/_neighborhood_iterator_imp.h +90 -0
  62. numpy/_core/include/numpy/_numpyconfig.h +33 -0
  63. numpy/_core/include/numpy/_public_dtype_api_table.h +86 -0
  64. numpy/_core/include/numpy/arrayobject.h +7 -0
  65. numpy/_core/include/numpy/arrayscalars.h +198 -0
  66. numpy/_core/include/numpy/dtype_api.h +547 -0
  67. numpy/_core/include/numpy/halffloat.h +70 -0
  68. numpy/_core/include/numpy/ndarrayobject.h +304 -0
  69. numpy/_core/include/numpy/ndarraytypes.h +1982 -0
  70. numpy/_core/include/numpy/npy_2_compat.h +249 -0
  71. numpy/_core/include/numpy/npy_2_complexcompat.h +28 -0
  72. numpy/_core/include/numpy/npy_3kcompat.h +374 -0
  73. numpy/_core/include/numpy/npy_common.h +989 -0
  74. numpy/_core/include/numpy/npy_cpu.h +126 -0
  75. numpy/_core/include/numpy/npy_endian.h +79 -0
  76. numpy/_core/include/numpy/npy_math.h +602 -0
  77. numpy/_core/include/numpy/npy_no_deprecated_api.h +20 -0
  78. numpy/_core/include/numpy/npy_os.h +42 -0
  79. numpy/_core/include/numpy/numpyconfig.h +185 -0
  80. numpy/_core/include/numpy/random/LICENSE.txt +21 -0
  81. numpy/_core/include/numpy/random/bitgen.h +20 -0
  82. numpy/_core/include/numpy/random/distributions.h +209 -0
  83. numpy/_core/include/numpy/random/libdivide.h +2079 -0
  84. numpy/_core/include/numpy/ufuncobject.h +343 -0
  85. numpy/_core/include/numpy/utils.h +37 -0
  86. numpy/_core/lib/libnpymath.a +0 -0
  87. numpy/_core/lib/npy-pkg-config/mlib.ini +12 -0
  88. numpy/_core/lib/npy-pkg-config/npymath.ini +20 -0
  89. numpy/_core/lib/pkgconfig/numpy.pc +7 -0
  90. numpy/_core/memmap.py +363 -0
  91. numpy/_core/memmap.pyi +3 -0
  92. numpy/_core/multiarray.py +1740 -0
  93. numpy/_core/multiarray.pyi +1316 -0
  94. numpy/_core/numeric.py +2758 -0
  95. numpy/_core/numeric.pyi +1276 -0
  96. numpy/_core/numerictypes.py +633 -0
  97. numpy/_core/numerictypes.pyi +196 -0
  98. numpy/_core/overrides.py +188 -0
  99. numpy/_core/overrides.pyi +47 -0
  100. numpy/_core/printoptions.py +32 -0
  101. numpy/_core/printoptions.pyi +28 -0
  102. numpy/_core/records.py +1088 -0
  103. numpy/_core/records.pyi +340 -0
  104. numpy/_core/shape_base.py +996 -0
  105. numpy/_core/shape_base.pyi +182 -0
  106. numpy/_core/strings.py +1813 -0
  107. numpy/_core/strings.pyi +536 -0
  108. numpy/_core/tests/_locales.py +72 -0
  109. numpy/_core/tests/_natype.py +144 -0
  110. numpy/_core/tests/data/astype_copy.pkl +0 -0
  111. numpy/_core/tests/data/generate_umath_validation_data.cpp +170 -0
  112. numpy/_core/tests/data/recarray_from_file.fits +0 -0
  113. numpy/_core/tests/data/umath-validation-set-README.txt +15 -0
  114. numpy/_core/tests/data/umath-validation-set-arccos.csv +1429 -0
  115. numpy/_core/tests/data/umath-validation-set-arccosh.csv +1429 -0
  116. numpy/_core/tests/data/umath-validation-set-arcsin.csv +1429 -0
  117. numpy/_core/tests/data/umath-validation-set-arcsinh.csv +1429 -0
  118. numpy/_core/tests/data/umath-validation-set-arctan.csv +1429 -0
  119. numpy/_core/tests/data/umath-validation-set-arctanh.csv +1429 -0
  120. numpy/_core/tests/data/umath-validation-set-cbrt.csv +1429 -0
  121. numpy/_core/tests/data/umath-validation-set-cos.csv +1375 -0
  122. numpy/_core/tests/data/umath-validation-set-cosh.csv +1429 -0
  123. numpy/_core/tests/data/umath-validation-set-exp.csv +412 -0
  124. numpy/_core/tests/data/umath-validation-set-exp2.csv +1429 -0
  125. numpy/_core/tests/data/umath-validation-set-expm1.csv +1429 -0
  126. numpy/_core/tests/data/umath-validation-set-log.csv +271 -0
  127. numpy/_core/tests/data/umath-validation-set-log10.csv +1629 -0
  128. numpy/_core/tests/data/umath-validation-set-log1p.csv +1429 -0
  129. numpy/_core/tests/data/umath-validation-set-log2.csv +1629 -0
  130. numpy/_core/tests/data/umath-validation-set-sin.csv +1370 -0
  131. numpy/_core/tests/data/umath-validation-set-sinh.csv +1429 -0
  132. numpy/_core/tests/data/umath-validation-set-tan.csv +1429 -0
  133. numpy/_core/tests/data/umath-validation-set-tanh.csv +1429 -0
  134. numpy/_core/tests/examples/cython/checks.pyx +373 -0
  135. numpy/_core/tests/examples/cython/meson.build +43 -0
  136. numpy/_core/tests/examples/cython/setup.py +39 -0
  137. numpy/_core/tests/examples/limited_api/limited_api1.c +17 -0
  138. numpy/_core/tests/examples/limited_api/limited_api2.pyx +11 -0
  139. numpy/_core/tests/examples/limited_api/limited_api_latest.c +19 -0
  140. numpy/_core/tests/examples/limited_api/meson.build +59 -0
  141. numpy/_core/tests/examples/limited_api/setup.py +24 -0
  142. numpy/_core/tests/test__exceptions.py +90 -0
  143. numpy/_core/tests/test_abc.py +54 -0
  144. numpy/_core/tests/test_api.py +655 -0
  145. numpy/_core/tests/test_argparse.py +90 -0
  146. numpy/_core/tests/test_array_api_info.py +113 -0
  147. numpy/_core/tests/test_array_coercion.py +928 -0
  148. numpy/_core/tests/test_array_interface.py +222 -0
  149. numpy/_core/tests/test_arraymethod.py +84 -0
  150. numpy/_core/tests/test_arrayobject.py +75 -0
  151. numpy/_core/tests/test_arrayprint.py +1324 -0
  152. numpy/_core/tests/test_casting_floatingpoint_errors.py +154 -0
  153. numpy/_core/tests/test_casting_unittests.py +955 -0
  154. numpy/_core/tests/test_conversion_utils.py +209 -0
  155. numpy/_core/tests/test_cpu_dispatcher.py +48 -0
  156. numpy/_core/tests/test_cpu_features.py +450 -0
  157. numpy/_core/tests/test_custom_dtypes.py +393 -0
  158. numpy/_core/tests/test_cython.py +352 -0
  159. numpy/_core/tests/test_datetime.py +2792 -0
  160. numpy/_core/tests/test_defchararray.py +858 -0
  161. numpy/_core/tests/test_deprecations.py +460 -0
  162. numpy/_core/tests/test_dlpack.py +190 -0
  163. numpy/_core/tests/test_dtype.py +2110 -0
  164. numpy/_core/tests/test_einsum.py +1351 -0
  165. numpy/_core/tests/test_errstate.py +131 -0
  166. numpy/_core/tests/test_extint128.py +217 -0
  167. numpy/_core/tests/test_finfo.py +86 -0
  168. numpy/_core/tests/test_function_base.py +504 -0
  169. numpy/_core/tests/test_getlimits.py +171 -0
  170. numpy/_core/tests/test_half.py +593 -0
  171. numpy/_core/tests/test_hashtable.py +36 -0
  172. numpy/_core/tests/test_indexerrors.py +122 -0
  173. numpy/_core/tests/test_indexing.py +1692 -0
  174. numpy/_core/tests/test_item_selection.py +167 -0
  175. numpy/_core/tests/test_limited_api.py +102 -0
  176. numpy/_core/tests/test_longdouble.py +370 -0
  177. numpy/_core/tests/test_mem_overlap.py +933 -0
  178. numpy/_core/tests/test_mem_policy.py +453 -0
  179. numpy/_core/tests/test_memmap.py +248 -0
  180. numpy/_core/tests/test_multiarray.py +11008 -0
  181. numpy/_core/tests/test_multiprocessing.py +55 -0
  182. numpy/_core/tests/test_multithreading.py +353 -0
  183. numpy/_core/tests/test_nditer.py +3533 -0
  184. numpy/_core/tests/test_nep50_promotions.py +287 -0
  185. numpy/_core/tests/test_numeric.py +4295 -0
  186. numpy/_core/tests/test_numerictypes.py +650 -0
  187. numpy/_core/tests/test_overrides.py +800 -0
  188. numpy/_core/tests/test_print.py +202 -0
  189. numpy/_core/tests/test_protocols.py +46 -0
  190. numpy/_core/tests/test_records.py +544 -0
  191. numpy/_core/tests/test_regression.py +2677 -0
  192. numpy/_core/tests/test_scalar_ctors.py +203 -0
  193. numpy/_core/tests/test_scalar_methods.py +328 -0
  194. numpy/_core/tests/test_scalarbuffer.py +153 -0
  195. numpy/_core/tests/test_scalarinherit.py +105 -0
  196. numpy/_core/tests/test_scalarmath.py +1168 -0
  197. numpy/_core/tests/test_scalarprint.py +403 -0
  198. numpy/_core/tests/test_shape_base.py +904 -0
  199. numpy/_core/tests/test_simd.py +1345 -0
  200. numpy/_core/tests/test_simd_module.py +105 -0
  201. numpy/_core/tests/test_stringdtype.py +1855 -0
  202. numpy/_core/tests/test_strings.py +1515 -0
  203. numpy/_core/tests/test_ufunc.py +3405 -0
  204. numpy/_core/tests/test_umath.py +4962 -0
  205. numpy/_core/tests/test_umath_accuracy.py +132 -0
  206. numpy/_core/tests/test_umath_complex.py +631 -0
  207. numpy/_core/tests/test_unicode.py +369 -0
  208. numpy/_core/umath.py +60 -0
  209. numpy/_core/umath.pyi +232 -0
  210. numpy/_distributor_init.py +15 -0
  211. numpy/_distributor_init.pyi +1 -0
  212. numpy/_expired_attrs_2_0.py +78 -0
  213. numpy/_expired_attrs_2_0.pyi +61 -0
  214. numpy/_globals.py +121 -0
  215. numpy/_globals.pyi +17 -0
  216. numpy/_pyinstaller/__init__.py +0 -0
  217. numpy/_pyinstaller/__init__.pyi +0 -0
  218. numpy/_pyinstaller/hook-numpy.py +36 -0
  219. numpy/_pyinstaller/hook-numpy.pyi +6 -0
  220. numpy/_pyinstaller/tests/__init__.py +16 -0
  221. numpy/_pyinstaller/tests/pyinstaller-smoke.py +32 -0
  222. numpy/_pyinstaller/tests/test_pyinstaller.py +35 -0
  223. numpy/_pytesttester.py +201 -0
  224. numpy/_pytesttester.pyi +18 -0
  225. numpy/_typing/__init__.py +173 -0
  226. numpy/_typing/_add_docstring.py +153 -0
  227. numpy/_typing/_array_like.py +106 -0
  228. numpy/_typing/_char_codes.py +213 -0
  229. numpy/_typing/_dtype_like.py +114 -0
  230. numpy/_typing/_extended_precision.py +15 -0
  231. numpy/_typing/_nbit.py +19 -0
  232. numpy/_typing/_nbit_base.py +94 -0
  233. numpy/_typing/_nbit_base.pyi +39 -0
  234. numpy/_typing/_nested_sequence.py +79 -0
  235. numpy/_typing/_scalars.py +20 -0
  236. numpy/_typing/_shape.py +8 -0
  237. numpy/_typing/_ufunc.py +7 -0
  238. numpy/_typing/_ufunc.pyi +975 -0
  239. numpy/_utils/__init__.py +95 -0
  240. numpy/_utils/__init__.pyi +28 -0
  241. numpy/_utils/_convertions.py +18 -0
  242. numpy/_utils/_convertions.pyi +4 -0
  243. numpy/_utils/_inspect.py +192 -0
  244. numpy/_utils/_inspect.pyi +70 -0
  245. numpy/_utils/_pep440.py +486 -0
  246. numpy/_utils/_pep440.pyi +118 -0
  247. numpy/char/__init__.py +2 -0
  248. numpy/char/__init__.pyi +111 -0
  249. numpy/conftest.py +248 -0
  250. numpy/core/__init__.py +33 -0
  251. numpy/core/__init__.pyi +0 -0
  252. numpy/core/_dtype.py +10 -0
  253. numpy/core/_dtype.pyi +0 -0
  254. numpy/core/_dtype_ctypes.py +10 -0
  255. numpy/core/_dtype_ctypes.pyi +0 -0
  256. numpy/core/_internal.py +27 -0
  257. numpy/core/_multiarray_umath.py +57 -0
  258. numpy/core/_utils.py +21 -0
  259. numpy/core/arrayprint.py +10 -0
  260. numpy/core/defchararray.py +10 -0
  261. numpy/core/einsumfunc.py +10 -0
  262. numpy/core/fromnumeric.py +10 -0
  263. numpy/core/function_base.py +10 -0
  264. numpy/core/getlimits.py +10 -0
  265. numpy/core/multiarray.py +25 -0
  266. numpy/core/numeric.py +12 -0
  267. numpy/core/numerictypes.py +10 -0
  268. numpy/core/overrides.py +10 -0
  269. numpy/core/overrides.pyi +7 -0
  270. numpy/core/records.py +10 -0
  271. numpy/core/shape_base.py +10 -0
  272. numpy/core/umath.py +10 -0
  273. numpy/ctypeslib/__init__.py +13 -0
  274. numpy/ctypeslib/__init__.pyi +15 -0
  275. numpy/ctypeslib/_ctypeslib.py +603 -0
  276. numpy/ctypeslib/_ctypeslib.pyi +236 -0
  277. numpy/doc/ufuncs.py +138 -0
  278. numpy/dtypes.py +41 -0
  279. numpy/dtypes.pyi +630 -0
  280. numpy/exceptions.py +246 -0
  281. numpy/exceptions.pyi +27 -0
  282. numpy/f2py/__init__.py +86 -0
  283. numpy/f2py/__init__.pyi +5 -0
  284. numpy/f2py/__main__.py +5 -0
  285. numpy/f2py/__version__.py +1 -0
  286. numpy/f2py/__version__.pyi +1 -0
  287. numpy/f2py/_backends/__init__.py +9 -0
  288. numpy/f2py/_backends/__init__.pyi +5 -0
  289. numpy/f2py/_backends/_backend.py +44 -0
  290. numpy/f2py/_backends/_backend.pyi +46 -0
  291. numpy/f2py/_backends/_distutils.py +76 -0
  292. numpy/f2py/_backends/_distutils.pyi +13 -0
  293. numpy/f2py/_backends/_meson.py +244 -0
  294. numpy/f2py/_backends/_meson.pyi +62 -0
  295. numpy/f2py/_backends/meson.build.template +58 -0
  296. numpy/f2py/_isocbind.py +62 -0
  297. numpy/f2py/_isocbind.pyi +13 -0
  298. numpy/f2py/_src_pyf.py +247 -0
  299. numpy/f2py/_src_pyf.pyi +28 -0
  300. numpy/f2py/auxfuncs.py +1004 -0
  301. numpy/f2py/auxfuncs.pyi +262 -0
  302. numpy/f2py/capi_maps.py +811 -0
  303. numpy/f2py/capi_maps.pyi +33 -0
  304. numpy/f2py/cb_rules.py +665 -0
  305. numpy/f2py/cb_rules.pyi +17 -0
  306. numpy/f2py/cfuncs.py +1563 -0
  307. numpy/f2py/cfuncs.pyi +31 -0
  308. numpy/f2py/common_rules.py +143 -0
  309. numpy/f2py/common_rules.pyi +9 -0
  310. numpy/f2py/crackfortran.py +3725 -0
  311. numpy/f2py/crackfortran.pyi +266 -0
  312. numpy/f2py/diagnose.py +149 -0
  313. numpy/f2py/diagnose.pyi +1 -0
  314. numpy/f2py/f2py2e.py +788 -0
  315. numpy/f2py/f2py2e.pyi +74 -0
  316. numpy/f2py/f90mod_rules.py +269 -0
  317. numpy/f2py/f90mod_rules.pyi +16 -0
  318. numpy/f2py/func2subr.py +329 -0
  319. numpy/f2py/func2subr.pyi +7 -0
  320. numpy/f2py/rules.py +1629 -0
  321. numpy/f2py/rules.pyi +41 -0
  322. numpy/f2py/setup.cfg +3 -0
  323. numpy/f2py/src/fortranobject.c +1436 -0
  324. numpy/f2py/src/fortranobject.h +173 -0
  325. numpy/f2py/symbolic.py +1518 -0
  326. numpy/f2py/symbolic.pyi +219 -0
  327. numpy/f2py/tests/__init__.py +16 -0
  328. numpy/f2py/tests/src/abstract_interface/foo.f90 +34 -0
  329. numpy/f2py/tests/src/abstract_interface/gh18403_mod.f90 +6 -0
  330. numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c +235 -0
  331. numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap +1 -0
  332. numpy/f2py/tests/src/assumed_shape/foo_free.f90 +34 -0
  333. numpy/f2py/tests/src/assumed_shape/foo_mod.f90 +41 -0
  334. numpy/f2py/tests/src/assumed_shape/foo_use.f90 +19 -0
  335. numpy/f2py/tests/src/assumed_shape/precision.f90 +4 -0
  336. numpy/f2py/tests/src/block_docstring/foo.f +6 -0
  337. numpy/f2py/tests/src/callback/foo.f +62 -0
  338. numpy/f2py/tests/src/callback/gh17797.f90 +7 -0
  339. numpy/f2py/tests/src/callback/gh18335.f90 +17 -0
  340. numpy/f2py/tests/src/callback/gh25211.f +10 -0
  341. numpy/f2py/tests/src/callback/gh25211.pyf +18 -0
  342. numpy/f2py/tests/src/callback/gh26681.f90 +18 -0
  343. numpy/f2py/tests/src/cli/gh_22819.pyf +6 -0
  344. numpy/f2py/tests/src/cli/hi77.f +3 -0
  345. numpy/f2py/tests/src/cli/hiworld.f90 +3 -0
  346. numpy/f2py/tests/src/common/block.f +11 -0
  347. numpy/f2py/tests/src/common/gh19161.f90 +10 -0
  348. numpy/f2py/tests/src/crackfortran/accesstype.f90 +13 -0
  349. numpy/f2py/tests/src/crackfortran/common_with_division.f +17 -0
  350. numpy/f2py/tests/src/crackfortran/data_common.f +8 -0
  351. numpy/f2py/tests/src/crackfortran/data_multiplier.f +5 -0
  352. numpy/f2py/tests/src/crackfortran/data_stmts.f90 +20 -0
  353. numpy/f2py/tests/src/crackfortran/data_with_comments.f +8 -0
  354. numpy/f2py/tests/src/crackfortran/foo_deps.f90 +6 -0
  355. numpy/f2py/tests/src/crackfortran/gh15035.f +16 -0
  356. numpy/f2py/tests/src/crackfortran/gh17859.f +12 -0
  357. numpy/f2py/tests/src/crackfortran/gh22648.pyf +7 -0
  358. numpy/f2py/tests/src/crackfortran/gh23533.f +5 -0
  359. numpy/f2py/tests/src/crackfortran/gh23598.f90 +4 -0
  360. numpy/f2py/tests/src/crackfortran/gh23598Warn.f90 +11 -0
  361. numpy/f2py/tests/src/crackfortran/gh23879.f90 +20 -0
  362. numpy/f2py/tests/src/crackfortran/gh27697.f90 +12 -0
  363. numpy/f2py/tests/src/crackfortran/gh2848.f90 +13 -0
  364. numpy/f2py/tests/src/crackfortran/operators.f90 +49 -0
  365. numpy/f2py/tests/src/crackfortran/privatemod.f90 +11 -0
  366. numpy/f2py/tests/src/crackfortran/publicmod.f90 +10 -0
  367. numpy/f2py/tests/src/crackfortran/pubprivmod.f90 +10 -0
  368. numpy/f2py/tests/src/crackfortran/unicode_comment.f90 +4 -0
  369. numpy/f2py/tests/src/f2cmap/.f2py_f2cmap +1 -0
  370. numpy/f2py/tests/src/f2cmap/isoFortranEnvMap.f90 +9 -0
  371. numpy/f2py/tests/src/isocintrin/isoCtests.f90 +34 -0
  372. numpy/f2py/tests/src/kind/foo.f90 +20 -0
  373. numpy/f2py/tests/src/mixed/foo.f +5 -0
  374. numpy/f2py/tests/src/mixed/foo_fixed.f90 +8 -0
  375. numpy/f2py/tests/src/mixed/foo_free.f90 +8 -0
  376. numpy/f2py/tests/src/modules/gh25337/data.f90 +8 -0
  377. numpy/f2py/tests/src/modules/gh25337/use_data.f90 +6 -0
  378. numpy/f2py/tests/src/modules/gh26920/two_mods_with_no_public_entities.f90 +21 -0
  379. numpy/f2py/tests/src/modules/gh26920/two_mods_with_one_public_routine.f90 +21 -0
  380. numpy/f2py/tests/src/modules/module_data_docstring.f90 +12 -0
  381. numpy/f2py/tests/src/modules/use_modules.f90 +20 -0
  382. numpy/f2py/tests/src/negative_bounds/issue_20853.f90 +7 -0
  383. numpy/f2py/tests/src/parameter/constant_array.f90 +45 -0
  384. numpy/f2py/tests/src/parameter/constant_both.f90 +57 -0
  385. numpy/f2py/tests/src/parameter/constant_compound.f90 +15 -0
  386. numpy/f2py/tests/src/parameter/constant_integer.f90 +22 -0
  387. numpy/f2py/tests/src/parameter/constant_non_compound.f90 +23 -0
  388. numpy/f2py/tests/src/parameter/constant_real.f90 +23 -0
  389. numpy/f2py/tests/src/quoted_character/foo.f +14 -0
  390. numpy/f2py/tests/src/regression/AB.inc +1 -0
  391. numpy/f2py/tests/src/regression/assignOnlyModule.f90 +25 -0
  392. numpy/f2py/tests/src/regression/datonly.f90 +17 -0
  393. numpy/f2py/tests/src/regression/f77comments.f +26 -0
  394. numpy/f2py/tests/src/regression/f77fixedform.f95 +5 -0
  395. numpy/f2py/tests/src/regression/f90continuation.f90 +9 -0
  396. numpy/f2py/tests/src/regression/incfile.f90 +5 -0
  397. numpy/f2py/tests/src/regression/inout.f90 +9 -0
  398. numpy/f2py/tests/src/regression/lower_f2py_fortran.f90 +5 -0
  399. numpy/f2py/tests/src/regression/mod_derived_types.f90 +23 -0
  400. numpy/f2py/tests/src/return_character/foo77.f +45 -0
  401. numpy/f2py/tests/src/return_character/foo90.f90 +48 -0
  402. numpy/f2py/tests/src/return_complex/foo77.f +45 -0
  403. numpy/f2py/tests/src/return_complex/foo90.f90 +48 -0
  404. numpy/f2py/tests/src/return_integer/foo77.f +56 -0
  405. numpy/f2py/tests/src/return_integer/foo90.f90 +59 -0
  406. numpy/f2py/tests/src/return_logical/foo77.f +56 -0
  407. numpy/f2py/tests/src/return_logical/foo90.f90 +59 -0
  408. numpy/f2py/tests/src/return_real/foo77.f +45 -0
  409. numpy/f2py/tests/src/return_real/foo90.f90 +48 -0
  410. numpy/f2py/tests/src/routines/funcfortranname.f +5 -0
  411. numpy/f2py/tests/src/routines/funcfortranname.pyf +11 -0
  412. numpy/f2py/tests/src/routines/subrout.f +4 -0
  413. numpy/f2py/tests/src/routines/subrout.pyf +10 -0
  414. numpy/f2py/tests/src/size/foo.f90 +44 -0
  415. numpy/f2py/tests/src/string/char.f90 +29 -0
  416. numpy/f2py/tests/src/string/fixed_string.f90 +34 -0
  417. numpy/f2py/tests/src/string/gh24008.f +8 -0
  418. numpy/f2py/tests/src/string/gh24662.f90 +7 -0
  419. numpy/f2py/tests/src/string/gh25286.f90 +14 -0
  420. numpy/f2py/tests/src/string/gh25286.pyf +12 -0
  421. numpy/f2py/tests/src/string/gh25286_bc.pyf +12 -0
  422. numpy/f2py/tests/src/string/scalar_string.f90 +9 -0
  423. numpy/f2py/tests/src/string/string.f +12 -0
  424. numpy/f2py/tests/src/value_attrspec/gh21665.f90 +9 -0
  425. numpy/f2py/tests/test_abstract_interface.py +26 -0
  426. numpy/f2py/tests/test_array_from_pyobj.py +678 -0
  427. numpy/f2py/tests/test_assumed_shape.py +50 -0
  428. numpy/f2py/tests/test_block_docstring.py +20 -0
  429. numpy/f2py/tests/test_callback.py +263 -0
  430. numpy/f2py/tests/test_character.py +641 -0
  431. numpy/f2py/tests/test_common.py +23 -0
  432. numpy/f2py/tests/test_crackfortran.py +421 -0
  433. numpy/f2py/tests/test_data.py +71 -0
  434. numpy/f2py/tests/test_docs.py +66 -0
  435. numpy/f2py/tests/test_f2cmap.py +17 -0
  436. numpy/f2py/tests/test_f2py2e.py +983 -0
  437. numpy/f2py/tests/test_isoc.py +56 -0
  438. numpy/f2py/tests/test_kind.py +52 -0
  439. numpy/f2py/tests/test_mixed.py +35 -0
  440. numpy/f2py/tests/test_modules.py +83 -0
  441. numpy/f2py/tests/test_parameter.py +129 -0
  442. numpy/f2py/tests/test_pyf_src.py +43 -0
  443. numpy/f2py/tests/test_quoted_character.py +18 -0
  444. numpy/f2py/tests/test_regression.py +187 -0
  445. numpy/f2py/tests/test_return_character.py +48 -0
  446. numpy/f2py/tests/test_return_complex.py +67 -0
  447. numpy/f2py/tests/test_return_integer.py +55 -0
  448. numpy/f2py/tests/test_return_logical.py +65 -0
  449. numpy/f2py/tests/test_return_real.py +109 -0
  450. numpy/f2py/tests/test_routines.py +29 -0
  451. numpy/f2py/tests/test_semicolon_split.py +75 -0
  452. numpy/f2py/tests/test_size.py +45 -0
  453. numpy/f2py/tests/test_string.py +100 -0
  454. numpy/f2py/tests/test_symbolic.py +500 -0
  455. numpy/f2py/tests/test_value_attrspec.py +15 -0
  456. numpy/f2py/tests/util.py +442 -0
  457. numpy/f2py/use_rules.py +99 -0
  458. numpy/f2py/use_rules.pyi +9 -0
  459. numpy/fft/__init__.py +213 -0
  460. numpy/fft/__init__.pyi +38 -0
  461. numpy/fft/_helper.py +235 -0
  462. numpy/fft/_helper.pyi +44 -0
  463. numpy/fft/_pocketfft.py +1693 -0
  464. numpy/fft/_pocketfft.pyi +137 -0
  465. numpy/fft/_pocketfft_umath.cpython-313t-aarch64-linux-musl.so +0 -0
  466. numpy/fft/tests/__init__.py +0 -0
  467. numpy/fft/tests/test_helper.py +167 -0
  468. numpy/fft/tests/test_pocketfft.py +589 -0
  469. numpy/lib/__init__.py +97 -0
  470. numpy/lib/__init__.pyi +52 -0
  471. numpy/lib/_array_utils_impl.py +62 -0
  472. numpy/lib/_array_utils_impl.pyi +10 -0
  473. numpy/lib/_arraypad_impl.py +926 -0
  474. numpy/lib/_arraypad_impl.pyi +88 -0
  475. numpy/lib/_arraysetops_impl.py +1158 -0
  476. numpy/lib/_arraysetops_impl.pyi +462 -0
  477. numpy/lib/_arrayterator_impl.py +224 -0
  478. numpy/lib/_arrayterator_impl.pyi +45 -0
  479. numpy/lib/_datasource.py +700 -0
  480. numpy/lib/_datasource.pyi +30 -0
  481. numpy/lib/_format_impl.py +1036 -0
  482. numpy/lib/_format_impl.pyi +56 -0
  483. numpy/lib/_function_base_impl.py +5758 -0
  484. numpy/lib/_function_base_impl.pyi +2324 -0
  485. numpy/lib/_histograms_impl.py +1085 -0
  486. numpy/lib/_histograms_impl.pyi +40 -0
  487. numpy/lib/_index_tricks_impl.py +1048 -0
  488. numpy/lib/_index_tricks_impl.pyi +267 -0
  489. numpy/lib/_iotools.py +900 -0
  490. numpy/lib/_iotools.pyi +116 -0
  491. numpy/lib/_nanfunctions_impl.py +2001 -0
  492. numpy/lib/_nanfunctions_impl.pyi +48 -0
  493. numpy/lib/_npyio_impl.py +2583 -0
  494. numpy/lib/_npyio_impl.pyi +299 -0
  495. numpy/lib/_polynomial_impl.py +1465 -0
  496. numpy/lib/_polynomial_impl.pyi +338 -0
  497. numpy/lib/_scimath_impl.py +642 -0
  498. numpy/lib/_scimath_impl.pyi +93 -0
  499. numpy/lib/_shape_base_impl.py +1289 -0
  500. numpy/lib/_shape_base_impl.pyi +236 -0
  501. numpy/lib/_stride_tricks_impl.py +582 -0
  502. numpy/lib/_stride_tricks_impl.pyi +73 -0
  503. numpy/lib/_twodim_base_impl.py +1201 -0
  504. numpy/lib/_twodim_base_impl.pyi +408 -0
  505. numpy/lib/_type_check_impl.py +710 -0
  506. numpy/lib/_type_check_impl.pyi +348 -0
  507. numpy/lib/_ufunclike_impl.py +199 -0
  508. numpy/lib/_ufunclike_impl.pyi +60 -0
  509. numpy/lib/_user_array_impl.py +310 -0
  510. numpy/lib/_user_array_impl.pyi +226 -0
  511. numpy/lib/_utils_impl.py +784 -0
  512. numpy/lib/_utils_impl.pyi +22 -0
  513. numpy/lib/_version.py +153 -0
  514. numpy/lib/_version.pyi +17 -0
  515. numpy/lib/array_utils.py +7 -0
  516. numpy/lib/array_utils.pyi +6 -0
  517. numpy/lib/format.py +24 -0
  518. numpy/lib/format.pyi +24 -0
  519. numpy/lib/introspect.py +94 -0
  520. numpy/lib/introspect.pyi +3 -0
  521. numpy/lib/mixins.py +180 -0
  522. numpy/lib/mixins.pyi +78 -0
  523. numpy/lib/npyio.py +1 -0
  524. numpy/lib/npyio.pyi +5 -0
  525. numpy/lib/recfunctions.py +1681 -0
  526. numpy/lib/recfunctions.pyi +444 -0
  527. numpy/lib/scimath.py +13 -0
  528. numpy/lib/scimath.pyi +12 -0
  529. numpy/lib/stride_tricks.py +1 -0
  530. numpy/lib/stride_tricks.pyi +4 -0
  531. numpy/lib/tests/__init__.py +0 -0
  532. numpy/lib/tests/data/py2-np0-objarr.npy +0 -0
  533. numpy/lib/tests/data/py2-objarr.npy +0 -0
  534. numpy/lib/tests/data/py2-objarr.npz +0 -0
  535. numpy/lib/tests/data/py3-objarr.npy +0 -0
  536. numpy/lib/tests/data/py3-objarr.npz +0 -0
  537. numpy/lib/tests/data/python3.npy +0 -0
  538. numpy/lib/tests/data/win64python2.npy +0 -0
  539. numpy/lib/tests/test__datasource.py +328 -0
  540. numpy/lib/tests/test__iotools.py +358 -0
  541. numpy/lib/tests/test__version.py +64 -0
  542. numpy/lib/tests/test_array_utils.py +32 -0
  543. numpy/lib/tests/test_arraypad.py +1427 -0
  544. numpy/lib/tests/test_arraysetops.py +1302 -0
  545. numpy/lib/tests/test_arrayterator.py +45 -0
  546. numpy/lib/tests/test_format.py +1054 -0
  547. numpy/lib/tests/test_function_base.py +4705 -0
  548. numpy/lib/tests/test_histograms.py +855 -0
  549. numpy/lib/tests/test_index_tricks.py +693 -0
  550. numpy/lib/tests/test_io.py +2857 -0
  551. numpy/lib/tests/test_loadtxt.py +1099 -0
  552. numpy/lib/tests/test_mixins.py +215 -0
  553. numpy/lib/tests/test_nanfunctions.py +1438 -0
  554. numpy/lib/tests/test_packbits.py +376 -0
  555. numpy/lib/tests/test_polynomial.py +325 -0
  556. numpy/lib/tests/test_recfunctions.py +1042 -0
  557. numpy/lib/tests/test_regression.py +231 -0
  558. numpy/lib/tests/test_shape_base.py +813 -0
  559. numpy/lib/tests/test_stride_tricks.py +655 -0
  560. numpy/lib/tests/test_twodim_base.py +559 -0
  561. numpy/lib/tests/test_type_check.py +473 -0
  562. numpy/lib/tests/test_ufunclike.py +97 -0
  563. numpy/lib/tests/test_utils.py +80 -0
  564. numpy/lib/user_array.py +1 -0
  565. numpy/lib/user_array.pyi +1 -0
  566. numpy/linalg/__init__.py +95 -0
  567. numpy/linalg/__init__.pyi +71 -0
  568. numpy/linalg/_linalg.py +3657 -0
  569. numpy/linalg/_linalg.pyi +548 -0
  570. numpy/linalg/_umath_linalg.cpython-313t-aarch64-linux-musl.so +0 -0
  571. numpy/linalg/_umath_linalg.pyi +60 -0
  572. numpy/linalg/lapack_lite.cpython-313t-aarch64-linux-musl.so +0 -0
  573. numpy/linalg/lapack_lite.pyi +143 -0
  574. numpy/linalg/tests/__init__.py +0 -0
  575. numpy/linalg/tests/test_deprecations.py +21 -0
  576. numpy/linalg/tests/test_linalg.py +2442 -0
  577. numpy/linalg/tests/test_regression.py +182 -0
  578. numpy/ma/API_CHANGES.txt +135 -0
  579. numpy/ma/LICENSE +24 -0
  580. numpy/ma/README.rst +236 -0
  581. numpy/ma/__init__.py +53 -0
  582. numpy/ma/__init__.pyi +458 -0
  583. numpy/ma/core.py +8929 -0
  584. numpy/ma/core.pyi +3720 -0
  585. numpy/ma/extras.py +2266 -0
  586. numpy/ma/extras.pyi +297 -0
  587. numpy/ma/mrecords.py +762 -0
  588. numpy/ma/mrecords.pyi +96 -0
  589. numpy/ma/tests/__init__.py +0 -0
  590. numpy/ma/tests/test_arrayobject.py +40 -0
  591. numpy/ma/tests/test_core.py +6008 -0
  592. numpy/ma/tests/test_deprecations.py +65 -0
  593. numpy/ma/tests/test_extras.py +1945 -0
  594. numpy/ma/tests/test_mrecords.py +495 -0
  595. numpy/ma/tests/test_old_ma.py +939 -0
  596. numpy/ma/tests/test_regression.py +83 -0
  597. numpy/ma/tests/test_subclassing.py +469 -0
  598. numpy/ma/testutils.py +294 -0
  599. numpy/ma/testutils.pyi +69 -0
  600. numpy/matlib.py +380 -0
  601. numpy/matlib.pyi +580 -0
  602. numpy/matrixlib/__init__.py +12 -0
  603. numpy/matrixlib/__init__.pyi +3 -0
  604. numpy/matrixlib/defmatrix.py +1119 -0
  605. numpy/matrixlib/defmatrix.pyi +218 -0
  606. numpy/matrixlib/tests/__init__.py +0 -0
  607. numpy/matrixlib/tests/test_defmatrix.py +455 -0
  608. numpy/matrixlib/tests/test_interaction.py +360 -0
  609. numpy/matrixlib/tests/test_masked_matrix.py +240 -0
  610. numpy/matrixlib/tests/test_matrix_linalg.py +110 -0
  611. numpy/matrixlib/tests/test_multiarray.py +17 -0
  612. numpy/matrixlib/tests/test_numeric.py +18 -0
  613. numpy/matrixlib/tests/test_regression.py +31 -0
  614. numpy/polynomial/__init__.py +187 -0
  615. numpy/polynomial/__init__.pyi +31 -0
  616. numpy/polynomial/_polybase.py +1191 -0
  617. numpy/polynomial/_polybase.pyi +262 -0
  618. numpy/polynomial/_polytypes.pyi +501 -0
  619. numpy/polynomial/chebyshev.py +2001 -0
  620. numpy/polynomial/chebyshev.pyi +180 -0
  621. numpy/polynomial/hermite.py +1738 -0
  622. numpy/polynomial/hermite.pyi +106 -0
  623. numpy/polynomial/hermite_e.py +1640 -0
  624. numpy/polynomial/hermite_e.pyi +106 -0
  625. numpy/polynomial/laguerre.py +1673 -0
  626. numpy/polynomial/laguerre.pyi +100 -0
  627. numpy/polynomial/legendre.py +1603 -0
  628. numpy/polynomial/legendre.pyi +100 -0
  629. numpy/polynomial/polynomial.py +1625 -0
  630. numpy/polynomial/polynomial.pyi +109 -0
  631. numpy/polynomial/polyutils.py +759 -0
  632. numpy/polynomial/polyutils.pyi +307 -0
  633. numpy/polynomial/tests/__init__.py +0 -0
  634. numpy/polynomial/tests/test_chebyshev.py +618 -0
  635. numpy/polynomial/tests/test_classes.py +613 -0
  636. numpy/polynomial/tests/test_hermite.py +553 -0
  637. numpy/polynomial/tests/test_hermite_e.py +554 -0
  638. numpy/polynomial/tests/test_laguerre.py +535 -0
  639. numpy/polynomial/tests/test_legendre.py +566 -0
  640. numpy/polynomial/tests/test_polynomial.py +691 -0
  641. numpy/polynomial/tests/test_polyutils.py +123 -0
  642. numpy/polynomial/tests/test_printing.py +557 -0
  643. numpy/polynomial/tests/test_symbol.py +217 -0
  644. numpy/py.typed +0 -0
  645. numpy/random/LICENSE.md +71 -0
  646. numpy/random/__init__.pxd +14 -0
  647. numpy/random/__init__.py +213 -0
  648. numpy/random/__init__.pyi +124 -0
  649. numpy/random/_bounded_integers.cpython-313t-aarch64-linux-musl.so +0 -0
  650. numpy/random/_bounded_integers.pxd +29 -0
  651. numpy/random/_bounded_integers.pyi +1 -0
  652. numpy/random/_common.cpython-313t-aarch64-linux-musl.so +0 -0
  653. numpy/random/_common.pxd +107 -0
  654. numpy/random/_common.pyi +16 -0
  655. numpy/random/_examples/cffi/extending.py +44 -0
  656. numpy/random/_examples/cffi/parse.py +53 -0
  657. numpy/random/_examples/cython/extending.pyx +77 -0
  658. numpy/random/_examples/cython/extending_distributions.pyx +117 -0
  659. numpy/random/_examples/cython/meson.build +53 -0
  660. numpy/random/_examples/numba/extending.py +86 -0
  661. numpy/random/_examples/numba/extending_distributions.py +67 -0
  662. numpy/random/_generator.cpython-313t-aarch64-linux-musl.so +0 -0
  663. numpy/random/_generator.pyi +862 -0
  664. numpy/random/_mt19937.cpython-313t-aarch64-linux-musl.so +0 -0
  665. numpy/random/_mt19937.pyi +27 -0
  666. numpy/random/_pcg64.cpython-313t-aarch64-linux-musl.so +0 -0
  667. numpy/random/_pcg64.pyi +41 -0
  668. numpy/random/_philox.cpython-313t-aarch64-linux-musl.so +0 -0
  669. numpy/random/_philox.pyi +36 -0
  670. numpy/random/_pickle.py +88 -0
  671. numpy/random/_pickle.pyi +43 -0
  672. numpy/random/_sfc64.cpython-313t-aarch64-linux-musl.so +0 -0
  673. numpy/random/_sfc64.pyi +25 -0
  674. numpy/random/bit_generator.cpython-313t-aarch64-linux-musl.so +0 -0
  675. numpy/random/bit_generator.pxd +35 -0
  676. numpy/random/bit_generator.pyi +123 -0
  677. numpy/random/c_distributions.pxd +119 -0
  678. numpy/random/lib/libnpyrandom.a +0 -0
  679. numpy/random/mtrand.cpython-313t-aarch64-linux-musl.so +0 -0
  680. numpy/random/mtrand.pyi +759 -0
  681. numpy/random/tests/__init__.py +0 -0
  682. numpy/random/tests/data/__init__.py +0 -0
  683. numpy/random/tests/data/generator_pcg64_np121.pkl.gz +0 -0
  684. numpy/random/tests/data/generator_pcg64_np126.pkl.gz +0 -0
  685. numpy/random/tests/data/mt19937-testset-1.csv +1001 -0
  686. numpy/random/tests/data/mt19937-testset-2.csv +1001 -0
  687. numpy/random/tests/data/pcg64-testset-1.csv +1001 -0
  688. numpy/random/tests/data/pcg64-testset-2.csv +1001 -0
  689. numpy/random/tests/data/pcg64dxsm-testset-1.csv +1001 -0
  690. numpy/random/tests/data/pcg64dxsm-testset-2.csv +1001 -0
  691. numpy/random/tests/data/philox-testset-1.csv +1001 -0
  692. numpy/random/tests/data/philox-testset-2.csv +1001 -0
  693. numpy/random/tests/data/sfc64-testset-1.csv +1001 -0
  694. numpy/random/tests/data/sfc64-testset-2.csv +1001 -0
  695. numpy/random/tests/data/sfc64_np126.pkl.gz +0 -0
  696. numpy/random/tests/test_direct.py +595 -0
  697. numpy/random/tests/test_extending.py +131 -0
  698. numpy/random/tests/test_generator_mt19937.py +2825 -0
  699. numpy/random/tests/test_generator_mt19937_regressions.py +221 -0
  700. numpy/random/tests/test_random.py +1724 -0
  701. numpy/random/tests/test_randomstate.py +2099 -0
  702. numpy/random/tests/test_randomstate_regression.py +213 -0
  703. numpy/random/tests/test_regression.py +175 -0
  704. numpy/random/tests/test_seed_sequence.py +79 -0
  705. numpy/random/tests/test_smoke.py +882 -0
  706. numpy/rec/__init__.py +2 -0
  707. numpy/rec/__init__.pyi +23 -0
  708. numpy/strings/__init__.py +2 -0
  709. numpy/strings/__init__.pyi +97 -0
  710. numpy/testing/__init__.py +22 -0
  711. numpy/testing/__init__.pyi +107 -0
  712. numpy/testing/_private/__init__.py +0 -0
  713. numpy/testing/_private/__init__.pyi +0 -0
  714. numpy/testing/_private/extbuild.py +250 -0
  715. numpy/testing/_private/extbuild.pyi +25 -0
  716. numpy/testing/_private/utils.py +2830 -0
  717. numpy/testing/_private/utils.pyi +505 -0
  718. numpy/testing/overrides.py +84 -0
  719. numpy/testing/overrides.pyi +10 -0
  720. numpy/testing/print_coercion_tables.py +207 -0
  721. numpy/testing/print_coercion_tables.pyi +26 -0
  722. numpy/testing/tests/__init__.py +0 -0
  723. numpy/testing/tests/test_utils.py +2123 -0
  724. numpy/tests/__init__.py +0 -0
  725. numpy/tests/test__all__.py +10 -0
  726. numpy/tests/test_configtool.py +51 -0
  727. numpy/tests/test_ctypeslib.py +383 -0
  728. numpy/tests/test_lazyloading.py +42 -0
  729. numpy/tests/test_matlib.py +59 -0
  730. numpy/tests/test_numpy_config.py +47 -0
  731. numpy/tests/test_numpy_version.py +54 -0
  732. numpy/tests/test_public_api.py +804 -0
  733. numpy/tests/test_reloading.py +76 -0
  734. numpy/tests/test_scripts.py +48 -0
  735. numpy/tests/test_warnings.py +79 -0
  736. numpy/typing/__init__.py +233 -0
  737. numpy/typing/__init__.pyi +3 -0
  738. numpy/typing/mypy_plugin.py +200 -0
  739. numpy/typing/tests/__init__.py +0 -0
  740. numpy/typing/tests/data/fail/arithmetic.pyi +126 -0
  741. numpy/typing/tests/data/fail/array_constructors.pyi +34 -0
  742. numpy/typing/tests/data/fail/array_like.pyi +15 -0
  743. numpy/typing/tests/data/fail/array_pad.pyi +6 -0
  744. numpy/typing/tests/data/fail/arrayprint.pyi +15 -0
  745. numpy/typing/tests/data/fail/arrayterator.pyi +14 -0
  746. numpy/typing/tests/data/fail/bitwise_ops.pyi +17 -0
  747. numpy/typing/tests/data/fail/char.pyi +63 -0
  748. numpy/typing/tests/data/fail/chararray.pyi +61 -0
  749. numpy/typing/tests/data/fail/comparisons.pyi +27 -0
  750. numpy/typing/tests/data/fail/constants.pyi +3 -0
  751. numpy/typing/tests/data/fail/datasource.pyi +16 -0
  752. numpy/typing/tests/data/fail/dtype.pyi +17 -0
  753. numpy/typing/tests/data/fail/einsumfunc.pyi +12 -0
  754. numpy/typing/tests/data/fail/flatiter.pyi +38 -0
  755. numpy/typing/tests/data/fail/fromnumeric.pyi +148 -0
  756. numpy/typing/tests/data/fail/histograms.pyi +12 -0
  757. numpy/typing/tests/data/fail/index_tricks.pyi +14 -0
  758. numpy/typing/tests/data/fail/lib_function_base.pyi +60 -0
  759. numpy/typing/tests/data/fail/lib_polynomial.pyi +29 -0
  760. numpy/typing/tests/data/fail/lib_utils.pyi +3 -0
  761. numpy/typing/tests/data/fail/lib_version.pyi +6 -0
  762. numpy/typing/tests/data/fail/linalg.pyi +52 -0
  763. numpy/typing/tests/data/fail/ma.pyi +155 -0
  764. numpy/typing/tests/data/fail/memmap.pyi +5 -0
  765. numpy/typing/tests/data/fail/modules.pyi +17 -0
  766. numpy/typing/tests/data/fail/multiarray.pyi +52 -0
  767. numpy/typing/tests/data/fail/ndarray.pyi +11 -0
  768. numpy/typing/tests/data/fail/ndarray_misc.pyi +49 -0
  769. numpy/typing/tests/data/fail/nditer.pyi +8 -0
  770. numpy/typing/tests/data/fail/nested_sequence.pyi +17 -0
  771. numpy/typing/tests/data/fail/npyio.pyi +24 -0
  772. numpy/typing/tests/data/fail/numerictypes.pyi +5 -0
  773. numpy/typing/tests/data/fail/random.pyi +62 -0
  774. numpy/typing/tests/data/fail/rec.pyi +17 -0
  775. numpy/typing/tests/data/fail/scalars.pyi +86 -0
  776. numpy/typing/tests/data/fail/shape.pyi +7 -0
  777. numpy/typing/tests/data/fail/shape_base.pyi +8 -0
  778. numpy/typing/tests/data/fail/stride_tricks.pyi +9 -0
  779. numpy/typing/tests/data/fail/strings.pyi +52 -0
  780. numpy/typing/tests/data/fail/testing.pyi +28 -0
  781. numpy/typing/tests/data/fail/twodim_base.pyi +39 -0
  782. numpy/typing/tests/data/fail/type_check.pyi +12 -0
  783. numpy/typing/tests/data/fail/ufunc_config.pyi +21 -0
  784. numpy/typing/tests/data/fail/ufunclike.pyi +21 -0
  785. numpy/typing/tests/data/fail/ufuncs.pyi +17 -0
  786. numpy/typing/tests/data/fail/warnings_and_errors.pyi +5 -0
  787. numpy/typing/tests/data/misc/extended_precision.pyi +9 -0
  788. numpy/typing/tests/data/mypy.ini +8 -0
  789. numpy/typing/tests/data/pass/arithmetic.py +614 -0
  790. numpy/typing/tests/data/pass/array_constructors.py +138 -0
  791. numpy/typing/tests/data/pass/array_like.py +43 -0
  792. numpy/typing/tests/data/pass/arrayprint.py +37 -0
  793. numpy/typing/tests/data/pass/arrayterator.py +28 -0
  794. numpy/typing/tests/data/pass/bitwise_ops.py +131 -0
  795. numpy/typing/tests/data/pass/comparisons.py +316 -0
  796. numpy/typing/tests/data/pass/dtype.py +57 -0
  797. numpy/typing/tests/data/pass/einsumfunc.py +36 -0
  798. numpy/typing/tests/data/pass/flatiter.py +26 -0
  799. numpy/typing/tests/data/pass/fromnumeric.py +272 -0
  800. numpy/typing/tests/data/pass/index_tricks.py +62 -0
  801. numpy/typing/tests/data/pass/lib_user_array.py +22 -0
  802. numpy/typing/tests/data/pass/lib_utils.py +19 -0
  803. numpy/typing/tests/data/pass/lib_version.py +18 -0
  804. numpy/typing/tests/data/pass/literal.py +52 -0
  805. numpy/typing/tests/data/pass/ma.py +199 -0
  806. numpy/typing/tests/data/pass/mod.py +149 -0
  807. numpy/typing/tests/data/pass/modules.py +45 -0
  808. numpy/typing/tests/data/pass/multiarray.py +77 -0
  809. numpy/typing/tests/data/pass/ndarray_conversion.py +81 -0
  810. numpy/typing/tests/data/pass/ndarray_misc.py +199 -0
  811. numpy/typing/tests/data/pass/ndarray_shape_manipulation.py +47 -0
  812. numpy/typing/tests/data/pass/nditer.py +4 -0
  813. numpy/typing/tests/data/pass/numeric.py +90 -0
  814. numpy/typing/tests/data/pass/numerictypes.py +17 -0
  815. numpy/typing/tests/data/pass/random.py +1498 -0
  816. numpy/typing/tests/data/pass/recfunctions.py +164 -0
  817. numpy/typing/tests/data/pass/scalars.py +249 -0
  818. numpy/typing/tests/data/pass/shape.py +19 -0
  819. numpy/typing/tests/data/pass/simple.py +170 -0
  820. numpy/typing/tests/data/pass/ufunc_config.py +64 -0
  821. numpy/typing/tests/data/pass/ufunclike.py +52 -0
  822. numpy/typing/tests/data/pass/ufuncs.py +16 -0
  823. numpy/typing/tests/data/pass/warnings_and_errors.py +6 -0
  824. numpy/typing/tests/data/reveal/arithmetic.pyi +719 -0
  825. numpy/typing/tests/data/reveal/array_api_info.pyi +70 -0
  826. numpy/typing/tests/data/reveal/array_constructors.pyi +277 -0
  827. numpy/typing/tests/data/reveal/arraypad.pyi +27 -0
  828. numpy/typing/tests/data/reveal/arrayprint.pyi +25 -0
  829. numpy/typing/tests/data/reveal/arraysetops.pyi +74 -0
  830. numpy/typing/tests/data/reveal/arrayterator.pyi +27 -0
  831. numpy/typing/tests/data/reveal/bitwise_ops.pyi +166 -0
  832. numpy/typing/tests/data/reveal/char.pyi +225 -0
  833. numpy/typing/tests/data/reveal/chararray.pyi +138 -0
  834. numpy/typing/tests/data/reveal/comparisons.pyi +264 -0
  835. numpy/typing/tests/data/reveal/constants.pyi +14 -0
  836. numpy/typing/tests/data/reveal/ctypeslib.pyi +81 -0
  837. numpy/typing/tests/data/reveal/datasource.pyi +23 -0
  838. numpy/typing/tests/data/reveal/dtype.pyi +132 -0
  839. numpy/typing/tests/data/reveal/einsumfunc.pyi +39 -0
  840. numpy/typing/tests/data/reveal/emath.pyi +54 -0
  841. numpy/typing/tests/data/reveal/fft.pyi +37 -0
  842. numpy/typing/tests/data/reveal/flatiter.pyi +86 -0
  843. numpy/typing/tests/data/reveal/fromnumeric.pyi +347 -0
  844. numpy/typing/tests/data/reveal/getlimits.pyi +53 -0
  845. numpy/typing/tests/data/reveal/histograms.pyi +25 -0
  846. numpy/typing/tests/data/reveal/index_tricks.pyi +70 -0
  847. numpy/typing/tests/data/reveal/lib_function_base.pyi +409 -0
  848. numpy/typing/tests/data/reveal/lib_polynomial.pyi +147 -0
  849. numpy/typing/tests/data/reveal/lib_utils.pyi +17 -0
  850. numpy/typing/tests/data/reveal/lib_version.pyi +20 -0
  851. numpy/typing/tests/data/reveal/linalg.pyi +154 -0
  852. numpy/typing/tests/data/reveal/ma.pyi +1098 -0
  853. numpy/typing/tests/data/reveal/matrix.pyi +73 -0
  854. numpy/typing/tests/data/reveal/memmap.pyi +19 -0
  855. numpy/typing/tests/data/reveal/mod.pyi +178 -0
  856. numpy/typing/tests/data/reveal/modules.pyi +51 -0
  857. numpy/typing/tests/data/reveal/multiarray.pyi +197 -0
  858. numpy/typing/tests/data/reveal/nbit_base_example.pyi +20 -0
  859. numpy/typing/tests/data/reveal/ndarray_assignability.pyi +82 -0
  860. numpy/typing/tests/data/reveal/ndarray_conversion.pyi +83 -0
  861. numpy/typing/tests/data/reveal/ndarray_misc.pyi +246 -0
  862. numpy/typing/tests/data/reveal/ndarray_shape_manipulation.pyi +47 -0
  863. numpy/typing/tests/data/reveal/nditer.pyi +49 -0
  864. numpy/typing/tests/data/reveal/nested_sequence.pyi +25 -0
  865. numpy/typing/tests/data/reveal/npyio.pyi +83 -0
  866. numpy/typing/tests/data/reveal/numeric.pyi +170 -0
  867. numpy/typing/tests/data/reveal/numerictypes.pyi +16 -0
  868. numpy/typing/tests/data/reveal/polynomial_polybase.pyi +217 -0
  869. numpy/typing/tests/data/reveal/polynomial_polyutils.pyi +218 -0
  870. numpy/typing/tests/data/reveal/polynomial_series.pyi +138 -0
  871. numpy/typing/tests/data/reveal/random.pyi +1546 -0
  872. numpy/typing/tests/data/reveal/rec.pyi +171 -0
  873. numpy/typing/tests/data/reveal/scalars.pyi +191 -0
  874. numpy/typing/tests/data/reveal/shape.pyi +13 -0
  875. numpy/typing/tests/data/reveal/shape_base.pyi +52 -0
  876. numpy/typing/tests/data/reveal/stride_tricks.pyi +27 -0
  877. numpy/typing/tests/data/reveal/strings.pyi +196 -0
  878. numpy/typing/tests/data/reveal/testing.pyi +198 -0
  879. numpy/typing/tests/data/reveal/twodim_base.pyi +225 -0
  880. numpy/typing/tests/data/reveal/type_check.pyi +67 -0
  881. numpy/typing/tests/data/reveal/ufunc_config.pyi +29 -0
  882. numpy/typing/tests/data/reveal/ufunclike.pyi +31 -0
  883. numpy/typing/tests/data/reveal/ufuncs.pyi +142 -0
  884. numpy/typing/tests/data/reveal/warnings_and_errors.pyi +11 -0
  885. numpy/typing/tests/test_isfile.py +38 -0
  886. numpy/typing/tests/test_runtime.py +110 -0
  887. numpy/typing/tests/test_typing.py +205 -0
  888. numpy/version.py +11 -0
  889. numpy/version.pyi +9 -0
  890. numpy-2.4.0.dist-info/METADATA +139 -0
  891. numpy-2.4.0.dist-info/RECORD +915 -0
  892. numpy-2.4.0.dist-info/WHEEL +5 -0
  893. numpy-2.4.0.dist-info/entry_points.txt +13 -0
  894. numpy-2.4.0.dist-info/licenses/LICENSE.txt +935 -0
  895. numpy-2.4.0.dist-info/licenses/numpy/_core/include/numpy/libdivide/LICENSE.txt +21 -0
  896. numpy-2.4.0.dist-info/licenses/numpy/_core/src/common/pythoncapi-compat/COPYING +14 -0
  897. numpy-2.4.0.dist-info/licenses/numpy/_core/src/highway/LICENSE +371 -0
  898. numpy-2.4.0.dist-info/licenses/numpy/_core/src/multiarray/dragon4_LICENSE.txt +27 -0
  899. numpy-2.4.0.dist-info/licenses/numpy/_core/src/npysort/x86-simd-sort/LICENSE.md +28 -0
  900. numpy-2.4.0.dist-info/licenses/numpy/_core/src/umath/svml/LICENSE +30 -0
  901. numpy-2.4.0.dist-info/licenses/numpy/fft/pocketfft/LICENSE.md +25 -0
  902. numpy-2.4.0.dist-info/licenses/numpy/linalg/lapack_lite/LICENSE.txt +48 -0
  903. numpy-2.4.0.dist-info/licenses/numpy/ma/LICENSE +24 -0
  904. numpy-2.4.0.dist-info/licenses/numpy/random/LICENSE.md +71 -0
  905. numpy-2.4.0.dist-info/licenses/numpy/random/src/distributions/LICENSE.md +61 -0
  906. numpy-2.4.0.dist-info/licenses/numpy/random/src/mt19937/LICENSE.md +61 -0
  907. numpy-2.4.0.dist-info/licenses/numpy/random/src/pcg64/LICENSE.md +22 -0
  908. numpy-2.4.0.dist-info/licenses/numpy/random/src/philox/LICENSE.md +31 -0
  909. numpy-2.4.0.dist-info/licenses/numpy/random/src/sfc64/LICENSE.md +27 -0
  910. numpy-2.4.0.dist-info/licenses/numpy/random/src/splitmix64/LICENSE.md +9 -0
  911. numpy.libs/libgcc_s-2d945d6c-767fb991.so.1 +0 -0
  912. numpy.libs/libgcc_s-2d945d6c.so.1 +0 -0
  913. numpy.libs/libgfortran-67378ab2-e7e7cfab.so.5.0.0 +0 -0
  914. numpy.libs/libscipy_openblas64_-1fc386ee.so +0 -0
  915. numpy.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
@@ -0,0 +1,3725 @@
1
+ """
2
+ crackfortran --- read fortran (77,90) code and extract declaration information.
3
+
4
+ Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
5
+ Copyright 2011 -- present NumPy Developers.
6
+ Permission to use, modify, and distribute this software is given under the
7
+ terms of the NumPy License.
8
+
9
+ NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
10
+
11
+
12
+ Usage of crackfortran:
13
+ ======================
14
+ Command line keys: -quiet,-verbose,-fix,-f77,-f90,-show,-h <pyffilename>
15
+ -m <module name for f77 routines>,--ignore-contains
16
+ Functions: crackfortran, crack2fortran
17
+ The following Fortran statements/constructions are supported
18
+ (or will be if needed):
19
+ block data,byte,call,character,common,complex,contains,data,
20
+ dimension,double complex,double precision,end,external,function,
21
+ implicit,integer,intent,interface,intrinsic,
22
+ logical,module,optional,parameter,private,public,
23
+ program,real,(sequence?),subroutine,type,use,virtual,
24
+ include,pythonmodule
25
+ Note: 'virtual' is mapped to 'dimension'.
26
+ Note: 'implicit integer (z) static (z)' is 'implicit static (z)' (this is minor bug).
27
+ Note: code after 'contains' will be ignored until its scope ends.
28
+ Note: 'common' statement is extended: dimensions are moved to variable definitions
29
+ Note: f2py directive: <commentchar>f2py<line> is read as <line>
30
+ Note: pythonmodule is introduced to represent Python module
31
+
32
+ Usage:
33
+ `postlist=crackfortran(files)`
34
+ `postlist` contains declaration information read from the list of files `files`.
35
+ `crack2fortran(postlist)` returns a fortran code to be saved to pyf-file
36
+
37
+ `postlist` has the following structure:
38
+ *** it is a list of dictionaries containing `blocks':
39
+ B = {'block','body','vars','parent_block'[,'name','prefix','args','result',
40
+ 'implicit','externals','interfaced','common','sortvars',
41
+ 'commonvars','note']}
42
+ B['block'] = 'interface' | 'function' | 'subroutine' | 'module' |
43
+ 'program' | 'block data' | 'type' | 'pythonmodule' |
44
+ 'abstract interface'
45
+ B['body'] --- list containing `subblocks' with the same structure as `blocks'
46
+ B['parent_block'] --- dictionary of a parent block:
47
+ C['body'][<index>]['parent_block'] is C
48
+ B['vars'] --- dictionary of variable definitions
49
+ B['sortvars'] --- dictionary of variable definitions sorted by dependence (independent first)
50
+ B['name'] --- name of the block (not if B['block']=='interface')
51
+ B['prefix'] --- prefix string (only if B['block']=='function')
52
+ B['args'] --- list of argument names if B['block']== 'function' | 'subroutine'
53
+ B['result'] --- name of the return value (only if B['block']=='function')
54
+ B['implicit'] --- dictionary {'a':<variable definition>,'b':...} | None
55
+ B['externals'] --- list of variables being external
56
+ B['interfaced'] --- list of variables being external and defined
57
+ B['common'] --- dictionary of common blocks (list of objects)
58
+ B['commonvars'] --- list of variables used in common blocks (dimensions are moved to variable definitions)
59
+ B['from'] --- string showing the 'parents' of the current block
60
+ B['use'] --- dictionary of modules used in current block:
61
+ {<modulename>:{['only':<0|1>],['map':{<local_name1>:<use_name1>,...}]}}
62
+ B['note'] --- list of LaTeX comments on the block
63
+ B['f2pyenhancements'] --- optional dictionary
64
+ {'threadsafe':'','fortranname':<name>,
65
+ 'callstatement':<C-expr>|<multi-line block>,
66
+ 'callprotoargument':<C-expr-list>,
67
+ 'usercode':<multi-line block>|<list of multi-line blocks>,
68
+ 'pymethoddef:<multi-line block>'
69
+ }
70
+ B['entry'] --- dictionary {entryname:argslist,..}
71
+ B['varnames'] --- list of variable names given in the order of reading the
72
+ Fortran code, useful for derived types.
73
+ B['saved_interface'] --- a string of scanned routine signature, defines explicit interface
74
+ *** Variable definition is a dictionary
75
+ D = B['vars'][<variable name>] =
76
+ {'typespec'[,'attrspec','kindselector','charselector','=','typename']}
77
+ D['typespec'] = 'byte' | 'character' | 'complex' | 'double complex' |
78
+ 'double precision' | 'integer' | 'logical' | 'real' | 'type'
79
+ D['attrspec'] --- list of attributes (e.g. 'dimension(<arrayspec>)',
80
+ 'external','intent(in|out|inout|hide|c|callback|cache|aligned4|aligned8|aligned16)',
81
+ 'optional','required', etc)
82
+ K = D['kindselector'] = {['*','kind']} (only if D['typespec'] =
83
+ 'complex' | 'integer' | 'logical' | 'real' )
84
+ C = D['charselector'] = {['*','len','kind','f2py_len']}
85
+ (only if D['typespec']=='character')
86
+ D['='] --- initialization expression string
87
+ D['typename'] --- name of the type if D['typespec']=='type'
88
+ D['dimension'] --- list of dimension bounds
89
+ D['intent'] --- list of intent specifications
90
+ D['depend'] --- list of variable names on which current variable depends on
91
+ D['check'] --- list of C-expressions; if C-expr returns zero, exception is raised
92
+ D['note'] --- list of LaTeX comments on the variable
93
+ *** Meaning of kind/char selectors (few examples):
94
+ D['typespec>']*K['*']
95
+ D['typespec'](kind=K['kind'])
96
+ character*C['*']
97
+ character(len=C['len'],kind=C['kind'], f2py_len=C['f2py_len'])
98
+ (see also fortran type declaration statement formats below)
99
+
100
+ Fortran 90 type declaration statement format (F77 is subset of F90)
101
+ ====================================================================
102
+ (Main source: IBM XL Fortran 5.1 Language Reference Manual)
103
+ type declaration = <typespec> [[<attrspec>]::] <entitydecl>
104
+ <typespec> = byte |
105
+ character[<charselector>] |
106
+ complex[<kindselector>] |
107
+ double complex |
108
+ double precision |
109
+ integer[<kindselector>] |
110
+ logical[<kindselector>] |
111
+ real[<kindselector>] |
112
+ type(<typename>)
113
+ <charselector> = * <charlen> |
114
+ ([len=]<len>[,[kind=]<kind>]) |
115
+ (kind=<kind>[,len=<len>])
116
+ <kindselector> = * <intlen> |
117
+ ([kind=]<kind>)
118
+ <attrspec> = comma separated list of attributes.
119
+ Only the following attributes are used in
120
+ building up the interface:
121
+ external
122
+ (parameter --- affects '=' key)
123
+ optional
124
+ intent
125
+ Other attributes are ignored.
126
+ <intentspec> = in | out | inout
127
+ <arrayspec> = comma separated list of dimension bounds.
128
+ <entitydecl> = <name> [[*<charlen>][(<arrayspec>)] | [(<arrayspec>)]*<charlen>]
129
+ [/<init_expr>/ | =<init_expr>] [,<entitydecl>]
130
+
131
+ In addition, the following attributes are used: check,depend,note
132
+
133
+ TODO:
134
+ * Apply 'parameter' attribute (e.g. 'integer parameter :: i=2' 'real x(i)'
135
+ -> 'real x(2)')
136
+ The above may be solved by creating appropriate preprocessor program, for example.
137
+
138
+ """
139
+ import codecs
140
+ import copy
141
+ import fileinput
142
+ import os
143
+ import platform
144
+ import re
145
+ import string
146
+ import sys
147
+ from pathlib import Path
148
+
149
+ try:
150
+ import charset_normalizer
151
+ except ImportError:
152
+ charset_normalizer = None
153
+
154
+ from . import __version__, symbolic
155
+
156
+ # The environment provided by auxfuncs.py is needed for some calls to eval.
157
+ # As the needed functions cannot be determined by static inspection of the
158
+ # code, it is safest to use import * pending a major refactoring of f2py.
159
+ from .auxfuncs import *
160
+
161
+ f2py_version = __version__.version
162
+
163
+ # Global flags:
164
+ strictf77 = 1 # Ignore `!' comments unless line[0]=='!'
165
+ sourcecodeform = 'fix' # 'fix','free'
166
+ quiet = 0 # Be verbose if 0 (Obsolete: not used any more)
167
+ verbose = 1 # Be quiet if 0, extra verbose if > 1.
168
+ tabchar = 4 * ' '
169
+ pyffilename = ''
170
+ f77modulename = ''
171
+ skipemptyends = 0 # for old F77 programs without 'program' statement
172
+ ignorecontains = 1
173
+ dolowercase = 1
174
+ debug = []
175
+
176
+ # Global variables
177
+ beginpattern = ''
178
+ currentfilename = ''
179
+ expectbegin = 1
180
+ f90modulevars = {}
181
+ filepositiontext = ''
182
+ gotnextfile = 1
183
+ groupcache = None
184
+ groupcounter = 0
185
+ grouplist = {groupcounter: []}
186
+ groupname = ''
187
+ include_paths = []
188
+ neededmodule = -1
189
+ onlyfuncs = []
190
+ previous_context = None
191
+ skipblocksuntil = -1
192
+ skipfuncs = []
193
+ skipfunctions = []
194
+ usermodules = []
195
+
196
+
197
+ def reset_global_f2py_vars():
198
+ global groupcounter, grouplist, neededmodule, expectbegin
199
+ global skipblocksuntil, usermodules, f90modulevars, gotnextfile
200
+ global filepositiontext, currentfilename, skipfunctions, skipfuncs
201
+ global onlyfuncs, include_paths, previous_context
202
+ global strictf77, sourcecodeform, quiet, verbose, tabchar, pyffilename
203
+ global f77modulename, skipemptyends, ignorecontains, dolowercase, debug
204
+
205
+ # flags
206
+ strictf77 = 1
207
+ sourcecodeform = 'fix'
208
+ quiet = 0
209
+ verbose = 1
210
+ tabchar = 4 * ' '
211
+ pyffilename = ''
212
+ f77modulename = ''
213
+ skipemptyends = 0
214
+ ignorecontains = 1
215
+ dolowercase = 1
216
+ debug = []
217
+ # variables
218
+ groupcounter = 0
219
+ grouplist = {groupcounter: []}
220
+ neededmodule = -1
221
+ expectbegin = 1
222
+ skipblocksuntil = -1
223
+ usermodules = []
224
+ f90modulevars = {}
225
+ gotnextfile = 1
226
+ filepositiontext = ''
227
+ currentfilename = ''
228
+ skipfunctions = []
229
+ skipfuncs = []
230
+ onlyfuncs = []
231
+ include_paths = []
232
+ previous_context = None
233
+
234
+
235
+ def outmess(line, flag=1):
236
+ global filepositiontext
237
+
238
+ if not verbose:
239
+ return
240
+ if not quiet:
241
+ if flag:
242
+ sys.stdout.write(filepositiontext)
243
+ sys.stdout.write(line)
244
+
245
+
246
+ re._MAXCACHE = 50
247
+ defaultimplicitrules = {}
248
+ for c in "abcdefghopqrstuvwxyz$_":
249
+ defaultimplicitrules[c] = {'typespec': 'real'}
250
+ for c in "ijklmn":
251
+ defaultimplicitrules[c] = {'typespec': 'integer'}
252
+ badnames = {}
253
+ invbadnames = {}
254
+ for n in ['int', 'double', 'float', 'char', 'short', 'long', 'void', 'case', 'while',
255
+ 'return', 'signed', 'unsigned', 'if', 'for', 'typedef', 'sizeof', 'union',
256
+ 'struct', 'static', 'register', 'new', 'break', 'do', 'goto', 'switch',
257
+ 'continue', 'else', 'inline', 'extern', 'delete', 'const', 'auto',
258
+ 'len', 'rank', 'shape', 'index', 'slen', 'size', '_i',
259
+ 'max', 'min',
260
+ 'flen', 'fshape',
261
+ 'string', 'complex_double', 'float_double', 'stdin', 'stderr', 'stdout',
262
+ 'type', 'default']:
263
+ badnames[n] = n + '_bn'
264
+ invbadnames[n + '_bn'] = n
265
+
266
+
267
+ def rmbadname1(name):
268
+ if name in badnames:
269
+ errmess(f'rmbadname1: Replacing "{name}" with "{badnames[name]}".\n')
270
+ return badnames[name]
271
+ return name
272
+
273
+
274
+ def rmbadname(names):
275
+ return [rmbadname1(_m) for _m in names]
276
+
277
+
278
+ def undo_rmbadname1(name):
279
+ if name in invbadnames:
280
+ errmess(f'undo_rmbadname1: Replacing "{name}" with "{invbadnames[name]}".\n')
281
+ return invbadnames[name]
282
+ return name
283
+
284
+
285
+ def undo_rmbadname(names):
286
+ return [undo_rmbadname1(_m) for _m in names]
287
+
288
+
289
+ _has_f_header = re.compile(r'-\*-\s*fortran\s*-\*-', re.I).search
290
+ _has_f90_header = re.compile(r'-\*-\s*f90\s*-\*-', re.I).search
291
+ _has_fix_header = re.compile(r'-\*-\s*fix\s*-\*-', re.I).search
292
+ _free_f90_start = re.compile(r'[^c*]\s*[^\s\d\t]', re.I).match
293
+
294
+ # Extensions
295
+ COMMON_FREE_EXTENSIONS = ['.f90', '.f95', '.f03', '.f08']
296
+ COMMON_FIXED_EXTENSIONS = ['.for', '.ftn', '.f77', '.f']
297
+
298
+
299
+ def openhook(filename, mode):
300
+ """Ensures that filename is opened with correct encoding parameter.
301
+
302
+ This function uses charset_normalizer package, when available, for
303
+ determining the encoding of the file to be opened. When charset_normalizer
304
+ is not available, the function detects only UTF encodings, otherwise, ASCII
305
+ encoding is used as fallback.
306
+ """
307
+ # Reads in the entire file. Robust detection of encoding.
308
+ # Correctly handles comments or late stage unicode characters
309
+ # gh-22871
310
+ if charset_normalizer is not None:
311
+ encoding = charset_normalizer.from_path(filename).best().encoding
312
+ else:
313
+ # hint: install charset_normalizer for correct encoding handling
314
+ # No need to read the whole file for trying with startswith
315
+ nbytes = min(32, os.path.getsize(filename))
316
+ with open(filename, 'rb') as fhandle:
317
+ raw = fhandle.read(nbytes)
318
+ if raw.startswith(codecs.BOM_UTF8):
319
+ encoding = 'UTF-8-SIG'
320
+ elif raw.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)):
321
+ encoding = 'UTF-32'
322
+ elif raw.startswith((codecs.BOM_LE, codecs.BOM_BE)):
323
+ encoding = 'UTF-16'
324
+ else:
325
+ # Fallback, without charset_normalizer
326
+ encoding = 'ascii'
327
+ return open(filename, mode, encoding=encoding)
328
+
329
+
330
+ def is_free_format(fname):
331
+ """Check if file is in free format Fortran."""
332
+ # f90 allows both fixed and free format, assuming fixed unless
333
+ # signs of free format are detected.
334
+ result = False
335
+ if Path(fname).suffix.lower() in COMMON_FREE_EXTENSIONS:
336
+ result = True
337
+ with openhook(fname, 'r') as fhandle:
338
+ line = fhandle.readline()
339
+ n = 15 # the number of non-comment lines to scan for hints
340
+ if _has_f_header(line):
341
+ n = 0
342
+ elif _has_f90_header(line):
343
+ n = 0
344
+ result = True
345
+ while n > 0 and line:
346
+ if line[0] != '!' and line.strip():
347
+ n -= 1
348
+ if (line[0] != '\t' and _free_f90_start(line[:5])) or line[-2:-1] == '&':
349
+ result = True
350
+ break
351
+ line = fhandle.readline()
352
+ return result
353
+
354
+
355
+ # Read fortran (77,90) code
356
+ def readfortrancode(ffile, dowithline=show, istop=1):
357
+ """
358
+ Read fortran codes from files and
359
+ 1) Get rid of comments, line continuations, and empty lines; lower cases.
360
+ 2) Call dowithline(line) on every line.
361
+ 3) Recursively call itself when statement \"include '<filename>'\" is met.
362
+ """
363
+ global gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77
364
+ global beginpattern, quiet, verbose, dolowercase, include_paths
365
+
366
+ if not istop:
367
+ saveglobals = gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\
368
+ beginpattern, quiet, verbose, dolowercase
369
+ if ffile == []:
370
+ return
371
+ localdolowercase = dolowercase
372
+ # cont: set to True when the content of the last line read
373
+ # indicates statement continuation
374
+ cont = False
375
+ finalline = ''
376
+ ll = ''
377
+ includeline = re.compile(
378
+ r'\s*include\s*(\'|")(?P<name>[^\'"]*)(\'|")', re.I)
379
+ cont1 = re.compile(r'(?P<line>.*)&\s*\Z')
380
+ cont2 = re.compile(r'(\s*&|)(?P<line>.*)')
381
+ mline_mark = re.compile(r".*?'''")
382
+ if istop:
383
+ dowithline('', -1)
384
+ ll, l1 = '', ''
385
+ spacedigits = [' '] + [str(_m) for _m in range(10)]
386
+ filepositiontext = ''
387
+ fin = fileinput.FileInput(ffile, openhook=openhook)
388
+ while True:
389
+ try:
390
+ l = fin.readline()
391
+ except UnicodeDecodeError as msg:
392
+ raise Exception(
393
+ f'readfortrancode: reading {fin.filename()}#{fin.lineno()}'
394
+ f' failed with\n{msg}.\nIt is likely that installing charset_normalizer'
395
+ ' package will help f2py determine the input file encoding'
396
+ ' correctly.')
397
+ if not l:
398
+ break
399
+ if fin.isfirstline():
400
+ filepositiontext = ''
401
+ currentfilename = fin.filename()
402
+ gotnextfile = 1
403
+ l1 = l
404
+ strictf77 = 0
405
+ sourcecodeform = 'fix'
406
+ ext = os.path.splitext(currentfilename)[1]
407
+ if Path(currentfilename).suffix.lower() in COMMON_FIXED_EXTENSIONS and \
408
+ not (_has_f90_header(l) or _has_fix_header(l)):
409
+ strictf77 = 1
410
+ elif is_free_format(currentfilename) and not _has_fix_header(l):
411
+ sourcecodeform = 'free'
412
+ if strictf77:
413
+ beginpattern = beginpattern77
414
+ else:
415
+ beginpattern = beginpattern90
416
+ outmess('\tReading file %s (format:%s%s)\n'
417
+ % (repr(currentfilename), sourcecodeform,
418
+ (strictf77 and ',strict') or ''))
419
+
420
+ l = l.expandtabs().replace('\xa0', ' ')
421
+ # Get rid of newline characters
422
+ while not l == '':
423
+ if l[-1] not in "\n\r\f":
424
+ break
425
+ l = l[:-1]
426
+ # Do not lower for directives, gh-2547, gh-27697, gh-26681
427
+ is_f2py_directive = False
428
+ # Unconditionally remove comments
429
+ (l, rl) = split_by_unquoted(l, '!')
430
+ l += ' '
431
+ if rl[:5].lower() == '!f2py': # f2py directive
432
+ l, _ = split_by_unquoted(l + 4 * ' ' + rl[5:], '!')
433
+ is_f2py_directive = True
434
+ if l.strip() == '': # Skip empty line
435
+ if sourcecodeform == 'free':
436
+ # In free form, a statement continues in the next line
437
+ # that is not a comment line [3.3.2.4^1], lines with
438
+ # blanks are comment lines [3.3.2.3^1]. Hence, the
439
+ # line continuation flag must retain its state.
440
+ pass
441
+ else:
442
+ # In fixed form, statement continuation is determined
443
+ # by a non-blank character at the 6-th position. Empty
444
+ # line indicates a start of a new statement
445
+ # [3.3.3.3^1]. Hence, the line continuation flag must
446
+ # be reset.
447
+ cont = False
448
+ continue
449
+ if sourcecodeform == 'fix':
450
+ if l[0] in ['*', 'c', '!', 'C', '#']:
451
+ if l[1:5].lower() == 'f2py': # f2py directive
452
+ l = ' ' + l[5:]
453
+ is_f2py_directive = True
454
+ else: # Skip comment line
455
+ cont = False
456
+ is_f2py_directive = False
457
+ continue
458
+ elif strictf77:
459
+ if len(l) > 72:
460
+ l = l[:72]
461
+ if l[0] not in spacedigits:
462
+ raise Exception('readfortrancode: Found non-(space,digit) char '
463
+ 'in the first column.\n\tAre you sure that '
464
+ 'this code is in fix form?\n\tline=%s' % repr(l))
465
+
466
+ if (not cont or strictf77) and (len(l) > 5 and not l[5] == ' '):
467
+ # Continuation of a previous line
468
+ ll = ll + l[6:]
469
+ finalline = ''
470
+ origfinalline = ''
471
+ else:
472
+ r = cont1.match(l)
473
+ if r:
474
+ l = r.group('line') # Continuation follows ..
475
+ if cont:
476
+ ll = ll + cont2.match(l).group('line')
477
+ finalline = ''
478
+ origfinalline = ''
479
+ else:
480
+ # clean up line beginning from possible digits.
481
+ l = ' ' + l[5:]
482
+ # f2py directives are already stripped by this point
483
+ if localdolowercase:
484
+ finalline = ll.lower()
485
+ else:
486
+ finalline = ll
487
+ origfinalline = ll
488
+ ll = l
489
+
490
+ elif sourcecodeform == 'free':
491
+ if not cont and ext == '.pyf' and mline_mark.match(l):
492
+ l = l + '\n'
493
+ while True:
494
+ lc = fin.readline()
495
+ if not lc:
496
+ errmess(
497
+ 'Unexpected end of file when reading multiline\n')
498
+ break
499
+ l = l + lc
500
+ if mline_mark.match(lc):
501
+ break
502
+ l = l.rstrip()
503
+ r = cont1.match(l)
504
+ if r:
505
+ l = r.group('line') # Continuation follows ..
506
+ if cont:
507
+ ll = ll + cont2.match(l).group('line')
508
+ finalline = ''
509
+ origfinalline = ''
510
+ else:
511
+ if localdolowercase:
512
+ # only skip lowering for C style constructs
513
+ # gh-2547, gh-27697, gh-26681, gh-28014
514
+ finalline = ll.lower() if not (is_f2py_directive and iscstyledirective(ll)) else ll
515
+ else:
516
+ finalline = ll
517
+ origfinalline = ll
518
+ ll = l
519
+ cont = (r is not None)
520
+ else:
521
+ raise ValueError(
522
+ f"Flag sourcecodeform must be either 'fix' or 'free': {repr(sourcecodeform)}")
523
+ filepositiontext = 'Line #%d in %s:"%s"\n\t' % (
524
+ fin.filelineno() - 1, currentfilename, l1)
525
+ m = includeline.match(origfinalline)
526
+ if m:
527
+ fn = m.group('name')
528
+ if os.path.isfile(fn):
529
+ readfortrancode(fn, dowithline=dowithline, istop=0)
530
+ else:
531
+ include_dirs = [
532
+ os.path.dirname(currentfilename)] + include_paths
533
+ foundfile = 0
534
+ for inc_dir in include_dirs:
535
+ fn1 = os.path.join(inc_dir, fn)
536
+ if os.path.isfile(fn1):
537
+ foundfile = 1
538
+ readfortrancode(fn1, dowithline=dowithline, istop=0)
539
+ break
540
+ if not foundfile:
541
+ outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n' % (
542
+ repr(fn), os.pathsep.join(include_dirs)))
543
+ else:
544
+ dowithline(finalline)
545
+ l1 = ll
546
+ # Last line should never have an f2py directive anyway
547
+ if localdolowercase:
548
+ finalline = ll.lower()
549
+ else:
550
+ finalline = ll
551
+ origfinalline = ll
552
+ filepositiontext = 'Line #%d in %s:"%s"\n\t' % (
553
+ fin.filelineno() - 1, currentfilename, l1)
554
+ m = includeline.match(origfinalline)
555
+ if m:
556
+ fn = m.group('name')
557
+ if os.path.isfile(fn):
558
+ readfortrancode(fn, dowithline=dowithline, istop=0)
559
+ else:
560
+ include_dirs = [os.path.dirname(currentfilename)] + include_paths
561
+ foundfile = 0
562
+ for inc_dir in include_dirs:
563
+ fn1 = os.path.join(inc_dir, fn)
564
+ if os.path.isfile(fn1):
565
+ foundfile = 1
566
+ readfortrancode(fn1, dowithline=dowithline, istop=0)
567
+ break
568
+ if not foundfile:
569
+ outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n' % (
570
+ repr(fn), os.pathsep.join(include_dirs)))
571
+ else:
572
+ dowithline(finalline)
573
+ filepositiontext = ''
574
+ fin.close()
575
+ if istop:
576
+ dowithline('', 1)
577
+ else:
578
+ gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\
579
+ beginpattern, quiet, verbose, dolowercase = saveglobals
580
+
581
+
582
+ # Crack line
583
+ beforethisafter = r'\s*(?P<before>%s(?=\s*(\b(%s)\b)))'\
584
+ r'\s*(?P<this>(\b(%s)\b))'\
585
+ r'\s*(?P<after>%s)\s*\Z'
586
+ ##
587
+ fortrantypes = r'character|logical|integer|real|complex|double\s*(precision\s*(complex|)|complex)|type(?=\s*\([\w\s,=(*)]*\))|byte'
588
+ typespattern = re.compile(
589
+ beforethisafter % ('', fortrantypes, fortrantypes, '.*'), re.I), 'type'
590
+ typespattern4implicit = re.compile(beforethisafter % (
591
+ '', fortrantypes + '|static|automatic|undefined', fortrantypes + '|static|automatic|undefined', '.*'), re.I)
592
+ #
593
+ functionpattern = re.compile(beforethisafter % (
594
+ r'([a-z]+[\w\s(=*+-/)]*?|)', 'function', 'function', '.*'), re.I), 'begin'
595
+ subroutinepattern = re.compile(beforethisafter % (
596
+ r'[a-z\s]*?', 'subroutine', 'subroutine', '.*'), re.I), 'begin'
597
+ # modulepattern=re.compile(beforethisafter%('[a-z\s]*?','module','module','.*'),re.I),'begin'
598
+ #
599
+ groupbegins77 = r'program|block\s*data'
600
+ beginpattern77 = re.compile(
601
+ beforethisafter % ('', groupbegins77, groupbegins77, '.*'), re.I), 'begin'
602
+ groupbegins90 = groupbegins77 + \
603
+ r'|module(?!\s*procedure)|python\s*module|(abstract|)\s*interface|'\
604
+ r'type(?!\s*\()'
605
+ beginpattern90 = re.compile(
606
+ beforethisafter % ('', groupbegins90, groupbegins90, '.*'), re.I), 'begin'
607
+ groupends = (r'end|endprogram|endblockdata|endmodule|endpythonmodule|'
608
+ r'endinterface|endsubroutine|endfunction')
609
+ endpattern = re.compile(
610
+ beforethisafter % ('', groupends, groupends, '.*'), re.I), 'end'
611
+ # block, the Fortran 2008 construct needs special handling in the rest of the file
612
+ endifs = r'end\s*(if|do|where|select|while|forall|associate|'\
613
+ r'critical|enum|team)'
614
+ endifpattern = re.compile(
615
+ beforethisafter % (r'[\w]*?', endifs, endifs, '.*'), re.I), 'endif'
616
+ #
617
+ moduleprocedures = r'module\s*procedure'
618
+ moduleprocedurepattern = re.compile(
619
+ beforethisafter % ('', moduleprocedures, moduleprocedures, '.*'), re.I), \
620
+ 'moduleprocedure'
621
+ implicitpattern = re.compile(
622
+ beforethisafter % ('', 'implicit', 'implicit', '.*'), re.I), 'implicit'
623
+ dimensionpattern = re.compile(beforethisafter % (
624
+ '', 'dimension|virtual', 'dimension|virtual', '.*'), re.I), 'dimension'
625
+ externalpattern = re.compile(
626
+ beforethisafter % ('', 'external', 'external', '.*'), re.I), 'external'
627
+ optionalpattern = re.compile(
628
+ beforethisafter % ('', 'optional', 'optional', '.*'), re.I), 'optional'
629
+ requiredpattern = re.compile(
630
+ beforethisafter % ('', 'required', 'required', '.*'), re.I), 'required'
631
+ publicpattern = re.compile(
632
+ beforethisafter % ('', 'public', 'public', '.*'), re.I), 'public'
633
+ privatepattern = re.compile(
634
+ beforethisafter % ('', 'private', 'private', '.*'), re.I), 'private'
635
+ intrinsicpattern = re.compile(
636
+ beforethisafter % ('', 'intrinsic', 'intrinsic', '.*'), re.I), 'intrinsic'
637
+ intentpattern = re.compile(beforethisafter % (
638
+ '', 'intent|depend|note|check', 'intent|depend|note|check', r'\s*\(.*?\).*'), re.I), 'intent'
639
+ parameterpattern = re.compile(
640
+ beforethisafter % ('', 'parameter', 'parameter', r'\s*\(.*'), re.I), 'parameter'
641
+ datapattern = re.compile(
642
+ beforethisafter % ('', 'data', 'data', '.*'), re.I), 'data'
643
+ callpattern = re.compile(
644
+ beforethisafter % ('', 'call', 'call', '.*'), re.I), 'call'
645
+ entrypattern = re.compile(
646
+ beforethisafter % ('', 'entry', 'entry', '.*'), re.I), 'entry'
647
+ callfunpattern = re.compile(
648
+ beforethisafter % ('', 'callfun', 'callfun', '.*'), re.I), 'callfun'
649
+ commonpattern = re.compile(
650
+ beforethisafter % ('', 'common', 'common', '.*'), re.I), 'common'
651
+ usepattern = re.compile(
652
+ beforethisafter % ('', 'use', 'use', '.*'), re.I), 'use'
653
+ containspattern = re.compile(
654
+ beforethisafter % ('', 'contains', 'contains', ''), re.I), 'contains'
655
+ formatpattern = re.compile(
656
+ beforethisafter % ('', 'format', 'format', '.*'), re.I), 'format'
657
+ # Non-fortran and f2py-specific statements
658
+ f2pyenhancementspattern = re.compile(beforethisafter % ('', 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef',
659
+ 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', '.*'), re.I | re.S), 'f2pyenhancements'
660
+ multilinepattern = re.compile(
661
+ r"\s*(?P<before>''')(?P<this>.*?)(?P<after>''')\s*\Z", re.S), 'multiline'
662
+ ##
663
+
664
+ def split_by_unquoted(line, characters):
665
+ """
666
+ Splits the line into (line[:i], line[i:]),
667
+ where i is the index of first occurrence of one of the characters
668
+ not within quotes, or len(line) if no such index exists
669
+ """
670
+ assert not (set('"\'') & set(characters)), "cannot split by unquoted quotes"
671
+ r = re.compile(
672
+ r"\A(?P<before>({single_quoted}|{double_quoted}|{not_quoted})*)"
673
+ r"(?P<after>{char}.*)\Z".format(
674
+ not_quoted=f"[^\"'{re.escape(characters)}]",
675
+ char=f"[{re.escape(characters)}]",
676
+ single_quoted=r"('([^'\\]|(\\.))*')",
677
+ double_quoted=r'("([^"\\]|(\\.))*")'))
678
+ m = r.match(line)
679
+ if m:
680
+ d = m.groupdict()
681
+ return (d["before"], d["after"])
682
+ return (line, "")
683
+
684
+ def _simplifyargs(argsline):
685
+ a = []
686
+ for n in markoutercomma(argsline).split('@,@'):
687
+ for r in '(),':
688
+ n = n.replace(r, '_')
689
+ a.append(n)
690
+ return ','.join(a)
691
+
692
+
693
+ crackline_re_1 = re.compile(r'\s*(?P<result>\b[a-z]+\w*\b)\s*=.*', re.I)
694
+ crackline_bind_1 = re.compile(r'\s*(?P<bind>\b[a-z]+\w*\b)\s*=.*', re.I)
695
+ crackline_bindlang = re.compile(r'\s*bind\(\s*(?P<lang>[^,]+)\s*,\s*name\s*=\s*"(?P<lang_name>[^"]+)"\s*\)', re.I)
696
+
697
+ def crackline(line, reset=0):
698
+ """
699
+ reset=-1 --- initialize
700
+ reset=0 --- crack the line
701
+ reset=1 --- final check if mismatch of blocks occurred
702
+
703
+ Cracked data is saved in grouplist[0].
704
+ """
705
+ global beginpattern, groupcounter, groupname, groupcache, grouplist
706
+ global filepositiontext, currentfilename, neededmodule, expectbegin
707
+ global skipblocksuntil, skipemptyends, previous_context, gotnextfile
708
+
709
+ _, has_semicolon = split_by_unquoted(line, ";")
710
+ if has_semicolon and not (f2pyenhancementspattern[0].match(line) or
711
+ multilinepattern[0].match(line)):
712
+ # XXX: non-zero reset values need testing
713
+ assert reset == 0, repr(reset)
714
+ # split line on unquoted semicolons
715
+ line, semicolon_line = split_by_unquoted(line, ";")
716
+ while semicolon_line:
717
+ crackline(line, reset)
718
+ line, semicolon_line = split_by_unquoted(semicolon_line[1:], ";")
719
+ crackline(line, reset)
720
+ return
721
+ if reset < 0:
722
+ groupcounter = 0
723
+ groupname = {groupcounter: ''}
724
+ groupcache = {groupcounter: {}}
725
+ grouplist = {groupcounter: []}
726
+ groupcache[groupcounter]['body'] = []
727
+ groupcache[groupcounter]['vars'] = {}
728
+ groupcache[groupcounter]['block'] = ''
729
+ groupcache[groupcounter]['name'] = ''
730
+ neededmodule = -1
731
+ skipblocksuntil = -1
732
+ return
733
+ if reset > 0:
734
+ fl = 0
735
+ if f77modulename and neededmodule == groupcounter:
736
+ fl = 2
737
+ while groupcounter > fl:
738
+ outmess('crackline: groupcounter=%s groupname=%s\n' %
739
+ (repr(groupcounter), repr(groupname)))
740
+ outmess(
741
+ 'crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.\n')
742
+ grouplist[groupcounter - 1].append(groupcache[groupcounter])
743
+ grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter]
744
+ del grouplist[groupcounter]
745
+ groupcounter = groupcounter - 1
746
+ if f77modulename and neededmodule == groupcounter:
747
+ grouplist[groupcounter - 1].append(groupcache[groupcounter])
748
+ grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter]
749
+ del grouplist[groupcounter]
750
+ groupcounter = groupcounter - 1 # end interface
751
+ grouplist[groupcounter - 1].append(groupcache[groupcounter])
752
+ grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter]
753
+ del grouplist[groupcounter]
754
+ groupcounter = groupcounter - 1 # end module
755
+ neededmodule = -1
756
+ return
757
+ if line == '':
758
+ return
759
+ flag = 0
760
+ for pat in [dimensionpattern, externalpattern, intentpattern, optionalpattern,
761
+ requiredpattern,
762
+ parameterpattern, datapattern, publicpattern, privatepattern,
763
+ intrinsicpattern,
764
+ endifpattern, endpattern,
765
+ formatpattern,
766
+ beginpattern, functionpattern, subroutinepattern,
767
+ implicitpattern, typespattern, commonpattern,
768
+ callpattern, usepattern, containspattern,
769
+ entrypattern,
770
+ f2pyenhancementspattern,
771
+ multilinepattern,
772
+ moduleprocedurepattern
773
+ ]:
774
+ m = pat[0].match(line)
775
+ if m:
776
+ break
777
+ flag = flag + 1
778
+ if not m:
779
+ re_1 = crackline_re_1
780
+ if 0 <= skipblocksuntil <= groupcounter:
781
+ return
782
+ if 'externals' in groupcache[groupcounter]:
783
+ for name in groupcache[groupcounter]['externals']:
784
+ if name in invbadnames:
785
+ name = invbadnames[name]
786
+ if 'interfaced' in groupcache[groupcounter] and name in groupcache[groupcounter]['interfaced']:
787
+ continue
788
+ m1 = re.match(
789
+ r'(?P<before>[^"]*)\b%s\b\s*@\(@(?P<args>[^@]*)@\)@.*\Z' % name, markouterparen(line), re.I)
790
+ if m1:
791
+ m2 = re_1.match(m1.group('before'))
792
+ a = _simplifyargs(m1.group('args'))
793
+ if m2:
794
+ line = f"callfun {name}({a}) result ({m2.group('result')})"
795
+ else:
796
+ line = f'callfun {name}({a})'
797
+ m = callfunpattern[0].match(line)
798
+ if not m:
799
+ outmess(
800
+ f'crackline: could not resolve function call for line={repr(line)}.\n')
801
+ return
802
+ analyzeline(m, 'callfun', line)
803
+ return
804
+ if verbose > 1 or (verbose == 1 and currentfilename.lower().endswith('.pyf')):
805
+ previous_context = None
806
+ outmess('crackline:%d: No pattern for line\n' % (groupcounter))
807
+ return
808
+ elif pat[1] == 'end':
809
+ if 0 <= skipblocksuntil < groupcounter:
810
+ groupcounter = groupcounter - 1
811
+ if skipblocksuntil <= groupcounter:
812
+ return
813
+ if groupcounter <= 0:
814
+ raise Exception('crackline: groupcounter(=%s) is nonpositive. '
815
+ 'Check the blocks.'
816
+ % (groupcounter))
817
+ m1 = beginpattern[0].match(line)
818
+ if (m1) and (not m1.group('this') == groupname[groupcounter]):
819
+ raise Exception('crackline: End group %s does not match with '
820
+ 'previous Begin group %s\n\t%s' %
821
+ (repr(m1.group('this')), repr(groupname[groupcounter]),
822
+ filepositiontext)
823
+ )
824
+ if skipblocksuntil == groupcounter:
825
+ skipblocksuntil = -1
826
+ grouplist[groupcounter - 1].append(groupcache[groupcounter])
827
+ grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter]
828
+ del grouplist[groupcounter]
829
+ groupcounter = groupcounter - 1
830
+ if not skipemptyends:
831
+ expectbegin = 1
832
+ elif pat[1] == 'begin':
833
+ if 0 <= skipblocksuntil <= groupcounter:
834
+ groupcounter = groupcounter + 1
835
+ return
836
+ gotnextfile = 0
837
+ analyzeline(m, pat[1], line)
838
+ expectbegin = 0
839
+ elif pat[1] == 'endif':
840
+ pass
841
+ elif pat[1] == 'moduleprocedure':
842
+ analyzeline(m, pat[1], line)
843
+ elif pat[1] == 'contains':
844
+ if ignorecontains:
845
+ return
846
+ if 0 <= skipblocksuntil <= groupcounter:
847
+ return
848
+ skipblocksuntil = groupcounter
849
+ else:
850
+ if 0 <= skipblocksuntil <= groupcounter:
851
+ return
852
+ analyzeline(m, pat[1], line)
853
+
854
+
855
+ def markouterparen(line):
856
+ l = ''
857
+ f = 0
858
+ for c in line:
859
+ if c == '(':
860
+ f = f + 1
861
+ if f == 1:
862
+ l = l + '@(@'
863
+ continue
864
+ elif c == ')':
865
+ f = f - 1
866
+ if f == 0:
867
+ l = l + '@)@'
868
+ continue
869
+ l = l + c
870
+ return l
871
+
872
+
873
+ def markoutercomma(line, comma=','):
874
+ l = ''
875
+ f = 0
876
+ before, after = split_by_unquoted(line, comma + '()')
877
+ l += before
878
+ while after:
879
+ if (after[0] == comma) and (f == 0):
880
+ l += '@' + comma + '@'
881
+ else:
882
+ l += after[0]
883
+ if after[0] == '(':
884
+ f += 1
885
+ elif after[0] == ')':
886
+ f -= 1
887
+ before, after = split_by_unquoted(after[1:], comma + '()')
888
+ l += before
889
+ assert not f, repr((f, line, l))
890
+ return l
891
+
892
+ def unmarkouterparen(line):
893
+ r = line.replace('@(@', '(').replace('@)@', ')')
894
+ return r
895
+
896
+
897
+ def appenddecl(decl, decl2, force=1):
898
+ if not decl:
899
+ decl = {}
900
+ if not decl2:
901
+ return decl
902
+ if decl is decl2:
903
+ return decl
904
+ for k in list(decl2.keys()):
905
+ if k == 'typespec':
906
+ if force or k not in decl:
907
+ decl[k] = decl2[k]
908
+ elif k == 'attrspec':
909
+ for l in decl2[k]:
910
+ decl = setattrspec(decl, l, force)
911
+ elif k == 'kindselector':
912
+ decl = setkindselector(decl, decl2[k], force)
913
+ elif k == 'charselector':
914
+ decl = setcharselector(decl, decl2[k], force)
915
+ elif k in ['=', 'typename']:
916
+ if force or k not in decl:
917
+ decl[k] = decl2[k]
918
+ elif k == 'note':
919
+ pass
920
+ elif k in ['intent', 'check', 'dimension', 'optional',
921
+ 'required', 'depend']:
922
+ errmess(f'appenddecl: "{k}" not implemented.\n')
923
+ else:
924
+ raise Exception('appenddecl: Unknown variable definition key: ' +
925
+ str(k))
926
+ return decl
927
+
928
+
929
+ selectpattern = re.compile(
930
+ r'\s*(?P<this>(@\(@.*?@\)@|\*[\d*]+|\*\s*@\(@.*?@\)@|))(?P<after>.*)\Z', re.I)
931
+ typedefpattern = re.compile(
932
+ r'(?:,(?P<attributes>[\w(),]+))?(::)?(?P<name>\b[a-z$_][\w$]*\b)'
933
+ r'(?:\((?P<params>[\w,]*)\))?\Z', re.I)
934
+ nameargspattern = re.compile(
935
+ r'\s*(?P<name>\b[\w$]+\b)\s*(@\(@\s*(?P<args>[\w\s,]*)\s*@\)@|)\s*((result(\s*@\(@\s*(?P<result>\b[\w$]+\b)\s*@\)@|))|(bind\s*@\(@\s*(?P<bind>(?:(?!@\)@).)*)\s*@\)@))*\s*\Z', re.I)
936
+ operatorpattern = re.compile(
937
+ r'\s*(?P<scheme>(operator|assignment))'
938
+ r'@\(@\s*(?P<name>[^)]+)\s*@\)@\s*\Z', re.I)
939
+ callnameargspattern = re.compile(
940
+ r'\s*(?P<name>\b[\w$]+\b)\s*@\(@\s*(?P<args>.*)\s*@\)@\s*\Z', re.I)
941
+ real16pattern = re.compile(
942
+ r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+))[dD]((?:[-+]?\d+)?)')
943
+ real8pattern = re.compile(
944
+ r'([-+]?((?:\d+(?:\.\d*)?|\d*\.\d+))[eE]((?:[-+]?\d+)?)|(\d+\.\d*))')
945
+
946
+ _intentcallbackpattern = re.compile(r'intent\s*\(.*?\bcallback\b', re.I)
947
+
948
+
949
+ def _is_intent_callback(vdecl):
950
+ for a in vdecl.get('attrspec', []):
951
+ if _intentcallbackpattern.match(a):
952
+ return 1
953
+ return 0
954
+
955
+
956
+ def _resolvetypedefpattern(line):
957
+ line = ''.join(line.split()) # removes whitespace
958
+ m1 = typedefpattern.match(line)
959
+ print(line, m1)
960
+ if m1:
961
+ attrs = m1.group('attributes')
962
+ attrs = [a.lower() for a in attrs.split(',')] if attrs else []
963
+ return m1.group('name'), attrs, m1.group('params')
964
+ return None, [], None
965
+
966
+ def parse_name_for_bind(line):
967
+ pattern = re.compile(r'bind\(\s*(?P<lang>[^,]+)(?:\s*,\s*name\s*=\s*["\'](?P<name>[^"\']+)["\']\s*)?\)', re.I)
968
+ match = pattern.search(line)
969
+ bind_statement = None
970
+ if match:
971
+ bind_statement = match.group(0)
972
+ # Remove the 'bind' construct from the line.
973
+ line = line[:match.start()] + line[match.end():]
974
+ return line, bind_statement
975
+
976
+ def _resolvenameargspattern(line):
977
+ line, bind_cname = parse_name_for_bind(line)
978
+ line = markouterparen(line)
979
+ m1 = nameargspattern.match(line)
980
+ if m1:
981
+ return m1.group('name'), m1.group('args'), m1.group('result'), bind_cname
982
+ m1 = operatorpattern.match(line)
983
+ if m1:
984
+ name = m1.group('scheme') + '(' + m1.group('name') + ')'
985
+ return name, [], None, None
986
+ m1 = callnameargspattern.match(line)
987
+ if m1:
988
+ return m1.group('name'), m1.group('args'), None, None
989
+ return None, [], None, None
990
+
991
+
992
+ def analyzeline(m, case, line):
993
+ """
994
+ Reads each line in the input file in sequence and updates global vars.
995
+
996
+ Effectively reads and collects information from the input file to the
997
+ global variable groupcache, a dictionary containing info about each part
998
+ of the fortran module.
999
+
1000
+ At the end of analyzeline, information is filtered into the correct dict
1001
+ keys, but parameter values and dimensions are not yet interpreted.
1002
+ """
1003
+ global groupcounter, groupname, groupcache, grouplist, filepositiontext
1004
+ global currentfilename, f77modulename, neededinterface, neededmodule
1005
+ global expectbegin, gotnextfile, previous_context
1006
+
1007
+ block = m.group('this')
1008
+ if case != 'multiline':
1009
+ previous_context = None
1010
+ if expectbegin and case not in ['begin', 'call', 'callfun', 'type'] \
1011
+ and not skipemptyends and groupcounter < 1:
1012
+ newname = os.path.basename(currentfilename).split('.')[0]
1013
+ outmess(
1014
+ f'analyzeline: no group yet. Creating program group with name "{newname}".\n')
1015
+ gotnextfile = 0
1016
+ groupcounter = groupcounter + 1
1017
+ groupname[groupcounter] = 'program'
1018
+ groupcache[groupcounter] = {}
1019
+ grouplist[groupcounter] = []
1020
+ groupcache[groupcounter]['body'] = []
1021
+ groupcache[groupcounter]['vars'] = {}
1022
+ groupcache[groupcounter]['block'] = 'program'
1023
+ groupcache[groupcounter]['name'] = newname
1024
+ groupcache[groupcounter]['from'] = 'fromsky'
1025
+ expectbegin = 0
1026
+ if case in ['begin', 'call', 'callfun']:
1027
+ # Crack line => block,name,args,result
1028
+ block = block.lower()
1029
+ if re.match(r'block\s*data', block, re.I):
1030
+ block = 'block data'
1031
+ elif re.match(r'python\s*module', block, re.I):
1032
+ block = 'python module'
1033
+ elif re.match(r'abstract\s*interface', block, re.I):
1034
+ block = 'abstract interface'
1035
+ if block == 'type':
1036
+ name, attrs, _ = _resolvetypedefpattern(m.group('after'))
1037
+ groupcache[groupcounter]['vars'][name] = {'attrspec': attrs}
1038
+ args = []
1039
+ result = None
1040
+ else:
1041
+ name, args, result, bindcline = _resolvenameargspattern(m.group('after'))
1042
+ if name is None:
1043
+ if block == 'block data':
1044
+ name = '_BLOCK_DATA_'
1045
+ else:
1046
+ name = ''
1047
+ if block not in ['interface', 'block data', 'abstract interface']:
1048
+ outmess('analyzeline: No name/args pattern found for line.\n')
1049
+
1050
+ previous_context = (block, name, groupcounter)
1051
+ if args:
1052
+ args = rmbadname([x.strip()
1053
+ for x in markoutercomma(args).split('@,@')])
1054
+ else:
1055
+ args = []
1056
+ if '' in args:
1057
+ while '' in args:
1058
+ args.remove('')
1059
+ outmess(
1060
+ 'analyzeline: argument list is malformed (missing argument).\n')
1061
+
1062
+ # end of crack line => block,name,args,result
1063
+ needmodule = 0
1064
+ needinterface = 0
1065
+
1066
+ if case in ['call', 'callfun']:
1067
+ needinterface = 1
1068
+ if 'args' not in groupcache[groupcounter]:
1069
+ return
1070
+ if name not in groupcache[groupcounter]['args']:
1071
+ return
1072
+ for it in grouplist[groupcounter]:
1073
+ if it['name'] == name:
1074
+ return
1075
+ if name in groupcache[groupcounter]['interfaced']:
1076
+ return
1077
+ block = {'call': 'subroutine', 'callfun': 'function'}[case]
1078
+ if f77modulename and neededmodule == -1 and groupcounter <= 1:
1079
+ neededmodule = groupcounter + 2
1080
+ needmodule = 1
1081
+ if block not in ['interface', 'abstract interface']:
1082
+ needinterface = 1
1083
+ # Create new block(s)
1084
+ groupcounter = groupcounter + 1
1085
+ groupcache[groupcounter] = {}
1086
+ grouplist[groupcounter] = []
1087
+ if needmodule:
1088
+ if verbose > 1:
1089
+ outmess('analyzeline: Creating module block %s\n' %
1090
+ repr(f77modulename), 0)
1091
+ groupname[groupcounter] = 'module'
1092
+ groupcache[groupcounter]['block'] = 'python module'
1093
+ groupcache[groupcounter]['name'] = f77modulename
1094
+ groupcache[groupcounter]['from'] = ''
1095
+ groupcache[groupcounter]['body'] = []
1096
+ groupcache[groupcounter]['externals'] = []
1097
+ groupcache[groupcounter]['interfaced'] = []
1098
+ groupcache[groupcounter]['vars'] = {}
1099
+ groupcounter = groupcounter + 1
1100
+ groupcache[groupcounter] = {}
1101
+ grouplist[groupcounter] = []
1102
+ if needinterface:
1103
+ if verbose > 1:
1104
+ outmess('analyzeline: Creating additional interface block (groupcounter=%s).\n' % (
1105
+ groupcounter), 0)
1106
+ groupname[groupcounter] = 'interface'
1107
+ groupcache[groupcounter]['block'] = 'interface'
1108
+ groupcache[groupcounter]['name'] = 'unknown_interface'
1109
+ groupcache[groupcounter]['from'] = '%s:%s' % (
1110
+ groupcache[groupcounter - 1]['from'], groupcache[groupcounter - 1]['name'])
1111
+ groupcache[groupcounter]['body'] = []
1112
+ groupcache[groupcounter]['externals'] = []
1113
+ groupcache[groupcounter]['interfaced'] = []
1114
+ groupcache[groupcounter]['vars'] = {}
1115
+ groupcounter = groupcounter + 1
1116
+ groupcache[groupcounter] = {}
1117
+ grouplist[groupcounter] = []
1118
+ groupname[groupcounter] = block
1119
+ groupcache[groupcounter]['block'] = block
1120
+ if not name:
1121
+ name = 'unknown_' + block.replace(' ', '_')
1122
+ groupcache[groupcounter]['prefix'] = m.group('before')
1123
+ groupcache[groupcounter]['name'] = rmbadname1(name)
1124
+ groupcache[groupcounter]['result'] = result
1125
+ if groupcounter == 1:
1126
+ groupcache[groupcounter]['from'] = currentfilename
1127
+ elif f77modulename and groupcounter == 3:
1128
+ groupcache[groupcounter]['from'] = '%s:%s' % (
1129
+ groupcache[groupcounter - 1]['from'], currentfilename)
1130
+ else:
1131
+ groupcache[groupcounter]['from'] = '%s:%s' % (
1132
+ groupcache[groupcounter - 1]['from'], groupcache[groupcounter - 1]['name'])
1133
+ for k in list(groupcache[groupcounter].keys()):
1134
+ if not groupcache[groupcounter][k]:
1135
+ del groupcache[groupcounter][k]
1136
+
1137
+ groupcache[groupcounter]['args'] = args
1138
+ groupcache[groupcounter]['body'] = []
1139
+ groupcache[groupcounter]['externals'] = []
1140
+ groupcache[groupcounter]['interfaced'] = []
1141
+ groupcache[groupcounter]['vars'] = {}
1142
+ groupcache[groupcounter]['entry'] = {}
1143
+ # end of creation
1144
+ if block == 'type':
1145
+ groupcache[groupcounter]['varnames'] = []
1146
+
1147
+ if case in ['call', 'callfun']: # set parents variables
1148
+ if name not in groupcache[groupcounter - 2]['externals']:
1149
+ groupcache[groupcounter - 2]['externals'].append(name)
1150
+ groupcache[groupcounter]['vars'] = copy.deepcopy(
1151
+ groupcache[groupcounter - 2]['vars'])
1152
+ try:
1153
+ del groupcache[groupcounter]['vars'][name][
1154
+ groupcache[groupcounter]['vars'][name]['attrspec'].index('external')]
1155
+ except Exception:
1156
+ pass
1157
+ if block in ['function', 'subroutine']: # set global attributes
1158
+ # name is fortran name
1159
+ if bindcline:
1160
+ bindcdat = re.search(crackline_bindlang, bindcline)
1161
+ if bindcdat:
1162
+ groupcache[groupcounter]['bindlang'] = {name: {}}
1163
+ groupcache[groupcounter]['bindlang'][name]["lang"] = bindcdat.group('lang')
1164
+ if bindcdat.group('lang_name'):
1165
+ groupcache[groupcounter]['bindlang'][name]["name"] = bindcdat.group('lang_name')
1166
+ try:
1167
+ groupcache[groupcounter]['vars'][name] = appenddecl(
1168
+ groupcache[groupcounter]['vars'][name], groupcache[groupcounter - 2]['vars'][''])
1169
+ except Exception:
1170
+ pass
1171
+ if case == 'callfun': # return type
1172
+ if result and result in groupcache[groupcounter]['vars']:
1173
+ if not name == result:
1174
+ groupcache[groupcounter]['vars'][name] = appenddecl(
1175
+ groupcache[groupcounter]['vars'][name], groupcache[groupcounter]['vars'][result])
1176
+ # if groupcounter>1: # name is interfaced
1177
+ try:
1178
+ groupcache[groupcounter - 2]['interfaced'].append(name)
1179
+ except Exception:
1180
+ pass
1181
+ if block == 'function':
1182
+ t = typespattern[0].match(m.group('before') + ' ' + name)
1183
+ if t:
1184
+ typespec, selector, attr, edecl = cracktypespec0(
1185
+ t.group('this'), t.group('after'))
1186
+ updatevars(typespec, selector, attr, edecl)
1187
+
1188
+ if case in ['call', 'callfun']:
1189
+ grouplist[groupcounter - 1].append(groupcache[groupcounter])
1190
+ grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter]
1191
+ del grouplist[groupcounter]
1192
+ groupcounter = groupcounter - 1 # end routine
1193
+ grouplist[groupcounter - 1].append(groupcache[groupcounter])
1194
+ grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter]
1195
+ del grouplist[groupcounter]
1196
+ groupcounter = groupcounter - 1 # end interface
1197
+
1198
+ elif case == 'entry':
1199
+ name, args, result, _ = _resolvenameargspattern(m.group('after'))
1200
+ if name is not None:
1201
+ if args:
1202
+ args = rmbadname([x.strip()
1203
+ for x in markoutercomma(args).split('@,@')])
1204
+ else:
1205
+ args = []
1206
+ assert result is None, repr(result)
1207
+ groupcache[groupcounter]['entry'][name] = args
1208
+ previous_context = ('entry', name, groupcounter)
1209
+ elif case == 'type':
1210
+ typespec, selector, attr, edecl = cracktypespec0(
1211
+ block, m.group('after'))
1212
+ last_name = updatevars(typespec, selector, attr, edecl)
1213
+ if last_name is not None:
1214
+ previous_context = ('variable', last_name, groupcounter)
1215
+ elif case in ['dimension', 'intent', 'optional', 'required', 'external', 'public', 'private', 'intrinsic']:
1216
+ edecl = groupcache[groupcounter]['vars']
1217
+ ll = m.group('after').strip()
1218
+ i = ll.find('::')
1219
+ if i < 0 and case == 'intent':
1220
+ i = markouterparen(ll).find('@)@') - 2
1221
+ ll = ll[:i + 1] + '::' + ll[i + 1:]
1222
+ i = ll.find('::')
1223
+ if ll[i:] == '::' and 'args' in groupcache[groupcounter]:
1224
+ outmess('All arguments will have attribute %s%s\n' %
1225
+ (m.group('this'), ll[:i]))
1226
+ ll = ll + ','.join(groupcache[groupcounter]['args'])
1227
+ if i < 0:
1228
+ i = 0
1229
+ pl = ''
1230
+ else:
1231
+ pl = ll[:i].strip()
1232
+ ll = ll[i + 2:]
1233
+ ch = markoutercomma(pl).split('@,@')
1234
+ if len(ch) > 1:
1235
+ pl = ch[0]
1236
+ outmess('analyzeline: cannot handle multiple attributes without type specification. Ignoring %r.\n' % (
1237
+ ','.join(ch[1:])))
1238
+ last_name = None
1239
+
1240
+ for e in [x.strip() for x in markoutercomma(ll).split('@,@')]:
1241
+ m1 = namepattern.match(e)
1242
+ if not m1:
1243
+ if case in ['public', 'private']:
1244
+ k = ''
1245
+ else:
1246
+ print(m.groupdict())
1247
+ outmess('analyzeline: no name pattern found in %s statement for %s. Skipping.\n' % (
1248
+ case, repr(e)))
1249
+ continue
1250
+ else:
1251
+ k = rmbadname1(m1.group('name'))
1252
+ if case in ['public', 'private'] and k in {'operator', 'assignment'}:
1253
+ k += m1.group('after')
1254
+ if k not in edecl:
1255
+ edecl[k] = {}
1256
+ if case == 'dimension':
1257
+ ap = case + m1.group('after')
1258
+ if case == 'intent':
1259
+ ap = m.group('this') + pl
1260
+ if _intentcallbackpattern.match(ap):
1261
+ if k not in groupcache[groupcounter]['args']:
1262
+ if groupcounter > 1:
1263
+ if '__user__' not in groupcache[groupcounter - 2]['name']:
1264
+ outmess(
1265
+ 'analyzeline: missing __user__ module (could be nothing)\n')
1266
+ # fixes ticket 1693
1267
+ if k != groupcache[groupcounter]['name']:
1268
+ outmess('analyzeline: appending intent(callback) %s'
1269
+ ' to %s arguments\n' % (k, groupcache[groupcounter]['name']))
1270
+ groupcache[groupcounter]['args'].append(k)
1271
+ else:
1272
+ errmess(
1273
+ f'analyzeline: intent(callback) {k} is ignored\n')
1274
+ else:
1275
+ errmess('analyzeline: intent(callback) %s is already'
1276
+ ' in argument list\n' % (k))
1277
+ if case in ['optional', 'required', 'public', 'external', 'private', 'intrinsic']:
1278
+ ap = case
1279
+ if 'attrspec' in edecl[k]:
1280
+ edecl[k]['attrspec'].append(ap)
1281
+ else:
1282
+ edecl[k]['attrspec'] = [ap]
1283
+ if case == 'external':
1284
+ if groupcache[groupcounter]['block'] == 'program':
1285
+ outmess('analyzeline: ignoring program arguments\n')
1286
+ continue
1287
+ if k not in groupcache[groupcounter]['args']:
1288
+ continue
1289
+ if 'externals' not in groupcache[groupcounter]:
1290
+ groupcache[groupcounter]['externals'] = []
1291
+ groupcache[groupcounter]['externals'].append(k)
1292
+ last_name = k
1293
+ groupcache[groupcounter]['vars'] = edecl
1294
+ if last_name is not None:
1295
+ previous_context = ('variable', last_name, groupcounter)
1296
+ elif case == 'moduleprocedure':
1297
+ groupcache[groupcounter]['implementedby'] = \
1298
+ [x.strip() for x in m.group('after').split(',')]
1299
+ elif case == 'parameter':
1300
+ edecl = groupcache[groupcounter]['vars']
1301
+ ll = m.group('after').strip()[1:-1]
1302
+ last_name = None
1303
+ for e in markoutercomma(ll).split('@,@'):
1304
+ try:
1305
+ k, initexpr = [x.strip() for x in e.split('=')]
1306
+ except Exception:
1307
+ outmess(
1308
+ f'analyzeline: could not extract name,expr in parameter statement "{e}" of "{ll}\"\n')
1309
+ continue
1310
+ params = get_parameters(edecl)
1311
+ k = rmbadname1(k)
1312
+ if k not in edecl:
1313
+ edecl[k] = {}
1314
+ if '=' in edecl[k] and (not edecl[k]['='] == initexpr):
1315
+ outmess('analyzeline: Overwriting the value of parameter "%s" ("%s") with "%s".\n' % (
1316
+ k, edecl[k]['='], initexpr))
1317
+ t = determineexprtype(initexpr, params)
1318
+ if t:
1319
+ if t.get('typespec') == 'real':
1320
+ tt = list(initexpr)
1321
+ for m in real16pattern.finditer(initexpr):
1322
+ tt[m.start():m.end()] = list(
1323
+ initexpr[m.start():m.end()].lower().replace('d', 'e'))
1324
+ initexpr = ''.join(tt)
1325
+ elif t.get('typespec') == 'complex':
1326
+ initexpr = initexpr[1:].lower().replace('d', 'e').\
1327
+ replace(',', '+1j*(')
1328
+ try:
1329
+ v = eval(initexpr, {}, params)
1330
+ except (SyntaxError, NameError, TypeError) as msg:
1331
+ errmess('analyzeline: Failed to evaluate %r. Ignoring: %s\n'
1332
+ % (initexpr, msg))
1333
+ continue
1334
+ edecl[k]['='] = repr(v)
1335
+ if 'attrspec' in edecl[k]:
1336
+ edecl[k]['attrspec'].append('parameter')
1337
+ else:
1338
+ edecl[k]['attrspec'] = ['parameter']
1339
+ last_name = k
1340
+ groupcache[groupcounter]['vars'] = edecl
1341
+ if last_name is not None:
1342
+ previous_context = ('variable', last_name, groupcounter)
1343
+ elif case == 'implicit':
1344
+ if m.group('after').strip().lower() == 'none':
1345
+ groupcache[groupcounter]['implicit'] = None
1346
+ elif m.group('after'):
1347
+ impl = groupcache[groupcounter].get('implicit', {})
1348
+ if impl is None:
1349
+ outmess(
1350
+ 'analyzeline: Overwriting earlier "implicit none" statement.\n')
1351
+ impl = {}
1352
+ for e in markoutercomma(m.group('after')).split('@,@'):
1353
+ decl = {}
1354
+ m1 = re.match(
1355
+ r'\s*(?P<this>.*?)\s*(\(\s*(?P<after>[a-z-, ]+)\s*\)\s*|)\Z', e, re.I)
1356
+ if not m1:
1357
+ outmess(
1358
+ f'analyzeline: could not extract info of implicit statement part "{e}\"\n')
1359
+ continue
1360
+ m2 = typespattern4implicit.match(m1.group('this'))
1361
+ if not m2:
1362
+ outmess(
1363
+ f'analyzeline: could not extract types pattern of implicit statement part "{e}\"\n')
1364
+ continue
1365
+ typespec, selector, attr, edecl = cracktypespec0(
1366
+ m2.group('this'), m2.group('after'))
1367
+ kindselect, charselect, typename = cracktypespec(
1368
+ typespec, selector)
1369
+ decl['typespec'] = typespec
1370
+ decl['kindselector'] = kindselect
1371
+ decl['charselector'] = charselect
1372
+ decl['typename'] = typename
1373
+ for k in list(decl.keys()):
1374
+ if not decl[k]:
1375
+ del decl[k]
1376
+ for r in markoutercomma(m1.group('after')).split('@,@'):
1377
+ if '-' in r:
1378
+ try:
1379
+ begc, endc = [x.strip() for x in r.split('-')]
1380
+ except Exception:
1381
+ outmess(
1382
+ f'analyzeline: expected "<char>-<char>" instead of "{r}" in range list of implicit statement\n')
1383
+ continue
1384
+ else:
1385
+ begc = endc = r.strip()
1386
+ if not len(begc) == len(endc) == 1:
1387
+ outmess(
1388
+ f'analyzeline: expected "<char>-<char>" instead of "{r}" in range list of implicit statement (2)\n')
1389
+ continue
1390
+ for o in range(ord(begc), ord(endc) + 1):
1391
+ impl[chr(o)] = decl
1392
+ groupcache[groupcounter]['implicit'] = impl
1393
+ elif case == 'data':
1394
+ ll = []
1395
+ dl = ''
1396
+ il = ''
1397
+ f = 0
1398
+ fc = 1
1399
+ inp = 0
1400
+ for c in m.group('after'):
1401
+ if not inp:
1402
+ if c == "'":
1403
+ fc = not fc
1404
+ if c == '/' and fc:
1405
+ f = f + 1
1406
+ continue
1407
+ if c == '(':
1408
+ inp = inp + 1
1409
+ elif c == ')':
1410
+ inp = inp - 1
1411
+ if f == 0:
1412
+ dl = dl + c
1413
+ elif f == 1:
1414
+ il = il + c
1415
+ elif f == 2:
1416
+ dl = dl.strip()
1417
+ if dl.startswith(','):
1418
+ dl = dl[1:].strip()
1419
+ ll.append([dl, il])
1420
+ dl = c
1421
+ il = ''
1422
+ f = 0
1423
+ if f == 2:
1424
+ dl = dl.strip()
1425
+ if dl.startswith(','):
1426
+ dl = dl[1:].strip()
1427
+ ll.append([dl, il])
1428
+ vars = groupcache[groupcounter].get('vars', {})
1429
+ last_name = None
1430
+ for l in ll:
1431
+ l[0], l[1] = l[0].strip().removeprefix(','), l[1].strip()
1432
+ if l[0].startswith('('):
1433
+ outmess(f'analyzeline: implied-DO list "{l[0]}" is not supported. Skipping.\n')
1434
+ continue
1435
+ for idx, v in enumerate(rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')])):
1436
+ if v.startswith('('):
1437
+ outmess(f'analyzeline: implied-DO list "{v}" is not supported. Skipping.\n')
1438
+ # XXX: subsequent init expressions may get wrong values.
1439
+ # Ignoring since data statements are irrelevant for
1440
+ # wrapping.
1441
+ continue
1442
+ if '!' in l[1]:
1443
+ # Fixes gh-24746 pyf generation
1444
+ # XXX: This essentially ignores the value for generating the pyf which is fine:
1445
+ # integer dimension(3) :: mytab
1446
+ # common /mycom/ mytab
1447
+ # Since in any case it is initialized in the Fortran code
1448
+ outmess(f'Comment line in declaration "{l[1]}" is not supported. Skipping.\n')
1449
+ continue
1450
+ vars.setdefault(v, {})
1451
+ vtype = vars[v].get('typespec')
1452
+ vdim = getdimension(vars[v])
1453
+ matches = re.findall(r"\(.*?\)", l[1]) if vtype == 'complex' else l[1].split(',')
1454
+ try:
1455
+ new_val = f"(/{', '.join(matches)}/)" if vdim else matches[idx]
1456
+ except IndexError:
1457
+ # gh-24746
1458
+ # Runs only if above code fails. Fixes the line
1459
+ # DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /4*0,0.0D0/
1460
+ # by expanding to ['0', '0', '0', '0', '0.0d0']
1461
+ if any("*" in m for m in matches):
1462
+ expanded_list = []
1463
+ for match in matches:
1464
+ if "*" in match:
1465
+ try:
1466
+ multiplier, value = match.split("*")
1467
+ expanded_list.extend([value.strip()] * int(multiplier))
1468
+ except ValueError: # if int(multiplier) fails
1469
+ expanded_list.append(match.strip())
1470
+ else:
1471
+ expanded_list.append(match.strip())
1472
+ matches = expanded_list
1473
+ new_val = f"(/{', '.join(matches)}/)" if vdim else matches[idx]
1474
+ current_val = vars[v].get('=')
1475
+ if current_val and (current_val != new_val):
1476
+ outmess(f'analyzeline: changing init expression of "{v}" ("{current_val}") to "{new_val}\"\n')
1477
+ vars[v]['='] = new_val
1478
+ last_name = v
1479
+ groupcache[groupcounter]['vars'] = vars
1480
+ if last_name:
1481
+ previous_context = ('variable', last_name, groupcounter)
1482
+ elif case == 'common':
1483
+ line = m.group('after').strip()
1484
+ if not line[0] == '/':
1485
+ line = '//' + line
1486
+
1487
+ cl = []
1488
+ [_, bn, ol] = re.split('/', line, maxsplit=2) # noqa: RUF039
1489
+ bn = bn.strip()
1490
+ if not bn:
1491
+ bn = '_BLNK_'
1492
+ cl.append([bn, ol])
1493
+ commonkey = {}
1494
+ if 'common' in groupcache[groupcounter]:
1495
+ commonkey = groupcache[groupcounter]['common']
1496
+ for c in cl:
1497
+ if c[0] not in commonkey:
1498
+ commonkey[c[0]] = []
1499
+ for i in [x.strip() for x in markoutercomma(c[1]).split('@,@')]:
1500
+ if i:
1501
+ commonkey[c[0]].append(i)
1502
+ groupcache[groupcounter]['common'] = commonkey
1503
+ previous_context = ('common', bn, groupcounter)
1504
+ elif case == 'use':
1505
+ m1 = re.match(
1506
+ r'\A\s*(?P<name>\b\w+\b)\s*((,(\s*\bonly\b\s*:|(?P<notonly>))\s*(?P<list>.*))|)\s*\Z', m.group('after'), re.I)
1507
+ if m1:
1508
+ mm = m1.groupdict()
1509
+ if 'use' not in groupcache[groupcounter]:
1510
+ groupcache[groupcounter]['use'] = {}
1511
+ name = m1.group('name')
1512
+ groupcache[groupcounter]['use'][name] = {}
1513
+ isonly = 0
1514
+ if 'list' in mm and mm['list'] is not None:
1515
+ if 'notonly' in mm and mm['notonly'] is None:
1516
+ isonly = 1
1517
+ groupcache[groupcounter]['use'][name]['only'] = isonly
1518
+ ll = [x.strip() for x in mm['list'].split(',')]
1519
+ rl = {}
1520
+ for l in ll:
1521
+ if '=' in l:
1522
+ m2 = re.match(
1523
+ r'\A\s*(?P<local>\b\w+\b)\s*=\s*>\s*(?P<use>\b\w+\b)\s*\Z', l, re.I)
1524
+ if m2:
1525
+ rl[m2.group('local').strip()] = m2.group(
1526
+ 'use').strip()
1527
+ else:
1528
+ outmess(
1529
+ f'analyzeline: Not local=>use pattern found in {repr(l)}\n')
1530
+ else:
1531
+ rl[l] = l
1532
+ groupcache[groupcounter]['use'][name]['map'] = rl
1533
+ else:
1534
+ print(m.groupdict())
1535
+ outmess('analyzeline: Could not crack the use statement.\n')
1536
+ elif case in ['f2pyenhancements']:
1537
+ if 'f2pyenhancements' not in groupcache[groupcounter]:
1538
+ groupcache[groupcounter]['f2pyenhancements'] = {}
1539
+ d = groupcache[groupcounter]['f2pyenhancements']
1540
+ if m.group('this') == 'usercode' and 'usercode' in d:
1541
+ if isinstance(d['usercode'], str):
1542
+ d['usercode'] = [d['usercode']]
1543
+ d['usercode'].append(m.group('after'))
1544
+ else:
1545
+ d[m.group('this')] = m.group('after')
1546
+ elif case == 'multiline':
1547
+ if previous_context is None:
1548
+ if verbose:
1549
+ outmess('analyzeline: No context for multiline block.\n')
1550
+ return
1551
+ gc = groupcounter
1552
+ appendmultiline(groupcache[gc],
1553
+ previous_context[:2],
1554
+ m.group('this'))
1555
+ elif verbose > 1:
1556
+ print(m.groupdict())
1557
+ outmess('analyzeline: No code implemented for line.\n')
1558
+
1559
+
1560
+ def appendmultiline(group, context_name, ml):
1561
+ if 'f2pymultilines' not in group:
1562
+ group['f2pymultilines'] = {}
1563
+ d = group['f2pymultilines']
1564
+ if context_name not in d:
1565
+ d[context_name] = []
1566
+ d[context_name].append(ml)
1567
+
1568
+
1569
+ def cracktypespec0(typespec, ll):
1570
+ selector = None
1571
+ attr = None
1572
+ if re.match(r'double\s*complex', typespec, re.I):
1573
+ typespec = 'double complex'
1574
+ elif re.match(r'double\s*precision', typespec, re.I):
1575
+ typespec = 'double precision'
1576
+ else:
1577
+ typespec = typespec.strip().lower()
1578
+ m1 = selectpattern.match(markouterparen(ll))
1579
+ if not m1:
1580
+ outmess(
1581
+ 'cracktypespec0: no kind/char_selector pattern found for line.\n')
1582
+ return
1583
+ d = m1.groupdict()
1584
+ for k in list(d.keys()):
1585
+ d[k] = unmarkouterparen(d[k])
1586
+ if typespec in ['complex', 'integer', 'logical', 'real', 'character', 'type']:
1587
+ selector = d['this']
1588
+ ll = d['after']
1589
+ i = ll.find('::')
1590
+ if i >= 0:
1591
+ attr = ll[:i].strip()
1592
+ ll = ll[i + 2:]
1593
+ return typespec, selector, attr, ll
1594
+
1595
+
1596
+ #####
1597
+ namepattern = re.compile(r'\s*(?P<name>\b\w+\b)\s*(?P<after>.*)\s*\Z', re.I)
1598
+ kindselector = re.compile(
1599
+ r'\s*(\(\s*(kind\s*=)?\s*(?P<kind>.*)\s*\)|\*\s*(?P<kind2>.*?))\s*\Z', re.I)
1600
+ charselector = re.compile(
1601
+ r'\s*(\((?P<lenkind>.*)\)|\*\s*(?P<charlen>.*))\s*\Z', re.I)
1602
+ lenkindpattern = re.compile(
1603
+ r'\s*(kind\s*=\s*(?P<kind>.*?)\s*(@,@\s*len\s*=\s*(?P<len>.*)|)'
1604
+ r'|(len\s*=\s*|)(?P<len2>.*?)\s*(@,@\s*(kind\s*=\s*|)(?P<kind2>.*)'
1605
+ r'|(f2py_len\s*=\s*(?P<f2py_len>.*))|))\s*\Z', re.I)
1606
+ lenarraypattern = re.compile(
1607
+ r'\s*(@\(@\s*(?!/)\s*(?P<array>.*?)\s*@\)@\s*\*\s*(?P<len>.*?)|(\*\s*(?P<len2>.*?)|)\s*(@\(@\s*(?!/)\s*(?P<array2>.*?)\s*@\)@|))\s*(=\s*(?P<init>.*?)|(@\(@|)/\s*(?P<init2>.*?)\s*/(@\)@|)|)\s*\Z', re.I)
1608
+
1609
+
1610
+ def removespaces(expr):
1611
+ expr = expr.strip()
1612
+ if len(expr) <= 1:
1613
+ return expr
1614
+ expr2 = expr[0]
1615
+ for i in range(1, len(expr) - 1):
1616
+ if (expr[i] == ' ' and
1617
+ ((expr[i + 1] in "()[]{}=+-/* ") or
1618
+ (expr[i - 1] in "()[]{}=+-/* "))):
1619
+ continue
1620
+ expr2 = expr2 + expr[i]
1621
+ expr2 = expr2 + expr[-1]
1622
+ return expr2
1623
+
1624
+
1625
+ def markinnerspaces(line):
1626
+ """
1627
+ The function replace all spaces in the input variable line which are
1628
+ surrounded with quotation marks, with the triplet "@_@".
1629
+
1630
+ For instance, for the input "a 'b c'" the function returns "a 'b@_@c'"
1631
+
1632
+ Parameters
1633
+ ----------
1634
+ line : str
1635
+
1636
+ Returns
1637
+ -------
1638
+ str
1639
+
1640
+ """
1641
+ fragment = ''
1642
+ inside = False
1643
+ current_quote = None
1644
+ escaped = ''
1645
+ for c in line:
1646
+ if escaped == '\\' and c in ['\\', '\'', '"']:
1647
+ fragment += c
1648
+ escaped = c
1649
+ continue
1650
+ if not inside and c in ['\'', '"']:
1651
+ current_quote = c
1652
+ if c == current_quote:
1653
+ inside = not inside
1654
+ elif c == ' ' and inside:
1655
+ fragment += '@_@'
1656
+ continue
1657
+ fragment += c
1658
+ escaped = c # reset to non-backslash
1659
+ return fragment
1660
+
1661
+
1662
+ def updatevars(typespec, selector, attrspec, entitydecl):
1663
+ """
1664
+ Returns last_name, the variable name without special chars, parenthesis
1665
+ or dimension specifiers.
1666
+
1667
+ Alters groupcache to add the name, typespec, attrspec (and possibly value)
1668
+ of current variable.
1669
+ """
1670
+ global groupcache, groupcounter
1671
+
1672
+ last_name = None
1673
+ kindselect, charselect, typename = cracktypespec(typespec, selector)
1674
+ # Clean up outer commas, whitespace and undesired chars from attrspec
1675
+ if attrspec:
1676
+ attrspec = [x.strip() for x in markoutercomma(attrspec).split('@,@')]
1677
+ l = []
1678
+ c = re.compile(r'(?P<start>[a-zA-Z]+)')
1679
+ for a in attrspec:
1680
+ if not a:
1681
+ continue
1682
+ m = c.match(a)
1683
+ if m:
1684
+ s = m.group('start').lower()
1685
+ a = s + a[len(s):]
1686
+ l.append(a)
1687
+ attrspec = l
1688
+ el = [x.strip() for x in markoutercomma(entitydecl).split('@,@')]
1689
+ el1 = []
1690
+ for e in el:
1691
+ for e1 in [x.strip() for x in markoutercomma(removespaces(markinnerspaces(e)), comma=' ').split('@ @')]:
1692
+ if e1:
1693
+ el1.append(e1.replace('@_@', ' '))
1694
+ for e in el1:
1695
+ m = namepattern.match(e)
1696
+ if not m:
1697
+ outmess(
1698
+ f'updatevars: no name pattern found for entity={repr(e)}. Skipping.\n')
1699
+ continue
1700
+ ename = rmbadname1(m.group('name'))
1701
+ edecl = {}
1702
+ if ename in groupcache[groupcounter]['vars']:
1703
+ edecl = groupcache[groupcounter]['vars'][ename].copy()
1704
+ not_has_typespec = 'typespec' not in edecl
1705
+ if not_has_typespec:
1706
+ edecl['typespec'] = typespec
1707
+ elif typespec and (not typespec == edecl['typespec']):
1708
+ outmess('updatevars: attempt to change the type of "%s" ("%s") to "%s". Ignoring.\n' % (
1709
+ ename, edecl['typespec'], typespec))
1710
+ if 'kindselector' not in edecl:
1711
+ edecl['kindselector'] = copy.copy(kindselect)
1712
+ elif kindselect:
1713
+ for k in list(kindselect.keys()):
1714
+ if k in edecl['kindselector'] and (not kindselect[k] == edecl['kindselector'][k]):
1715
+ outmess('updatevars: attempt to change the kindselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (
1716
+ k, ename, edecl['kindselector'][k], kindselect[k]))
1717
+ else:
1718
+ edecl['kindselector'][k] = copy.copy(kindselect[k])
1719
+ if 'charselector' not in edecl and charselect:
1720
+ if not_has_typespec:
1721
+ edecl['charselector'] = charselect
1722
+ else:
1723
+ errmess('updatevars:%s: attempt to change empty charselector to %r. Ignoring.\n'
1724
+ % (ename, charselect))
1725
+ elif charselect:
1726
+ for k in list(charselect.keys()):
1727
+ if k in edecl['charselector'] and (not charselect[k] == edecl['charselector'][k]):
1728
+ outmess('updatevars: attempt to change the charselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (
1729
+ k, ename, edecl['charselector'][k], charselect[k]))
1730
+ else:
1731
+ edecl['charselector'][k] = copy.copy(charselect[k])
1732
+ if 'typename' not in edecl:
1733
+ edecl['typename'] = typename
1734
+ elif typename and (not edecl['typename'] == typename):
1735
+ outmess('updatevars: attempt to change the typename of "%s" ("%s") to "%s". Ignoring.\n' % (
1736
+ ename, edecl['typename'], typename))
1737
+ if 'attrspec' not in edecl:
1738
+ edecl['attrspec'] = copy.copy(attrspec)
1739
+ elif attrspec:
1740
+ for a in attrspec:
1741
+ if a not in edecl['attrspec']:
1742
+ edecl['attrspec'].append(a)
1743
+ else:
1744
+ edecl['typespec'] = copy.copy(typespec)
1745
+ edecl['kindselector'] = copy.copy(kindselect)
1746
+ edecl['charselector'] = copy.copy(charselect)
1747
+ edecl['typename'] = typename
1748
+ edecl['attrspec'] = copy.copy(attrspec)
1749
+ if 'external' in (edecl.get('attrspec') or []) and e in groupcache[groupcounter]['args']:
1750
+ if 'externals' not in groupcache[groupcounter]:
1751
+ groupcache[groupcounter]['externals'] = []
1752
+ groupcache[groupcounter]['externals'].append(e)
1753
+ if m.group('after'):
1754
+ m1 = lenarraypattern.match(markouterparen(m.group('after')))
1755
+ if m1:
1756
+ d1 = m1.groupdict()
1757
+ for lk in ['len', 'array', 'init']:
1758
+ if d1[lk + '2'] is not None:
1759
+ d1[lk] = d1[lk + '2']
1760
+ del d1[lk + '2']
1761
+ for k in list(d1.keys()):
1762
+ if d1[k] is not None:
1763
+ d1[k] = unmarkouterparen(d1[k])
1764
+ else:
1765
+ del d1[k]
1766
+
1767
+ if 'len' in d1 and 'array' in d1:
1768
+ if d1['len'] == '':
1769
+ d1['len'] = d1['array']
1770
+ del d1['array']
1771
+ elif typespec == 'character':
1772
+ if ('charselector' not in edecl) or (not edecl['charselector']):
1773
+ edecl['charselector'] = {}
1774
+ if 'len' in edecl['charselector']:
1775
+ del edecl['charselector']['len']
1776
+ edecl['charselector']['*'] = d1['len']
1777
+ del d1['len']
1778
+ else:
1779
+ d1['array'] = d1['array'] + ',' + d1['len']
1780
+ del d1['len']
1781
+ errmess('updatevars: "%s %s" is mapped to "%s %s(%s)"\n' % (
1782
+ typespec, e, typespec, ename, d1['array']))
1783
+
1784
+ if 'len' in d1:
1785
+ if typespec in ['complex', 'integer', 'logical', 'real']:
1786
+ if ('kindselector' not in edecl) or (not edecl['kindselector']):
1787
+ edecl['kindselector'] = {}
1788
+ edecl['kindselector']['*'] = d1['len']
1789
+ del d1['len']
1790
+ elif typespec == 'character':
1791
+ if ('charselector' not in edecl) or (not edecl['charselector']):
1792
+ edecl['charselector'] = {}
1793
+ if 'len' in edecl['charselector']:
1794
+ del edecl['charselector']['len']
1795
+ edecl['charselector']['*'] = d1['len']
1796
+ del d1['len']
1797
+
1798
+ if 'init' in d1:
1799
+ if '=' in edecl and (not edecl['='] == d1['init']):
1800
+ outmess('updatevars: attempt to change the init expression of "%s" ("%s") to "%s". Ignoring.\n' % (
1801
+ ename, edecl['='], d1['init']))
1802
+ else:
1803
+ edecl['='] = d1['init']
1804
+
1805
+ if 'array' in d1:
1806
+ dm = f"dimension({d1['array']})"
1807
+ if 'attrspec' not in edecl or (not edecl['attrspec']):
1808
+ edecl['attrspec'] = [dm]
1809
+ else:
1810
+ edecl['attrspec'].append(dm)
1811
+ for dm1 in edecl['attrspec']:
1812
+ if dm1[:9] == 'dimension' and dm1 != dm:
1813
+ del edecl['attrspec'][-1]
1814
+ errmess('updatevars:%s: attempt to change %r to %r. Ignoring.\n'
1815
+ % (ename, dm1, dm))
1816
+ break
1817
+
1818
+ else:
1819
+ outmess('updatevars: could not crack entity declaration "%s". Ignoring.\n' % (
1820
+ ename + m.group('after')))
1821
+ for k in list(edecl.keys()):
1822
+ if not edecl[k]:
1823
+ del edecl[k]
1824
+ groupcache[groupcounter]['vars'][ename] = edecl
1825
+ if 'varnames' in groupcache[groupcounter]:
1826
+ groupcache[groupcounter]['varnames'].append(ename)
1827
+ last_name = ename
1828
+ return last_name
1829
+
1830
+
1831
+ def cracktypespec(typespec, selector):
1832
+ kindselect = None
1833
+ charselect = None
1834
+ typename = None
1835
+ if selector:
1836
+ if typespec in ['complex', 'integer', 'logical', 'real']:
1837
+ kindselect = kindselector.match(selector)
1838
+ if not kindselect:
1839
+ outmess(
1840
+ f'cracktypespec: no kindselector pattern found for {repr(selector)}\n')
1841
+ return
1842
+ kindselect = kindselect.groupdict()
1843
+ kindselect['*'] = kindselect['kind2']
1844
+ del kindselect['kind2']
1845
+ for k in list(kindselect.keys()):
1846
+ if not kindselect[k]:
1847
+ del kindselect[k]
1848
+ for k, i in list(kindselect.items()):
1849
+ kindselect[k] = rmbadname1(i)
1850
+ elif typespec == 'character':
1851
+ charselect = charselector.match(selector)
1852
+ if not charselect:
1853
+ outmess(
1854
+ f'cracktypespec: no charselector pattern found for {repr(selector)}\n')
1855
+ return
1856
+ charselect = charselect.groupdict()
1857
+ charselect['*'] = charselect['charlen']
1858
+ del charselect['charlen']
1859
+ if charselect['lenkind']:
1860
+ lenkind = lenkindpattern.match(
1861
+ markoutercomma(charselect['lenkind']))
1862
+ lenkind = lenkind.groupdict()
1863
+ for lk in ['len', 'kind']:
1864
+ if lenkind[lk + '2']:
1865
+ lenkind[lk] = lenkind[lk + '2']
1866
+ charselect[lk] = lenkind[lk]
1867
+ del lenkind[lk + '2']
1868
+ if lenkind['f2py_len'] is not None:
1869
+ # used to specify the length of assumed length strings
1870
+ charselect['f2py_len'] = lenkind['f2py_len']
1871
+ del charselect['lenkind']
1872
+ for k in list(charselect.keys()):
1873
+ if not charselect[k]:
1874
+ del charselect[k]
1875
+ for k, i in list(charselect.items()):
1876
+ charselect[k] = rmbadname1(i)
1877
+ elif typespec == 'type':
1878
+ typename = re.match(r'\s*\(\s*(?P<name>\w+)\s*\)', selector, re.I)
1879
+ if typename:
1880
+ typename = typename.group('name')
1881
+ else:
1882
+ outmess('cracktypespec: no typename found in %s\n' %
1883
+ (repr(typespec + selector)))
1884
+ else:
1885
+ outmess(f'cracktypespec: no selector used for {repr(selector)}\n')
1886
+ return kindselect, charselect, typename
1887
+ ######
1888
+
1889
+
1890
+ def setattrspec(decl, attr, force=0):
1891
+ if not decl:
1892
+ decl = {}
1893
+ if not attr:
1894
+ return decl
1895
+ if 'attrspec' not in decl:
1896
+ decl['attrspec'] = [attr]
1897
+ return decl
1898
+ if force:
1899
+ decl['attrspec'].append(attr)
1900
+ if attr in decl['attrspec']:
1901
+ return decl
1902
+ if attr == 'static' and 'automatic' not in decl['attrspec']:
1903
+ decl['attrspec'].append(attr)
1904
+ elif attr == 'automatic' and 'static' not in decl['attrspec']:
1905
+ decl['attrspec'].append(attr)
1906
+ elif attr == 'public':
1907
+ if 'private' not in decl['attrspec']:
1908
+ decl['attrspec'].append(attr)
1909
+ elif attr == 'private':
1910
+ if 'public' not in decl['attrspec']:
1911
+ decl['attrspec'].append(attr)
1912
+ else:
1913
+ decl['attrspec'].append(attr)
1914
+ return decl
1915
+
1916
+
1917
+ def setkindselector(decl, sel, force=0):
1918
+ if not decl:
1919
+ decl = {}
1920
+ if not sel:
1921
+ return decl
1922
+ if 'kindselector' not in decl:
1923
+ decl['kindselector'] = sel
1924
+ return decl
1925
+ for k in list(sel.keys()):
1926
+ if force or k not in decl['kindselector']:
1927
+ decl['kindselector'][k] = sel[k]
1928
+ return decl
1929
+
1930
+
1931
+ def setcharselector(decl, sel, force=0):
1932
+ if not decl:
1933
+ decl = {}
1934
+ if not sel:
1935
+ return decl
1936
+ if 'charselector' not in decl:
1937
+ decl['charselector'] = sel
1938
+ return decl
1939
+
1940
+ for k in list(sel.keys()):
1941
+ if force or k not in decl['charselector']:
1942
+ decl['charselector'][k] = sel[k]
1943
+ return decl
1944
+
1945
+
1946
+ def getblockname(block, unknown='unknown'):
1947
+ if 'name' in block:
1948
+ return block['name']
1949
+ return unknown
1950
+
1951
+ # post processing
1952
+
1953
+
1954
+ def setmesstext(block):
1955
+ global filepositiontext
1956
+
1957
+ try:
1958
+ filepositiontext = f"In: {block['from']}:{block['name']}\n"
1959
+ except Exception:
1960
+ pass
1961
+
1962
+
1963
+ def get_usedict(block):
1964
+ usedict = {}
1965
+ if 'parent_block' in block:
1966
+ usedict = get_usedict(block['parent_block'])
1967
+ if 'use' in block:
1968
+ usedict.update(block['use'])
1969
+ return usedict
1970
+
1971
+
1972
+ def get_useparameters(block, param_map=None):
1973
+ global f90modulevars
1974
+
1975
+ if param_map is None:
1976
+ param_map = {}
1977
+ usedict = get_usedict(block)
1978
+ if not usedict:
1979
+ return param_map
1980
+ for usename, mapping in list(usedict.items()):
1981
+ usename = usename.lower()
1982
+ if usename not in f90modulevars:
1983
+ outmess('get_useparameters: no module %s info used by %s\n' %
1984
+ (usename, block.get('name')))
1985
+ continue
1986
+ mvars = f90modulevars[usename]
1987
+ params = get_parameters(mvars)
1988
+ if not params:
1989
+ continue
1990
+ # XXX: apply mapping
1991
+ if mapping:
1992
+ errmess(f'get_useparameters: mapping for {mapping} not impl.\n')
1993
+ for k, v in list(params.items()):
1994
+ if k in param_map:
1995
+ outmess('get_useparameters: overriding parameter %s with'
1996
+ ' value from module %s\n' % (repr(k), repr(usename)))
1997
+ param_map[k] = v
1998
+
1999
+ return param_map
2000
+
2001
+
2002
+ def postcrack2(block, tab='', param_map=None):
2003
+ global f90modulevars
2004
+
2005
+ if not f90modulevars:
2006
+ return block
2007
+ if isinstance(block, list):
2008
+ ret = [postcrack2(g, tab=tab + '\t', param_map=param_map)
2009
+ for g in block]
2010
+ return ret
2011
+ setmesstext(block)
2012
+ outmess(f"{tab}Block: {block['name']}\n", 0)
2013
+
2014
+ if param_map is None:
2015
+ param_map = get_useparameters(block)
2016
+
2017
+ if param_map is not None and 'vars' in block:
2018
+ vars = block['vars']
2019
+ for n in list(vars.keys()):
2020
+ var = vars[n]
2021
+ if 'kindselector' in var:
2022
+ kind = var['kindselector']
2023
+ if 'kind' in kind:
2024
+ val = kind['kind']
2025
+ if val in param_map:
2026
+ kind['kind'] = param_map[val]
2027
+ new_body = [postcrack2(b, tab=tab + '\t', param_map=param_map)
2028
+ for b in block['body']]
2029
+ block['body'] = new_body
2030
+
2031
+ return block
2032
+
2033
+
2034
+ def postcrack(block, args=None, tab=''):
2035
+ """
2036
+ TODO:
2037
+ function return values
2038
+ determine expression types if in argument list
2039
+ """
2040
+ global usermodules, onlyfunctions
2041
+
2042
+ if isinstance(block, list):
2043
+ gret = []
2044
+ uret = []
2045
+ for g in block:
2046
+ setmesstext(g)
2047
+ g = postcrack(g, tab=tab + '\t')
2048
+ # sort user routines to appear first
2049
+ if 'name' in g and '__user__' in g['name']:
2050
+ uret.append(g)
2051
+ else:
2052
+ gret.append(g)
2053
+ return uret + gret
2054
+ setmesstext(block)
2055
+ if not isinstance(block, dict) and 'block' not in block:
2056
+ raise Exception('postcrack: Expected block dictionary instead of ' +
2057
+ str(block))
2058
+ if 'name' in block and not block['name'] == 'unknown_interface':
2059
+ outmess(f"{tab}Block: {block['name']}\n", 0)
2060
+ block = analyzeargs(block)
2061
+ block = analyzecommon(block)
2062
+ block['vars'] = analyzevars(block)
2063
+ block['sortvars'] = sortvarnames(block['vars'])
2064
+ if block.get('args'):
2065
+ args = block['args']
2066
+ block['body'] = analyzebody(block, args, tab=tab)
2067
+
2068
+ userisdefined = []
2069
+ if 'use' in block:
2070
+ useblock = block['use']
2071
+ for k in list(useblock.keys()):
2072
+ if '__user__' in k:
2073
+ userisdefined.append(k)
2074
+ else:
2075
+ useblock = {}
2076
+ name = ''
2077
+ if 'name' in block:
2078
+ name = block['name']
2079
+ # and not userisdefined: # Build a __user__ module
2080
+ if block.get('externals'):
2081
+ interfaced = []
2082
+ if 'interfaced' in block:
2083
+ interfaced = block['interfaced']
2084
+ mvars = copy.copy(block['vars'])
2085
+ if name:
2086
+ mname = name + '__user__routines'
2087
+ else:
2088
+ mname = 'unknown__user__routines'
2089
+ if mname in userisdefined:
2090
+ i = 1
2091
+ while f"{mname}_{i}" in userisdefined:
2092
+ i = i + 1
2093
+ mname = f"{mname}_{i}"
2094
+ interface = {'block': 'interface', 'body': [],
2095
+ 'vars': {}, 'name': name + '_user_interface'}
2096
+ for e in block['externals']:
2097
+ if e in interfaced:
2098
+ edef = []
2099
+ j = -1
2100
+ for b in block['body']:
2101
+ j = j + 1
2102
+ if b['block'] == 'interface':
2103
+ i = -1
2104
+ for bb in b['body']:
2105
+ i = i + 1
2106
+ if 'name' in bb and bb['name'] == e:
2107
+ edef = copy.copy(bb)
2108
+ del b['body'][i]
2109
+ break
2110
+ if edef:
2111
+ if not b['body']:
2112
+ del block['body'][j]
2113
+ del interfaced[interfaced.index(e)]
2114
+ break
2115
+ interface['body'].append(edef)
2116
+ elif e in mvars and not isexternal(mvars[e]):
2117
+ interface['vars'][e] = mvars[e]
2118
+ if interface['vars'] or interface['body']:
2119
+ block['interfaced'] = interfaced
2120
+ mblock = {'block': 'python module', 'body': [
2121
+ interface], 'vars': {}, 'name': mname, 'interfaced': block['externals']}
2122
+ useblock[mname] = {}
2123
+ usermodules.append(mblock)
2124
+ if useblock:
2125
+ block['use'] = useblock
2126
+ return block
2127
+
2128
+
2129
+ def sortvarnames(vars):
2130
+ indep = []
2131
+ dep = []
2132
+ for v in list(vars.keys()):
2133
+ if 'depend' in vars[v] and vars[v]['depend']:
2134
+ dep.append(v)
2135
+ else:
2136
+ indep.append(v)
2137
+ n = len(dep)
2138
+ i = 0
2139
+ while dep: # XXX: How to catch dependence cycles correctly?
2140
+ v = dep[0]
2141
+ fl = 0
2142
+ for w in dep[1:]:
2143
+ if w in vars[v]['depend']:
2144
+ fl = 1
2145
+ break
2146
+ if fl:
2147
+ dep = dep[1:] + [v]
2148
+ i = i + 1
2149
+ if i > n:
2150
+ errmess('sortvarnames: failed to compute dependencies because'
2151
+ ' of cyclic dependencies between '
2152
+ + ', '.join(dep) + '\n')
2153
+ indep = indep + dep
2154
+ break
2155
+ else:
2156
+ indep.append(v)
2157
+ dep = dep[1:]
2158
+ n = len(dep)
2159
+ i = 0
2160
+ return indep
2161
+
2162
+
2163
+ def analyzecommon(block):
2164
+ if not hascommon(block):
2165
+ return block
2166
+ commonvars = []
2167
+ for k in list(block['common'].keys()):
2168
+ comvars = []
2169
+ for e in block['common'][k]:
2170
+ m = re.match(
2171
+ r'\A\s*\b(?P<name>.*?)\b\s*(\((?P<dims>.*?)\)|)\s*\Z', e, re.I)
2172
+ if m:
2173
+ dims = []
2174
+ if m.group('dims'):
2175
+ dims = [x.strip()
2176
+ for x in markoutercomma(m.group('dims')).split('@,@')]
2177
+ n = rmbadname1(m.group('name').strip())
2178
+ if n in block['vars']:
2179
+ if 'attrspec' in block['vars'][n]:
2180
+ block['vars'][n]['attrspec'].append(
2181
+ f"dimension({','.join(dims)})")
2182
+ else:
2183
+ block['vars'][n]['attrspec'] = [
2184
+ f"dimension({','.join(dims)})"]
2185
+ elif dims:
2186
+ block['vars'][n] = {
2187
+ 'attrspec': [f"dimension({','.join(dims)})"]}
2188
+ else:
2189
+ block['vars'][n] = {}
2190
+ if n not in commonvars:
2191
+ commonvars.append(n)
2192
+ else:
2193
+ n = e
2194
+ errmess(
2195
+ f'analyzecommon: failed to extract "<name>[(<dims>)]" from "{e}" in common /{k}/.\n')
2196
+ comvars.append(n)
2197
+ block['common'][k] = comvars
2198
+ if 'commonvars' not in block:
2199
+ block['commonvars'] = commonvars
2200
+ else:
2201
+ block['commonvars'] = block['commonvars'] + commonvars
2202
+ return block
2203
+
2204
+
2205
+ def analyzebody(block, args, tab=''):
2206
+ global usermodules, skipfuncs, onlyfuncs, f90modulevars
2207
+
2208
+ setmesstext(block)
2209
+
2210
+ maybe_private = {
2211
+ key: value
2212
+ for key, value in block['vars'].items()
2213
+ if 'attrspec' not in value or 'public' not in value['attrspec']
2214
+ }
2215
+
2216
+ body = []
2217
+ for b in block['body']:
2218
+ b['parent_block'] = block
2219
+ if b['block'] in ['function', 'subroutine']:
2220
+ if args is not None and b['name'] not in args:
2221
+ continue
2222
+ else:
2223
+ as_ = b['args']
2224
+ # Add private members to skipfuncs for gh-23879
2225
+ if b['name'] in maybe_private.keys():
2226
+ skipfuncs.append(b['name'])
2227
+ if b['name'] in skipfuncs:
2228
+ continue
2229
+ if onlyfuncs and b['name'] not in onlyfuncs:
2230
+ continue
2231
+ b['saved_interface'] = crack2fortrangen(
2232
+ b, '\n' + ' ' * 6, as_interface=True)
2233
+
2234
+ else:
2235
+ as_ = args
2236
+ b = postcrack(b, as_, tab=tab + '\t')
2237
+ if b['block'] in ['interface', 'abstract interface'] and \
2238
+ not b['body'] and not b.get('implementedby'):
2239
+ if 'f2pyenhancements' not in b:
2240
+ continue
2241
+ if b['block'].replace(' ', '') == 'pythonmodule':
2242
+ usermodules.append(b)
2243
+ else:
2244
+ if b['block'] == 'module':
2245
+ f90modulevars[b['name']] = b['vars']
2246
+ body.append(b)
2247
+ return body
2248
+
2249
+
2250
+ def buildimplicitrules(block):
2251
+ setmesstext(block)
2252
+ implicitrules = defaultimplicitrules
2253
+ attrrules = {}
2254
+ if 'implicit' in block:
2255
+ if block['implicit'] is None:
2256
+ implicitrules = None
2257
+ if verbose > 1:
2258
+ outmess(
2259
+ f"buildimplicitrules: no implicit rules for routine {repr(block['name'])}.\n")
2260
+ else:
2261
+ for k in list(block['implicit'].keys()):
2262
+ if block['implicit'][k].get('typespec') not in ['static', 'automatic']:
2263
+ implicitrules[k] = block['implicit'][k]
2264
+ else:
2265
+ attrrules[k] = block['implicit'][k]['typespec']
2266
+ return implicitrules, attrrules
2267
+
2268
+
2269
+ def myeval(e, g=None, l=None):
2270
+ """ Like `eval` but returns only integers and floats """
2271
+ r = eval(e, g, l)
2272
+ if type(r) in [int, float]:
2273
+ return r
2274
+ raise ValueError(f'r={r!r}')
2275
+
2276
+
2277
+ getlincoef_re_1 = re.compile(r'\A\b\w+\b\Z', re.I)
2278
+
2279
+
2280
+ def getlincoef(e, xset): # e = a*x+b ; x in xset
2281
+ """
2282
+ Obtain ``a`` and ``b`` when ``e == "a*x+b"``, where ``x`` is a symbol in
2283
+ xset.
2284
+
2285
+ >>> getlincoef('2*x + 1', {'x'})
2286
+ (2, 1, 'x')
2287
+ >>> getlincoef('3*x + x*2 + 2 + 1', {'x'})
2288
+ (5, 3, 'x')
2289
+ >>> getlincoef('0', {'x'})
2290
+ (0, 0, None)
2291
+ >>> getlincoef('0*x', {'x'})
2292
+ (0, 0, 'x')
2293
+ >>> getlincoef('x*x', {'x'})
2294
+ (None, None, None)
2295
+
2296
+ This can be tricked by sufficiently complex expressions
2297
+
2298
+ >>> getlincoef('(x - 0.5)*(x - 1.5)*(x - 1)*x + 2*x + 3', {'x'})
2299
+ (2.0, 3.0, 'x')
2300
+ """
2301
+ try:
2302
+ c = int(myeval(e, {}, {}))
2303
+ return 0, c, None
2304
+ except Exception:
2305
+ pass
2306
+ if getlincoef_re_1.match(e):
2307
+ return 1, 0, e
2308
+ len_e = len(e)
2309
+ for x in xset:
2310
+ if len(x) > len_e:
2311
+ continue
2312
+ if re.search(r'\w\s*\([^)]*\b' + x + r'\b', e):
2313
+ # skip function calls having x as an argument, e.g max(1, x)
2314
+ continue
2315
+ re_1 = re.compile(r'(?P<before>.*?)\b' + x + r'\b(?P<after>.*)', re.I)
2316
+ m = re_1.match(e)
2317
+ if m:
2318
+ try:
2319
+ m1 = re_1.match(e)
2320
+ while m1:
2321
+ ee = f"{m1.group('before')}({0}){m1.group('after')}"
2322
+ m1 = re_1.match(ee)
2323
+ b = myeval(ee, {}, {})
2324
+ m1 = re_1.match(e)
2325
+ while m1:
2326
+ ee = f"{m1.group('before')}({1}){m1.group('after')}"
2327
+ m1 = re_1.match(ee)
2328
+ a = myeval(ee, {}, {}) - b
2329
+ m1 = re_1.match(e)
2330
+ while m1:
2331
+ ee = f"{m1.group('before')}({0.5}){m1.group('after')}"
2332
+ m1 = re_1.match(ee)
2333
+ c = myeval(ee, {}, {})
2334
+ # computing another point to be sure that expression is linear
2335
+ m1 = re_1.match(e)
2336
+ while m1:
2337
+ ee = f"{m1.group('before')}({1.5}){m1.group('after')}"
2338
+ m1 = re_1.match(ee)
2339
+ c2 = myeval(ee, {}, {})
2340
+ if (a * 0.5 + b == c and a * 1.5 + b == c2):
2341
+ return a, b, x
2342
+ except Exception:
2343
+ pass
2344
+ break
2345
+ return None, None, None
2346
+
2347
+
2348
+ word_pattern = re.compile(r'\b[a-z][\w$]*\b', re.I)
2349
+
2350
+
2351
+ def _get_depend_dict(name, vars, deps):
2352
+ if name in vars:
2353
+ words = vars[name].get('depend', [])
2354
+
2355
+ if '=' in vars[name] and not isstring(vars[name]):
2356
+ for word in word_pattern.findall(vars[name]['=']):
2357
+ # The word_pattern may return values that are not
2358
+ # only variables, they can be string content for instance
2359
+ if word not in words and word in vars and word != name:
2360
+ words.append(word)
2361
+ for word in words[:]:
2362
+ for w in deps.get(word, []) \
2363
+ or _get_depend_dict(word, vars, deps):
2364
+ if w not in words:
2365
+ words.append(w)
2366
+ else:
2367
+ outmess(f'_get_depend_dict: no dependence info for {repr(name)}\n')
2368
+ words = []
2369
+ deps[name] = words
2370
+ return words
2371
+
2372
+
2373
+ def _calc_depend_dict(vars):
2374
+ names = list(vars.keys())
2375
+ depend_dict = {}
2376
+ for n in names:
2377
+ _get_depend_dict(n, vars, depend_dict)
2378
+ return depend_dict
2379
+
2380
+
2381
+ def get_sorted_names(vars):
2382
+ depend_dict = _calc_depend_dict(vars)
2383
+ names = []
2384
+ for name in list(depend_dict.keys()):
2385
+ if not depend_dict[name]:
2386
+ names.append(name)
2387
+ del depend_dict[name]
2388
+ while depend_dict:
2389
+ for name, lst in list(depend_dict.items()):
2390
+ new_lst = [n for n in lst if n in depend_dict]
2391
+ if not new_lst:
2392
+ names.append(name)
2393
+ del depend_dict[name]
2394
+ else:
2395
+ depend_dict[name] = new_lst
2396
+ return [name for name in names if name in vars]
2397
+
2398
+
2399
+ def _kind_func(string):
2400
+ # XXX: return something sensible.
2401
+ if string[0] in "'\"":
2402
+ string = string[1:-1]
2403
+ if real16pattern.match(string):
2404
+ return 8
2405
+ elif real8pattern.match(string):
2406
+ return 4
2407
+ return 'kind(' + string + ')'
2408
+
2409
+
2410
+ def _selected_int_kind_func(r):
2411
+ # XXX: This should be processor dependent
2412
+ m = 10 ** r
2413
+ if m <= 2 ** 8:
2414
+ return 1
2415
+ if m <= 2 ** 16:
2416
+ return 2
2417
+ if m <= 2 ** 32:
2418
+ return 4
2419
+ if m <= 2 ** 63:
2420
+ return 8
2421
+ if m <= 2 ** 128:
2422
+ return 16
2423
+ return -1
2424
+
2425
+
2426
+ def _selected_real_kind_func(p, r=0, radix=0):
2427
+ # XXX: This should be processor dependent
2428
+ # This is only verified for 0 <= p <= 20, possibly good for p <= 33 and above
2429
+ if p < 7:
2430
+ return 4
2431
+ if p < 16:
2432
+ return 8
2433
+ machine = platform.machine().lower()
2434
+ if machine.startswith(('aarch64', 'alpha', 'arm64', 'loongarch', 'mips', 'power', 'ppc', 'riscv', 's390x', 'sparc')):
2435
+ if p <= 33:
2436
+ return 16
2437
+ elif p < 19:
2438
+ return 10
2439
+ elif p <= 33:
2440
+ return 16
2441
+ return -1
2442
+
2443
+
2444
+ def get_parameters(vars, global_params={}):
2445
+ params = copy.copy(global_params)
2446
+ g_params = copy.copy(global_params)
2447
+ for name, func in [('kind', _kind_func),
2448
+ ('selected_int_kind', _selected_int_kind_func),
2449
+ ('selected_real_kind', _selected_real_kind_func), ]:
2450
+ if name not in g_params:
2451
+ g_params[name] = func
2452
+ param_names = []
2453
+ for n in get_sorted_names(vars):
2454
+ if 'attrspec' in vars[n] and 'parameter' in vars[n]['attrspec']:
2455
+ param_names.append(n)
2456
+ kind_re = re.compile(r'\bkind\s*\(\s*(?P<value>.*)\s*\)', re.I)
2457
+ selected_int_kind_re = re.compile(
2458
+ r'\bselected_int_kind\s*\(\s*(?P<value>.*)\s*\)', re.I)
2459
+ selected_kind_re = re.compile(
2460
+ r'\bselected_(int|real)_kind\s*\(\s*(?P<value>.*)\s*\)', re.I)
2461
+ for n in param_names:
2462
+ if '=' in vars[n]:
2463
+ v = vars[n]['=']
2464
+ if islogical(vars[n]):
2465
+ v = v.lower()
2466
+ for repl in [
2467
+ ('.false.', 'False'),
2468
+ ('.true.', 'True'),
2469
+ # TODO: test .eq., .neq., etc replacements.
2470
+ ]:
2471
+ v = v.replace(*repl)
2472
+
2473
+ v = kind_re.sub(r'kind("\1")', v)
2474
+ v = selected_int_kind_re.sub(r'selected_int_kind(\1)', v)
2475
+
2476
+ # We need to act according to the data.
2477
+ # The easy case is if the data has a kind-specifier,
2478
+ # then we may easily remove those specifiers.
2479
+ # However, it may be that the user uses other specifiers...(!)
2480
+ is_replaced = False
2481
+
2482
+ if 'kindselector' in vars[n]:
2483
+ # Remove kind specifier (including those defined
2484
+ # by parameters)
2485
+ if 'kind' in vars[n]['kindselector']:
2486
+ orig_v_len = len(v)
2487
+ v = v.replace('_' + vars[n]['kindselector']['kind'], '')
2488
+ # Again, this will be true if even a single specifier
2489
+ # has been replaced, see comment above.
2490
+ is_replaced = len(v) < orig_v_len
2491
+
2492
+ if not is_replaced:
2493
+ if not selected_kind_re.match(v):
2494
+ v_ = v.split('_')
2495
+ # In case there are additive parameters
2496
+ if len(v_) > 1:
2497
+ v = ''.join(v_[:-1]).lower().replace(v_[-1].lower(), '')
2498
+
2499
+ # Currently this will not work for complex numbers.
2500
+ # There is missing code for extracting a complex number,
2501
+ # which may be defined in either of these:
2502
+ # a) (Re, Im)
2503
+ # b) cmplx(Re, Im)
2504
+ # c) dcmplx(Re, Im)
2505
+ # d) cmplx(Re, Im, <prec>)
2506
+
2507
+ if isdouble(vars[n]):
2508
+ tt = list(v)
2509
+ for m in real16pattern.finditer(v):
2510
+ tt[m.start():m.end()] = list(
2511
+ v[m.start():m.end()].lower().replace('d', 'e'))
2512
+ v = ''.join(tt)
2513
+
2514
+ elif iscomplex(vars[n]):
2515
+ outmess(f'get_parameters[TODO]: '
2516
+ f'implement evaluation of complex expression {v}\n')
2517
+
2518
+ dimspec = ([s.removeprefix('dimension').strip()
2519
+ for s in vars[n]['attrspec']
2520
+ if s.startswith('dimension')] or [None])[0]
2521
+
2522
+ # Handle _dp for gh-6624
2523
+ # Also fixes gh-20460
2524
+ if real16pattern.search(v):
2525
+ v = 8
2526
+ elif real8pattern.search(v):
2527
+ v = 4
2528
+ try:
2529
+ params[n] = param_eval(v, g_params, params, dimspec=dimspec)
2530
+ except Exception as msg:
2531
+ params[n] = v
2532
+ outmess(f'get_parameters: got "{msg}" on {n!r}\n')
2533
+
2534
+ if isstring(vars[n]) and isinstance(params[n], int):
2535
+ params[n] = chr(params[n])
2536
+ nl = n.lower()
2537
+ if nl != n:
2538
+ params[nl] = params[n]
2539
+ else:
2540
+ print(vars[n])
2541
+ outmess(f'get_parameters:parameter {n!r} does not have value?!\n')
2542
+ return params
2543
+
2544
+
2545
+ def _eval_length(length, params):
2546
+ if length in ['(:)', '(*)', '*']:
2547
+ return '(*)'
2548
+ return _eval_scalar(length, params)
2549
+
2550
+
2551
+ _is_kind_number = re.compile(r'\d+_').match
2552
+
2553
+
2554
+ def _eval_scalar(value, params):
2555
+ if _is_kind_number(value):
2556
+ value = value.split('_')[0]
2557
+ try:
2558
+ # TODO: use symbolic from PR #19805
2559
+ value = eval(value, {}, params)
2560
+ value = (repr if isinstance(value, str) else str)(value)
2561
+ except (NameError, SyntaxError, TypeError):
2562
+ return value
2563
+ except Exception as msg:
2564
+ errmess('"%s" in evaluating %r '
2565
+ '(available names: %s)\n'
2566
+ % (msg, value, list(params.keys())))
2567
+ return value
2568
+
2569
+
2570
+ def analyzevars(block):
2571
+ """
2572
+ Sets correct dimension information for each variable/parameter
2573
+ """
2574
+
2575
+ global f90modulevars
2576
+
2577
+ setmesstext(block)
2578
+ implicitrules, attrrules = buildimplicitrules(block)
2579
+ vars = copy.copy(block['vars'])
2580
+ if block['block'] == 'function' and block['name'] not in vars:
2581
+ vars[block['name']] = {}
2582
+ if '' in block['vars']:
2583
+ del vars['']
2584
+ if 'attrspec' in block['vars']['']:
2585
+ gen = block['vars']['']['attrspec']
2586
+ for n in set(vars) | {b['name'] for b in block['body']}:
2587
+ for k in ['public', 'private']:
2588
+ if k in gen:
2589
+ vars[n] = setattrspec(vars.get(n, {}), k)
2590
+ svars = []
2591
+ args = block['args']
2592
+ for a in args:
2593
+ try:
2594
+ vars[a]
2595
+ svars.append(a)
2596
+ except KeyError:
2597
+ pass
2598
+ for n in list(vars.keys()):
2599
+ if n not in args:
2600
+ svars.append(n)
2601
+
2602
+ params = get_parameters(vars, get_useparameters(block))
2603
+ # At this point, params are read and interpreted, but
2604
+ # the params used to define vars are not yet parsed
2605
+ dep_matches = {}
2606
+ name_match = re.compile(r'[A-Za-z][\w$]*').match
2607
+ for v in list(vars.keys()):
2608
+ m = name_match(v)
2609
+ if m:
2610
+ n = v[m.start():m.end()]
2611
+ try:
2612
+ dep_matches[n]
2613
+ except KeyError:
2614
+ dep_matches[n] = re.compile(r'.*\b%s\b' % (v), re.I).match
2615
+ for n in svars:
2616
+ if n[0] in list(attrrules.keys()):
2617
+ vars[n] = setattrspec(vars[n], attrrules[n[0]])
2618
+ if 'typespec' not in vars[n]:
2619
+ if not ('attrspec' in vars[n] and 'external' in vars[n]['attrspec']):
2620
+ if implicitrules:
2621
+ ln0 = n[0].lower()
2622
+ for k in list(implicitrules[ln0].keys()):
2623
+ if k == 'typespec' and implicitrules[ln0][k] == 'undefined':
2624
+ continue
2625
+ if k not in vars[n]:
2626
+ vars[n][k] = implicitrules[ln0][k]
2627
+ elif k == 'attrspec':
2628
+ for l in implicitrules[ln0][k]:
2629
+ vars[n] = setattrspec(vars[n], l)
2630
+ elif n in block['args']:
2631
+ outmess('analyzevars: typespec of variable %s is not defined in routine %s.\n' % (
2632
+ repr(n), block['name']))
2633
+ if 'charselector' in vars[n]:
2634
+ if 'len' in vars[n]['charselector']:
2635
+ l = vars[n]['charselector']['len']
2636
+ try:
2637
+ l = str(eval(l, {}, params))
2638
+ except Exception:
2639
+ pass
2640
+ vars[n]['charselector']['len'] = l
2641
+
2642
+ if 'kindselector' in vars[n]:
2643
+ if 'kind' in vars[n]['kindselector']:
2644
+ l = vars[n]['kindselector']['kind']
2645
+ try:
2646
+ l = str(eval(l, {}, params))
2647
+ except Exception:
2648
+ pass
2649
+ vars[n]['kindselector']['kind'] = l
2650
+
2651
+ dimension_exprs = {}
2652
+ if 'attrspec' in vars[n]:
2653
+ attr = vars[n]['attrspec']
2654
+ attr.reverse()
2655
+ vars[n]['attrspec'] = []
2656
+ dim, intent, depend, check, note = None, None, None, None, None
2657
+ for a in attr:
2658
+ if a[:9] == 'dimension':
2659
+ dim = (a[9:].strip())[1:-1]
2660
+ elif a[:6] == 'intent':
2661
+ intent = (a[6:].strip())[1:-1]
2662
+ elif a[:6] == 'depend':
2663
+ depend = (a[6:].strip())[1:-1]
2664
+ elif a[:5] == 'check':
2665
+ check = (a[5:].strip())[1:-1]
2666
+ elif a[:4] == 'note':
2667
+ note = (a[4:].strip())[1:-1]
2668
+ else:
2669
+ vars[n] = setattrspec(vars[n], a)
2670
+ if intent:
2671
+ if 'intent' not in vars[n]:
2672
+ vars[n]['intent'] = []
2673
+ for c in [x.strip() for x in markoutercomma(intent).split('@,@')]:
2674
+ # Remove spaces so that 'in out' becomes 'inout'
2675
+ tmp = c.replace(' ', '')
2676
+ if tmp not in vars[n]['intent']:
2677
+ vars[n]['intent'].append(tmp)
2678
+ intent = None
2679
+ if note:
2680
+ note = note.replace('\\n\\n', '\n\n')
2681
+ note = note.replace('\\n ', '\n')
2682
+ if 'note' not in vars[n]:
2683
+ vars[n]['note'] = [note]
2684
+ else:
2685
+ vars[n]['note'].append(note)
2686
+ note = None
2687
+ if depend is not None:
2688
+ if 'depend' not in vars[n]:
2689
+ vars[n]['depend'] = []
2690
+ for c in rmbadname([x.strip() for x in markoutercomma(depend).split('@,@')]):
2691
+ if c not in vars[n]['depend']:
2692
+ vars[n]['depend'].append(c)
2693
+ depend = None
2694
+ if check is not None:
2695
+ if 'check' not in vars[n]:
2696
+ vars[n]['check'] = []
2697
+ for c in [x.strip() for x in markoutercomma(check).split('@,@')]:
2698
+ if c not in vars[n]['check']:
2699
+ vars[n]['check'].append(c)
2700
+ check = None
2701
+ if dim and 'dimension' not in vars[n]:
2702
+ vars[n]['dimension'] = []
2703
+ for d in rmbadname(
2704
+ [x.strip() for x in markoutercomma(dim).split('@,@')]
2705
+ ):
2706
+ # d is the expression inside the dimension declaration
2707
+ # Evaluate `d` with respect to params
2708
+ try:
2709
+ # the dimension for this variable depends on a
2710
+ # previously defined parameter
2711
+ d = param_parse(d, params)
2712
+ except (ValueError, IndexError, KeyError):
2713
+ outmess(
2714
+ 'analyzevars: could not parse dimension for '
2715
+ f'variable {d!r}\n'
2716
+ )
2717
+
2718
+ dim_char = ':' if d == ':' else '*'
2719
+ if d == dim_char:
2720
+ dl = [dim_char]
2721
+ else:
2722
+ dl = markoutercomma(d, ':').split('@:@')
2723
+ if len(dl) == 2 and '*' in dl: # e.g. dimension(5:*)
2724
+ dl = ['*']
2725
+ d = '*'
2726
+ if len(dl) == 1 and dl[0] != dim_char:
2727
+ dl = ['1', dl[0]]
2728
+ if len(dl) == 2:
2729
+ d1, d2 = map(symbolic.Expr.parse, dl)
2730
+ dsize = d2 - d1 + 1
2731
+ d = dsize.tostring(language=symbolic.Language.C)
2732
+ # find variables v that define d as a linear
2733
+ # function, `d == a * v + b`, and store
2734
+ # coefficients a and b for further analysis.
2735
+ solver_and_deps = {}
2736
+ for v in block['vars']:
2737
+ s = symbolic.as_symbol(v)
2738
+ if dsize.contains(s):
2739
+ try:
2740
+ a, b = dsize.linear_solve(s)
2741
+
2742
+ def solve_v(s, a=a, b=b):
2743
+ return (s - b) / a
2744
+
2745
+ all_symbols = set(a.symbols())
2746
+ all_symbols.update(b.symbols())
2747
+ except RuntimeError as msg:
2748
+ # d is not a linear function of v,
2749
+ # however, if v can be determined
2750
+ # from d using other means,
2751
+ # implement the corresponding
2752
+ # solve_v function here.
2753
+ solve_v = None
2754
+ all_symbols = set(dsize.symbols())
2755
+ v_deps = {
2756
+ s.data for s in all_symbols
2757
+ if s.data in vars}
2758
+ solver_and_deps[v] = solve_v, list(v_deps)
2759
+ # Note that dsize may contain symbols that are
2760
+ # not defined in block['vars']. Here we assume
2761
+ # these correspond to Fortran/C intrinsic
2762
+ # functions or that are defined by other
2763
+ # means. We'll let the compiler validate the
2764
+ # definiteness of such symbols.
2765
+ dimension_exprs[d] = solver_and_deps
2766
+ vars[n]['dimension'].append(d)
2767
+
2768
+ if 'check' not in vars[n] and 'args' in block and n in block['args']:
2769
+ # n is an argument that has no checks defined. Here we
2770
+ # generate some consistency checks for n, and when n is an
2771
+ # array, generate checks for its dimensions and construct
2772
+ # initialization expressions.
2773
+ n_deps = vars[n].get('depend', [])
2774
+ n_checks = []
2775
+ n_is_input = l_or(isintent_in, isintent_inout,
2776
+ isintent_inplace)(vars[n])
2777
+ if isarray(vars[n]): # n is array
2778
+ for i, d in enumerate(vars[n]['dimension']):
2779
+ coeffs_and_deps = dimension_exprs.get(d)
2780
+ if coeffs_and_deps is None:
2781
+ # d is `:` or `*` or a constant expression
2782
+ pass
2783
+ elif n_is_input:
2784
+ # n is an input array argument and its shape
2785
+ # may define variables used in dimension
2786
+ # specifications.
2787
+ for v, (solver, deps) in coeffs_and_deps.items():
2788
+ def compute_deps(v, deps):
2789
+ for v1 in coeffs_and_deps.get(v, [None, []])[1]:
2790
+ if v1 not in deps:
2791
+ deps.add(v1)
2792
+ compute_deps(v1, deps)
2793
+ all_deps = set()
2794
+ compute_deps(v, all_deps)
2795
+ if (v in n_deps
2796
+ or '=' in vars[v]
2797
+ or 'depend' in vars[v]):
2798
+ # Skip a variable that
2799
+ # - n depends on
2800
+ # - has user-defined initialization expression
2801
+ # - has user-defined dependencies
2802
+ continue
2803
+ if solver is not None and v not in all_deps:
2804
+ # v can be solved from d, hence, we
2805
+ # make it an optional argument with
2806
+ # initialization expression:
2807
+ is_required = False
2808
+ init = solver(symbolic.as_symbol(
2809
+ f'shape({n}, {i})'))
2810
+ init = init.tostring(
2811
+ language=symbolic.Language.C)
2812
+ vars[v]['='] = init
2813
+ # n needs to be initialized before v. So,
2814
+ # making v dependent on n and on any
2815
+ # variables in solver or d.
2816
+ vars[v]['depend'] = [n] + deps
2817
+ if 'check' not in vars[v]:
2818
+ # add check only when no
2819
+ # user-specified checks exist
2820
+ vars[v]['check'] = [
2821
+ f'shape({n}, {i}) == {d}']
2822
+ else:
2823
+ # d is a non-linear function on v,
2824
+ # hence, v must be a required input
2825
+ # argument that n will depend on
2826
+ is_required = True
2827
+ if 'intent' not in vars[v]:
2828
+ vars[v]['intent'] = []
2829
+ if 'in' not in vars[v]['intent']:
2830
+ vars[v]['intent'].append('in')
2831
+ # v needs to be initialized before n
2832
+ n_deps.append(v)
2833
+ n_checks.append(
2834
+ f'shape({n}, {i}) == {d}')
2835
+ v_attr = vars[v].get('attrspec', [])
2836
+ if not ('optional' in v_attr
2837
+ or 'required' in v_attr):
2838
+ v_attr.append(
2839
+ 'required' if is_required else 'optional')
2840
+ if v_attr:
2841
+ vars[v]['attrspec'] = v_attr
2842
+ if coeffs_and_deps is not None:
2843
+ # extend v dependencies with ones specified in attrspec
2844
+ for v, (solver, deps) in coeffs_and_deps.items():
2845
+ v_deps = vars[v].get('depend', [])
2846
+ for aa in vars[v].get('attrspec', []):
2847
+ if aa.startswith('depend'):
2848
+ aa = ''.join(aa.split())
2849
+ v_deps.extend(aa[7:-1].split(','))
2850
+ if v_deps:
2851
+ vars[v]['depend'] = list(set(v_deps))
2852
+ if n not in v_deps:
2853
+ n_deps.append(v)
2854
+ elif isstring(vars[n]):
2855
+ if 'charselector' in vars[n]:
2856
+ if '*' in vars[n]['charselector']:
2857
+ length = _eval_length(vars[n]['charselector']['*'],
2858
+ params)
2859
+ vars[n]['charselector']['*'] = length
2860
+ elif 'len' in vars[n]['charselector']:
2861
+ length = _eval_length(vars[n]['charselector']['len'],
2862
+ params)
2863
+ del vars[n]['charselector']['len']
2864
+ vars[n]['charselector']['*'] = length
2865
+ if n_checks:
2866
+ vars[n]['check'] = n_checks
2867
+ if n_deps:
2868
+ vars[n]['depend'] = list(set(n_deps))
2869
+
2870
+ if '=' in vars[n]:
2871
+ if 'attrspec' not in vars[n]:
2872
+ vars[n]['attrspec'] = []
2873
+ if ('optional' not in vars[n]['attrspec']) and \
2874
+ ('required' not in vars[n]['attrspec']):
2875
+ vars[n]['attrspec'].append('optional')
2876
+ if 'depend' not in vars[n]:
2877
+ vars[n]['depend'] = []
2878
+ for v, m in list(dep_matches.items()):
2879
+ if m(vars[n]['=']):
2880
+ vars[n]['depend'].append(v)
2881
+ if not vars[n]['depend']:
2882
+ del vars[n]['depend']
2883
+ if isscalar(vars[n]):
2884
+ vars[n]['='] = _eval_scalar(vars[n]['='], params)
2885
+
2886
+ for n in list(vars.keys()):
2887
+ if n == block['name']: # n is block name
2888
+ if 'note' in vars[n]:
2889
+ block['note'] = vars[n]['note']
2890
+ if block['block'] == 'function':
2891
+ if 'result' in block and block['result'] in vars:
2892
+ vars[n] = appenddecl(vars[n], vars[block['result']])
2893
+ if 'prefix' in block:
2894
+ pr = block['prefix']
2895
+ pr1 = pr.replace('pure', '')
2896
+ ispure = (not pr == pr1)
2897
+ pr = pr1.replace('recursive', '')
2898
+ isrec = (not pr == pr1)
2899
+ m = typespattern[0].match(pr)
2900
+ if m:
2901
+ typespec, selector, attr, edecl = cracktypespec0(
2902
+ m.group('this'), m.group('after'))
2903
+ kindselect, charselect, typename = cracktypespec(
2904
+ typespec, selector)
2905
+ vars[n]['typespec'] = typespec
2906
+ try:
2907
+ if block['result']:
2908
+ vars[block['result']]['typespec'] = typespec
2909
+ except Exception:
2910
+ pass
2911
+ if kindselect:
2912
+ if 'kind' in kindselect:
2913
+ try:
2914
+ kindselect['kind'] = eval(
2915
+ kindselect['kind'], {}, params)
2916
+ except Exception:
2917
+ pass
2918
+ vars[n]['kindselector'] = kindselect
2919
+ if charselect:
2920
+ vars[n]['charselector'] = charselect
2921
+ if typename:
2922
+ vars[n]['typename'] = typename
2923
+ if ispure:
2924
+ vars[n] = setattrspec(vars[n], 'pure')
2925
+ if isrec:
2926
+ vars[n] = setattrspec(vars[n], 'recursive')
2927
+ else:
2928
+ outmess(
2929
+ f"analyzevars: prefix ({repr(block['prefix'])}) were not used\n")
2930
+ if block['block'] not in ['module', 'pythonmodule', 'python module', 'block data']:
2931
+ if 'commonvars' in block:
2932
+ neededvars = copy.copy(block['args'] + block['commonvars'])
2933
+ else:
2934
+ neededvars = copy.copy(block['args'])
2935
+ for n in list(vars.keys()):
2936
+ if l_or(isintent_callback, isintent_aux)(vars[n]):
2937
+ neededvars.append(n)
2938
+ if 'entry' in block:
2939
+ neededvars.extend(list(block['entry'].keys()))
2940
+ for k in list(block['entry'].keys()):
2941
+ for n in block['entry'][k]:
2942
+ if n not in neededvars:
2943
+ neededvars.append(n)
2944
+ if block['block'] == 'function':
2945
+ if 'result' in block:
2946
+ neededvars.append(block['result'])
2947
+ else:
2948
+ neededvars.append(block['name'])
2949
+ if block['block'] in ['subroutine', 'function']:
2950
+ name = block['name']
2951
+ if name in vars and 'intent' in vars[name]:
2952
+ block['intent'] = vars[name]['intent']
2953
+ if block['block'] == 'type':
2954
+ neededvars.extend(list(vars.keys()))
2955
+ for n in list(vars.keys()):
2956
+ if n not in neededvars:
2957
+ del vars[n]
2958
+ return vars
2959
+
2960
+
2961
+ analyzeargs_re_1 = re.compile(r'\A[a-z]+[\w$]*\Z', re.I)
2962
+
2963
+
2964
+ def param_eval(v, g_params, params, dimspec=None):
2965
+ """
2966
+ Creates a dictionary of indices and values for each parameter in a
2967
+ parameter array to be evaluated later.
2968
+
2969
+ WARNING: It is not possible to initialize multidimensional array
2970
+ parameters e.g. dimension(-3:1, 4, 3:5) at this point. This is because in
2971
+ Fortran initialization through array constructor requires the RESHAPE
2972
+ intrinsic function. Since the right-hand side of the parameter declaration
2973
+ is not executed in f2py, but rather at the compiled c/fortran extension,
2974
+ later, it is not possible to execute a reshape of a parameter array.
2975
+ One issue remains: if the user wants to access the array parameter from
2976
+ python, we should either
2977
+ 1) allow them to access the parameter array using python standard indexing
2978
+ (which is often incompatible with the original fortran indexing)
2979
+ 2) allow the parameter array to be accessed in python as a dictionary with
2980
+ fortran indices as keys
2981
+ We are choosing 2 for now.
2982
+ """
2983
+ if dimspec is None:
2984
+ try:
2985
+ p = eval(v, g_params, params)
2986
+ except Exception as msg:
2987
+ p = v
2988
+ outmess(f'param_eval: got "{msg}" on {v!r}\n')
2989
+ return p
2990
+
2991
+ # This is an array parameter.
2992
+ # First, we parse the dimension information
2993
+ if len(dimspec) < 2 or dimspec[::len(dimspec) - 1] != "()":
2994
+ raise ValueError(f'param_eval: dimension {dimspec} can\'t be parsed')
2995
+ dimrange = dimspec[1:-1].split(',')
2996
+ if len(dimrange) == 1:
2997
+ # e.g. dimension(2) or dimension(-1:1)
2998
+ dimrange = dimrange[0].split(':')
2999
+ # now, dimrange is a list of 1 or 2 elements
3000
+ if len(dimrange) == 1:
3001
+ bound = param_parse(dimrange[0], params)
3002
+ dimrange = range(1, int(bound) + 1)
3003
+ else:
3004
+ lbound = param_parse(dimrange[0], params)
3005
+ ubound = param_parse(dimrange[1], params)
3006
+ dimrange = range(int(lbound), int(ubound) + 1)
3007
+ else:
3008
+ raise ValueError('param_eval: multidimensional array parameters '
3009
+ f'{dimspec} not supported')
3010
+
3011
+ # Parse parameter value
3012
+ v = (v[2:-2] if v.startswith('(/') else v).split(',')
3013
+ v_eval = []
3014
+ for item in v:
3015
+ try:
3016
+ item = eval(item, g_params, params)
3017
+ except Exception as msg:
3018
+ outmess(f'param_eval: got "{msg}" on {item!r}\n')
3019
+ v_eval.append(item)
3020
+
3021
+ p = dict(zip(dimrange, v_eval))
3022
+
3023
+ return p
3024
+
3025
+
3026
+ def param_parse(d, params):
3027
+ """Recursively parse array dimensions.
3028
+
3029
+ Parses the declaration of an array variable or parameter
3030
+ `dimension` keyword, and is called recursively if the
3031
+ dimension for this array is a previously defined parameter
3032
+ (found in `params`).
3033
+
3034
+ Parameters
3035
+ ----------
3036
+ d : str
3037
+ Fortran expression describing the dimension of an array.
3038
+ params : dict
3039
+ Previously parsed parameters declared in the Fortran source file.
3040
+
3041
+ Returns
3042
+ -------
3043
+ out : str
3044
+ Parsed dimension expression.
3045
+
3046
+ Examples
3047
+ --------
3048
+
3049
+ * If the line being analyzed is
3050
+
3051
+ `integer, parameter, dimension(2) :: pa = (/ 3, 5 /)`
3052
+
3053
+ then `d = 2` and we return immediately, with
3054
+
3055
+ >>> d = '2'
3056
+ >>> param_parse(d, params)
3057
+ 2
3058
+
3059
+ * If the line being analyzed is
3060
+
3061
+ `integer, parameter, dimension(pa) :: pb = (/1, 2, 3/)`
3062
+
3063
+ then `d = 'pa'`; since `pa` is a previously parsed parameter,
3064
+ and `pa = 3`, we call `param_parse` recursively, to obtain
3065
+
3066
+ >>> d = 'pa'
3067
+ >>> params = {'pa': 3}
3068
+ >>> param_parse(d, params)
3069
+ 3
3070
+
3071
+ * If the line being analyzed is
3072
+
3073
+ `integer, parameter, dimension(pa(1)) :: pb = (/1, 2, 3/)`
3074
+
3075
+ then `d = 'pa(1)'`; since `pa` is a previously parsed parameter,
3076
+ and `pa(1) = 3`, we call `param_parse` recursively, to obtain
3077
+
3078
+ >>> d = 'pa(1)'
3079
+ >>> params = dict(pa={1: 3, 2: 5})
3080
+ >>> param_parse(d, params)
3081
+ 3
3082
+ """
3083
+ if "(" in d:
3084
+ # this dimension expression is an array
3085
+ dname = d[:d.find("(")]
3086
+ ddims = d[d.find("(") + 1:d.rfind(")")]
3087
+ # this dimension expression is also a parameter;
3088
+ # parse it recursively
3089
+ index = int(param_parse(ddims, params))
3090
+ return str(params[dname][index])
3091
+ elif d in params:
3092
+ return str(params[d])
3093
+ else:
3094
+ for p in params:
3095
+ re_1 = re.compile(
3096
+ r'(?P<before>.*?)\b' + p + r'\b(?P<after>.*)', re.I
3097
+ )
3098
+ m = re_1.match(d)
3099
+ while m:
3100
+ d = m.group('before') + \
3101
+ str(params[p]) + m.group('after')
3102
+ m = re_1.match(d)
3103
+ return d
3104
+
3105
+
3106
+ def expr2name(a, block, args=[]):
3107
+ orig_a = a
3108
+ a_is_expr = not analyzeargs_re_1.match(a)
3109
+ if a_is_expr: # `a` is an expression
3110
+ implicitrules, attrrules = buildimplicitrules(block)
3111
+ at = determineexprtype(a, block['vars'], implicitrules)
3112
+ na = 'e_'
3113
+ for c in a:
3114
+ c = c.lower()
3115
+ if c not in string.ascii_lowercase + string.digits:
3116
+ c = '_'
3117
+ na = na + c
3118
+ if na[-1] == '_':
3119
+ na = na + 'e'
3120
+ else:
3121
+ na = na + '_e'
3122
+ a = na
3123
+ while a in block['vars'] or a in block['args']:
3124
+ a = a + 'r'
3125
+ if a in args:
3126
+ k = 1
3127
+ while a + str(k) in args:
3128
+ k = k + 1
3129
+ a = a + str(k)
3130
+ if a_is_expr:
3131
+ block['vars'][a] = at
3132
+ else:
3133
+ if a not in block['vars']:
3134
+ block['vars'][a] = block['vars'].get(orig_a, {})
3135
+ if 'externals' in block and orig_a in block['externals'] + block['interfaced']:
3136
+ block['vars'][a] = setattrspec(block['vars'][a], 'external')
3137
+ return a
3138
+
3139
+
3140
+ def analyzeargs(block):
3141
+ setmesstext(block)
3142
+ implicitrules, _ = buildimplicitrules(block)
3143
+ if 'args' not in block:
3144
+ block['args'] = []
3145
+ args = []
3146
+ for a in block['args']:
3147
+ a = expr2name(a, block, args)
3148
+ args.append(a)
3149
+ block['args'] = args
3150
+ if 'entry' in block:
3151
+ for k, args1 in list(block['entry'].items()):
3152
+ for a in args1:
3153
+ if a not in block['vars']:
3154
+ block['vars'][a] = {}
3155
+
3156
+ for b in block['body']:
3157
+ if b['name'] in args:
3158
+ if 'externals' not in block:
3159
+ block['externals'] = []
3160
+ if b['name'] not in block['externals']:
3161
+ block['externals'].append(b['name'])
3162
+ if 'result' in block and block['result'] not in block['vars']:
3163
+ block['vars'][block['result']] = {}
3164
+ return block
3165
+
3166
+
3167
+ determineexprtype_re_1 = re.compile(r'\A\(.+?,.+?\)\Z', re.I)
3168
+ determineexprtype_re_2 = re.compile(r'\A[+-]?\d+(_(?P<name>\w+)|)\Z', re.I)
3169
+ determineexprtype_re_3 = re.compile(
3170
+ r'\A[+-]?[\d.]+[-\d+de.]*(_(?P<name>\w+)|)\Z', re.I)
3171
+ determineexprtype_re_4 = re.compile(r'\A\(.*\)\Z', re.I)
3172
+ determineexprtype_re_5 = re.compile(r'\A(?P<name>\w+)\s*\(.*?\)\s*\Z', re.I)
3173
+
3174
+
3175
+ def _ensure_exprdict(r):
3176
+ if isinstance(r, int):
3177
+ return {'typespec': 'integer'}
3178
+ if isinstance(r, float):
3179
+ return {'typespec': 'real'}
3180
+ if isinstance(r, complex):
3181
+ return {'typespec': 'complex'}
3182
+ if isinstance(r, dict):
3183
+ return r
3184
+ raise AssertionError(repr(r))
3185
+
3186
+
3187
+ def determineexprtype(expr, vars, rules={}):
3188
+ if expr in vars:
3189
+ return _ensure_exprdict(vars[expr])
3190
+ expr = expr.strip()
3191
+ if determineexprtype_re_1.match(expr):
3192
+ return {'typespec': 'complex'}
3193
+ m = determineexprtype_re_2.match(expr)
3194
+ if m:
3195
+ if 'name' in m.groupdict() and m.group('name'):
3196
+ outmess(
3197
+ f'determineexprtype: selected kind types not supported ({repr(expr)})\n')
3198
+ return {'typespec': 'integer'}
3199
+ m = determineexprtype_re_3.match(expr)
3200
+ if m:
3201
+ if 'name' in m.groupdict() and m.group('name'):
3202
+ outmess(
3203
+ f'determineexprtype: selected kind types not supported ({repr(expr)})\n')
3204
+ return {'typespec': 'real'}
3205
+ for op in ['+', '-', '*', '/']:
3206
+ for e in [x.strip() for x in markoutercomma(expr, comma=op).split('@' + op + '@')]:
3207
+ if e in vars:
3208
+ return _ensure_exprdict(vars[e])
3209
+ t = {}
3210
+ if determineexprtype_re_4.match(expr): # in parenthesis
3211
+ t = determineexprtype(expr[1:-1], vars, rules)
3212
+ else:
3213
+ m = determineexprtype_re_5.match(expr)
3214
+ if m:
3215
+ rn = m.group('name')
3216
+ t = determineexprtype(m.group('name'), vars, rules)
3217
+ if t and 'attrspec' in t:
3218
+ del t['attrspec']
3219
+ if not t:
3220
+ if rn[0] in rules:
3221
+ return _ensure_exprdict(rules[rn[0]])
3222
+ if expr[0] in '\'"':
3223
+ return {'typespec': 'character', 'charselector': {'*': '*'}}
3224
+ if not t:
3225
+ outmess(
3226
+ f'determineexprtype: could not determine expressions ({repr(expr)}) type.\n')
3227
+ return t
3228
+
3229
+ ######
3230
+
3231
+
3232
+ def crack2fortrangen(block, tab='\n', as_interface=False):
3233
+ global skipfuncs, onlyfuncs
3234
+
3235
+ setmesstext(block)
3236
+ ret = ''
3237
+ if isinstance(block, list):
3238
+ for g in block:
3239
+ if g and g['block'] in ['function', 'subroutine']:
3240
+ if g['name'] in skipfuncs:
3241
+ continue
3242
+ if onlyfuncs and g['name'] not in onlyfuncs:
3243
+ continue
3244
+ ret = ret + crack2fortrangen(g, tab, as_interface=as_interface)
3245
+ return ret
3246
+ prefix = ''
3247
+ name = ''
3248
+ args = ''
3249
+ blocktype = block['block']
3250
+ if blocktype == 'program':
3251
+ return ''
3252
+ argsl = []
3253
+ if 'name' in block:
3254
+ name = block['name']
3255
+ if 'args' in block:
3256
+ vars = block['vars']
3257
+ for a in block['args']:
3258
+ a = expr2name(a, block, argsl)
3259
+ if not isintent_callback(vars[a]):
3260
+ argsl.append(a)
3261
+ if block['block'] == 'function' or argsl:
3262
+ args = f"({','.join(argsl)})"
3263
+ f2pyenhancements = ''
3264
+ if 'f2pyenhancements' in block:
3265
+ for k in list(block['f2pyenhancements'].keys()):
3266
+ f2pyenhancements = '%s%s%s %s' % (
3267
+ f2pyenhancements, tab + tabchar, k, block['f2pyenhancements'][k])
3268
+ intent_lst = block.get('intent', [])[:]
3269
+ if blocktype == 'function' and 'callback' in intent_lst:
3270
+ intent_lst.remove('callback')
3271
+ if intent_lst:
3272
+ f2pyenhancements = '%s%sintent(%s) %s' %\
3273
+ (f2pyenhancements, tab + tabchar,
3274
+ ','.join(intent_lst), name)
3275
+ use = ''
3276
+ if 'use' in block:
3277
+ use = use2fortran(block['use'], tab + tabchar)
3278
+ common = ''
3279
+ if 'common' in block:
3280
+ common = common2fortran(block['common'], tab + tabchar)
3281
+ if name == 'unknown_interface':
3282
+ name = ''
3283
+ result = ''
3284
+ if 'result' in block:
3285
+ result = f" result ({block['result']})"
3286
+ if block['result'] not in argsl:
3287
+ argsl.append(block['result'])
3288
+ body = crack2fortrangen(block['body'], tab + tabchar, as_interface=as_interface)
3289
+ vars = vars2fortran(
3290
+ block, block['vars'], argsl, tab + tabchar, as_interface=as_interface)
3291
+ mess = ''
3292
+ if 'from' in block and not as_interface:
3293
+ mess = f"! in {block['from']}"
3294
+ if 'entry' in block:
3295
+ entry_stmts = ''
3296
+ for k, i in list(block['entry'].items()):
3297
+ entry_stmts = f"{entry_stmts}{tab + tabchar}entry {k}({','.join(i)})"
3298
+ body = body + entry_stmts
3299
+ if blocktype == 'block data' and name == '_BLOCK_DATA_':
3300
+ name = ''
3301
+ ret = '%s%s%s %s%s%s %s%s%s%s%s%s%send %s %s' % (
3302
+ tab, prefix, blocktype, name, args, result, mess, f2pyenhancements, use, vars, common, body, tab, blocktype, name)
3303
+ return ret
3304
+
3305
+
3306
+ def common2fortran(common, tab=''):
3307
+ ret = ''
3308
+ for k in list(common.keys()):
3309
+ if k == '_BLNK_':
3310
+ ret = f"{ret}{tab}common {','.join(common[k])}"
3311
+ else:
3312
+ ret = f"{ret}{tab}common /{k}/ {','.join(common[k])}"
3313
+ return ret
3314
+
3315
+
3316
+ def use2fortran(use, tab=''):
3317
+ ret = ''
3318
+ for m in list(use.keys()):
3319
+ ret = f'{ret}{tab}use {m},'
3320
+ if use[m] == {}:
3321
+ if ret and ret[-1] == ',':
3322
+ ret = ret[:-1]
3323
+ continue
3324
+ if 'only' in use[m] and use[m]['only']:
3325
+ ret = f'{ret} only:'
3326
+ if 'map' in use[m] and use[m]['map']:
3327
+ c = ' '
3328
+ for k in list(use[m]['map'].keys()):
3329
+ if k == use[m]['map'][k]:
3330
+ ret = f'{ret}{c}{k}'
3331
+ c = ','
3332
+ else:
3333
+ ret = f"{ret}{c}{k}=>{use[m]['map'][k]}"
3334
+ c = ','
3335
+ if ret and ret[-1] == ',':
3336
+ ret = ret[:-1]
3337
+ return ret
3338
+
3339
+
3340
+ def true_intent_list(var):
3341
+ lst = var['intent']
3342
+ ret = []
3343
+ for intent in lst:
3344
+ try:
3345
+ f = globals()[f'isintent_{intent}']
3346
+ except KeyError:
3347
+ pass
3348
+ else:
3349
+ if f(var):
3350
+ ret.append(intent)
3351
+ return ret
3352
+
3353
+
3354
+ def vars2fortran(block, vars, args, tab='', as_interface=False):
3355
+ setmesstext(block)
3356
+ ret = ''
3357
+ nout = []
3358
+ for a in args:
3359
+ if a in block['vars']:
3360
+ nout.append(a)
3361
+ if 'commonvars' in block:
3362
+ for a in block['commonvars']:
3363
+ if a in vars:
3364
+ if a not in nout:
3365
+ nout.append(a)
3366
+ else:
3367
+ errmess(
3368
+ f'vars2fortran: Confused?!: "{a}" is not defined in vars.\n')
3369
+ if 'varnames' in block:
3370
+ nout.extend(block['varnames'])
3371
+ if not as_interface:
3372
+ for a in list(vars.keys()):
3373
+ if a not in nout:
3374
+ nout.append(a)
3375
+ for a in nout:
3376
+ if 'depend' in vars[a]:
3377
+ for d in vars[a]['depend']:
3378
+ if d in vars and 'depend' in vars[d] and a in vars[d]['depend']:
3379
+ errmess(
3380
+ f'vars2fortran: Warning: cross-dependence between variables "{a}" and "{d}\"\n')
3381
+ if 'externals' in block and a in block['externals']:
3382
+ if isintent_callback(vars[a]):
3383
+ ret = f'{ret}{tab}intent(callback) {a}'
3384
+ ret = f'{ret}{tab}external {a}'
3385
+ if isoptional(vars[a]):
3386
+ ret = f'{ret}{tab}optional {a}'
3387
+ if a in vars and 'typespec' not in vars[a]:
3388
+ continue
3389
+ cont = 1
3390
+ for b in block['body']:
3391
+ if a == b['name'] and b['block'] == 'function':
3392
+ cont = 0
3393
+ break
3394
+ if cont:
3395
+ continue
3396
+ if a not in vars:
3397
+ show(vars)
3398
+ outmess(f'vars2fortran: No definition for argument "{a}".\n')
3399
+ continue
3400
+ if a == block['name']:
3401
+ if block['block'] != 'function' or block.get('result'):
3402
+ # 1) skip declaring a variable that name matches with
3403
+ # subroutine name
3404
+ # 2) skip declaring function when its type is
3405
+ # declared via `result` construction
3406
+ continue
3407
+ if 'typespec' not in vars[a]:
3408
+ if 'attrspec' in vars[a] and 'external' in vars[a]['attrspec']:
3409
+ if a in args:
3410
+ ret = f'{ret}{tab}external {a}'
3411
+ continue
3412
+ show(vars[a])
3413
+ outmess(f'vars2fortran: No typespec for argument "{a}".\n')
3414
+ continue
3415
+ vardef = vars[a]['typespec']
3416
+ if vardef == 'type' and 'typename' in vars[a]:
3417
+ vardef = f"{vardef}({vars[a]['typename']})"
3418
+ selector = {}
3419
+ if 'kindselector' in vars[a]:
3420
+ selector = vars[a]['kindselector']
3421
+ elif 'charselector' in vars[a]:
3422
+ selector = vars[a]['charselector']
3423
+ if '*' in selector:
3424
+ if selector['*'] in ['*', ':']:
3425
+ vardef = f"{vardef}*({selector['*']})"
3426
+ else:
3427
+ vardef = f"{vardef}*{selector['*']}"
3428
+ elif 'len' in selector:
3429
+ vardef = f"{vardef}(len={selector['len']}"
3430
+ if 'kind' in selector:
3431
+ vardef = f"{vardef},kind={selector['kind']})"
3432
+ else:
3433
+ vardef = f'{vardef})'
3434
+ elif 'kind' in selector:
3435
+ vardef = f"{vardef}(kind={selector['kind']})"
3436
+ c = ' '
3437
+ if 'attrspec' in vars[a]:
3438
+ attr = [l for l in vars[a]['attrspec']
3439
+ if l not in ['external']]
3440
+ if as_interface and 'intent(in)' in attr and 'intent(out)' in attr:
3441
+ # In Fortran, intent(in, out) are conflicting while
3442
+ # intent(in, out) can be specified only via
3443
+ # `!f2py intent(out) ..`.
3444
+ # So, for the Fortran interface, we'll drop
3445
+ # intent(out) to resolve the conflict.
3446
+ attr.remove('intent(out)')
3447
+ if attr:
3448
+ vardef = f"{vardef}, {','.join(attr)}"
3449
+ c = ','
3450
+ if 'dimension' in vars[a]:
3451
+ vardef = f"{vardef}{c}dimension({','.join(vars[a]['dimension'])})"
3452
+ c = ','
3453
+ if 'intent' in vars[a]:
3454
+ lst = true_intent_list(vars[a])
3455
+ if lst:
3456
+ vardef = f"{vardef}{c}intent({','.join(lst)})"
3457
+ c = ','
3458
+ if 'check' in vars[a]:
3459
+ vardef = f"{vardef}{c}check({','.join(vars[a]['check'])})"
3460
+ c = ','
3461
+ if 'depend' in vars[a]:
3462
+ vardef = f"{vardef}{c}depend({','.join(vars[a]['depend'])})"
3463
+ c = ','
3464
+ if '=' in vars[a]:
3465
+ v = vars[a]['=']
3466
+ if vars[a]['typespec'] in ['complex', 'double complex']:
3467
+ try:
3468
+ v = eval(v)
3469
+ v = f'({v.real},{v.imag})'
3470
+ except Exception:
3471
+ pass
3472
+ vardef = f'{vardef} :: {a}={v}'
3473
+ else:
3474
+ vardef = f'{vardef} :: {a}'
3475
+ ret = f'{ret}{tab}{vardef}'
3476
+ return ret
3477
+ ######
3478
+
3479
+
3480
+ # We expose post_processing_hooks as global variable so that
3481
+ # user-libraries could register their own hooks to f2py.
3482
+ post_processing_hooks = []
3483
+
3484
+
3485
+ def crackfortran(files):
3486
+ global usermodules, post_processing_hooks
3487
+
3488
+ outmess('Reading fortran codes...\n', 0)
3489
+ readfortrancode(files, crackline)
3490
+ outmess('Post-processing...\n', 0)
3491
+ usermodules = []
3492
+ postlist = postcrack(grouplist[0])
3493
+ outmess('Applying post-processing hooks...\n', 0)
3494
+ for hook in post_processing_hooks:
3495
+ outmess(f' {hook.__name__}\n', 0)
3496
+ postlist = traverse(postlist, hook)
3497
+ outmess('Post-processing (stage 2)...\n', 0)
3498
+ postlist = postcrack2(postlist)
3499
+ return usermodules + postlist
3500
+
3501
+
3502
+ def crack2fortran(block):
3503
+ global f2py_version
3504
+
3505
+ pyf = crack2fortrangen(block) + '\n'
3506
+ header = """! -*- f90 -*-
3507
+ ! Note: the context of this file is case sensitive.
3508
+ """
3509
+ footer = """
3510
+ ! This file was auto-generated with f2py (version:%s).
3511
+ ! See:
3512
+ ! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e
3513
+ """ % (f2py_version)
3514
+ return header + pyf + footer
3515
+
3516
+
3517
+ def _is_visit_pair(obj):
3518
+ return (isinstance(obj, tuple)
3519
+ and len(obj) == 2
3520
+ and isinstance(obj[0], (int, str)))
3521
+
3522
+
3523
+ def traverse(obj, visit, parents=[], result=None, *args, **kwargs):
3524
+ '''Traverse f2py data structure with the following visit function:
3525
+
3526
+ def visit(item, parents, result, *args, **kwargs):
3527
+ """
3528
+
3529
+ parents is a list of key-"f2py data structure" pairs from which
3530
+ items are taken from.
3531
+
3532
+ result is a f2py data structure that is filled with the
3533
+ return value of the visit function.
3534
+
3535
+ item is 2-tuple (index, value) if parents[-1][1] is a list
3536
+ item is 2-tuple (key, value) if parents[-1][1] is a dict
3537
+
3538
+ The return value of visit must be None, or of the same kind as
3539
+ item, that is, if parents[-1] is a list, the return value must
3540
+ be 2-tuple (new_index, new_value), or if parents[-1] is a
3541
+ dict, the return value must be 2-tuple (new_key, new_value).
3542
+
3543
+ If new_index or new_value is None, the return value of visit
3544
+ is ignored, that is, it will not be added to the result.
3545
+
3546
+ If the return value is None, the content of obj will be
3547
+ traversed, otherwise not.
3548
+ """
3549
+ '''
3550
+
3551
+ if _is_visit_pair(obj):
3552
+ if obj[0] == 'parent_block':
3553
+ # avoid infinite recursion
3554
+ return obj
3555
+ new_result = visit(obj, parents, result, *args, **kwargs)
3556
+ if new_result is not None:
3557
+ assert _is_visit_pair(new_result)
3558
+ return new_result
3559
+ parent = obj
3560
+ result_key, obj = obj
3561
+ else:
3562
+ parent = (None, obj)
3563
+ result_key = None
3564
+
3565
+ if isinstance(obj, list):
3566
+ new_result = []
3567
+ for index, value in enumerate(obj):
3568
+ new_index, new_item = traverse((index, value), visit,
3569
+ parents + [parent], result,
3570
+ *args, **kwargs)
3571
+ if new_index is not None:
3572
+ new_result.append(new_item)
3573
+ elif isinstance(obj, dict):
3574
+ new_result = {}
3575
+ for key, value in obj.items():
3576
+ new_key, new_value = traverse((key, value), visit,
3577
+ parents + [parent], result,
3578
+ *args, **kwargs)
3579
+ if new_key is not None:
3580
+ new_result[new_key] = new_value
3581
+ else:
3582
+ new_result = obj
3583
+
3584
+ if result_key is None:
3585
+ return new_result
3586
+ return result_key, new_result
3587
+
3588
+
3589
+ def character_backward_compatibility_hook(item, parents, result,
3590
+ *args, **kwargs):
3591
+ """Previously, Fortran character was incorrectly treated as
3592
+ character*1. This hook fixes the usage of the corresponding
3593
+ variables in `check`, `dimension`, `=`, and `callstatement`
3594
+ expressions.
3595
+
3596
+ The usage of `char*` in `callprotoargument` expression can be left
3597
+ unchanged because C `character` is C typedef of `char`, although,
3598
+ new implementations should use `character*` in the corresponding
3599
+ expressions.
3600
+
3601
+ See https://github.com/numpy/numpy/pull/19388 for more information.
3602
+
3603
+ """
3604
+ parent_key, parent_value = parents[-1]
3605
+ key, value = item
3606
+
3607
+ def fix_usage(varname, value):
3608
+ value = re.sub(r'[*]\s*\b' + varname + r'\b', varname, value)
3609
+ value = re.sub(r'\b' + varname + r'\b\s*[\[]\s*0\s*[\]]',
3610
+ varname, value)
3611
+ return value
3612
+
3613
+ if parent_key in ['dimension', 'check']:
3614
+ assert parents[-3][0] == 'vars'
3615
+ vars_dict = parents[-3][1]
3616
+ elif key == '=':
3617
+ assert parents[-2][0] == 'vars'
3618
+ vars_dict = parents[-2][1]
3619
+ else:
3620
+ vars_dict = None
3621
+
3622
+ new_value = None
3623
+ if vars_dict is not None:
3624
+ new_value = value
3625
+ for varname, vd in vars_dict.items():
3626
+ if ischaracter(vd):
3627
+ new_value = fix_usage(varname, new_value)
3628
+ elif key == 'callstatement':
3629
+ vars_dict = parents[-2][1]['vars']
3630
+ new_value = value
3631
+ for varname, vd in vars_dict.items():
3632
+ if ischaracter(vd):
3633
+ # replace all occurrences of `<varname>` with
3634
+ # `&<varname>` in argument passing
3635
+ new_value = re.sub(
3636
+ r'(?<![&])\b' + varname + r'\b', '&' + varname, new_value)
3637
+
3638
+ if new_value is not None:
3639
+ if new_value != value:
3640
+ # We report the replacements here so that downstream
3641
+ # software could update their source codes
3642
+ # accordingly. However, such updates are recommended only
3643
+ # when BC with numpy 1.21 or older is not required.
3644
+ outmess(f'character_bc_hook[{parent_key}.{key}]:'
3645
+ f' replaced `{value}` -> `{new_value}`\n', 1)
3646
+ return (key, new_value)
3647
+
3648
+
3649
+ post_processing_hooks.append(character_backward_compatibility_hook)
3650
+
3651
+
3652
+ if __name__ == "__main__":
3653
+ files = []
3654
+ funcs = []
3655
+ f = 1
3656
+ f2 = 0
3657
+ f3 = 0
3658
+ showblocklist = 0
3659
+ for l in sys.argv[1:]:
3660
+ if l == '':
3661
+ pass
3662
+ elif l[0] == ':':
3663
+ f = 0
3664
+ elif l == '-quiet':
3665
+ quiet = 1
3666
+ verbose = 0
3667
+ elif l == '-verbose':
3668
+ verbose = 2
3669
+ quiet = 0
3670
+ elif l == '-fix':
3671
+ if strictf77:
3672
+ outmess(
3673
+ 'Use option -f90 before -fix if Fortran 90 code is in fix form.\n', 0)
3674
+ skipemptyends = 1
3675
+ sourcecodeform = 'fix'
3676
+ elif l == '-skipemptyends':
3677
+ skipemptyends = 1
3678
+ elif l == '--ignore-contains':
3679
+ ignorecontains = 1
3680
+ elif l == '-f77':
3681
+ strictf77 = 1
3682
+ sourcecodeform = 'fix'
3683
+ elif l == '-f90':
3684
+ strictf77 = 0
3685
+ sourcecodeform = 'free'
3686
+ skipemptyends = 1
3687
+ elif l == '-h':
3688
+ f2 = 1
3689
+ elif l == '-show':
3690
+ showblocklist = 1
3691
+ elif l == '-m':
3692
+ f3 = 1
3693
+ elif l[0] == '-':
3694
+ errmess(f'Unknown option {repr(l)}\n')
3695
+ elif f2:
3696
+ f2 = 0
3697
+ pyffilename = l
3698
+ elif f3:
3699
+ f3 = 0
3700
+ f77modulename = l
3701
+ elif f:
3702
+ try:
3703
+ open(l).close()
3704
+ files.append(l)
3705
+ except OSError as detail:
3706
+ errmess(f'OSError: {detail!s}\n')
3707
+ else:
3708
+ funcs.append(l)
3709
+ if not strictf77 and f77modulename and not skipemptyends:
3710
+ outmess("""\
3711
+ Warning: You have specified module name for non Fortran 77 code that
3712
+ should not need one (expect if you are scanning F90 code for non
3713
+ module blocks but then you should use flag -skipemptyends and also
3714
+ be sure that the files do not contain programs without program
3715
+ statement).
3716
+ """, 0)
3717
+
3718
+ postlist = crackfortran(files)
3719
+ if pyffilename:
3720
+ outmess(f'Writing fortran code to file {repr(pyffilename)}\n', 0)
3721
+ pyf = crack2fortran(postlist)
3722
+ with open(pyffilename, 'w') as f:
3723
+ f.write(pyf)
3724
+ if showblocklist:
3725
+ show(postlist)