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.
- numpy/__config__.py +170 -0
- numpy/__config__.pyi +108 -0
- numpy/__init__.cython-30.pxd +1242 -0
- numpy/__init__.pxd +1155 -0
- numpy/__init__.py +942 -0
- numpy/__init__.pyi +6202 -0
- numpy/_array_api_info.py +346 -0
- numpy/_array_api_info.pyi +206 -0
- numpy/_configtool.py +39 -0
- numpy/_configtool.pyi +1 -0
- numpy/_core/__init__.py +201 -0
- numpy/_core/__init__.pyi +666 -0
- numpy/_core/_add_newdocs.py +7151 -0
- numpy/_core/_add_newdocs.pyi +2 -0
- numpy/_core/_add_newdocs_scalars.py +381 -0
- numpy/_core/_add_newdocs_scalars.pyi +16 -0
- numpy/_core/_asarray.py +130 -0
- numpy/_core/_asarray.pyi +43 -0
- numpy/_core/_dtype.py +366 -0
- numpy/_core/_dtype.pyi +56 -0
- numpy/_core/_dtype_ctypes.py +120 -0
- numpy/_core/_dtype_ctypes.pyi +83 -0
- numpy/_core/_exceptions.py +162 -0
- numpy/_core/_exceptions.pyi +54 -0
- numpy/_core/_internal.py +968 -0
- numpy/_core/_internal.pyi +61 -0
- numpy/_core/_methods.py +252 -0
- numpy/_core/_methods.pyi +22 -0
- numpy/_core/_multiarray_tests.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_multiarray_umath.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_operand_flag_tests.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_rational_tests.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_simd.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_simd.pyi +35 -0
- numpy/_core/_string_helpers.py +100 -0
- numpy/_core/_string_helpers.pyi +12 -0
- numpy/_core/_struct_ufunc_tests.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_type_aliases.py +131 -0
- numpy/_core/_type_aliases.pyi +86 -0
- numpy/_core/_ufunc_config.py +515 -0
- numpy/_core/_ufunc_config.pyi +69 -0
- numpy/_core/_umath_tests.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/_core/_umath_tests.pyi +47 -0
- numpy/_core/arrayprint.py +1779 -0
- numpy/_core/arrayprint.pyi +158 -0
- numpy/_core/cversions.py +13 -0
- numpy/_core/defchararray.py +1414 -0
- numpy/_core/defchararray.pyi +1150 -0
- numpy/_core/einsumfunc.py +1650 -0
- numpy/_core/einsumfunc.pyi +184 -0
- numpy/_core/fromnumeric.py +4233 -0
- numpy/_core/fromnumeric.pyi +1735 -0
- numpy/_core/function_base.py +547 -0
- numpy/_core/function_base.pyi +276 -0
- numpy/_core/getlimits.py +462 -0
- numpy/_core/getlimits.pyi +124 -0
- numpy/_core/include/numpy/__multiarray_api.c +376 -0
- numpy/_core/include/numpy/__multiarray_api.h +1628 -0
- numpy/_core/include/numpy/__ufunc_api.c +55 -0
- numpy/_core/include/numpy/__ufunc_api.h +349 -0
- numpy/_core/include/numpy/_neighborhood_iterator_imp.h +90 -0
- numpy/_core/include/numpy/_numpyconfig.h +33 -0
- numpy/_core/include/numpy/_public_dtype_api_table.h +86 -0
- numpy/_core/include/numpy/arrayobject.h +7 -0
- numpy/_core/include/numpy/arrayscalars.h +198 -0
- numpy/_core/include/numpy/dtype_api.h +547 -0
- numpy/_core/include/numpy/halffloat.h +70 -0
- numpy/_core/include/numpy/ndarrayobject.h +304 -0
- numpy/_core/include/numpy/ndarraytypes.h +1982 -0
- numpy/_core/include/numpy/npy_2_compat.h +249 -0
- numpy/_core/include/numpy/npy_2_complexcompat.h +28 -0
- numpy/_core/include/numpy/npy_3kcompat.h +374 -0
- numpy/_core/include/numpy/npy_common.h +989 -0
- numpy/_core/include/numpy/npy_cpu.h +126 -0
- numpy/_core/include/numpy/npy_endian.h +79 -0
- numpy/_core/include/numpy/npy_math.h +602 -0
- numpy/_core/include/numpy/npy_no_deprecated_api.h +20 -0
- numpy/_core/include/numpy/npy_os.h +42 -0
- numpy/_core/include/numpy/numpyconfig.h +185 -0
- numpy/_core/include/numpy/random/LICENSE.txt +21 -0
- numpy/_core/include/numpy/random/bitgen.h +20 -0
- numpy/_core/include/numpy/random/distributions.h +209 -0
- numpy/_core/include/numpy/random/libdivide.h +2079 -0
- numpy/_core/include/numpy/ufuncobject.h +343 -0
- numpy/_core/include/numpy/utils.h +37 -0
- numpy/_core/lib/libnpymath.a +0 -0
- numpy/_core/lib/npy-pkg-config/mlib.ini +12 -0
- numpy/_core/lib/npy-pkg-config/npymath.ini +20 -0
- numpy/_core/lib/pkgconfig/numpy.pc +7 -0
- numpy/_core/memmap.py +363 -0
- numpy/_core/memmap.pyi +3 -0
- numpy/_core/multiarray.py +1740 -0
- numpy/_core/multiarray.pyi +1316 -0
- numpy/_core/numeric.py +2758 -0
- numpy/_core/numeric.pyi +1276 -0
- numpy/_core/numerictypes.py +633 -0
- numpy/_core/numerictypes.pyi +196 -0
- numpy/_core/overrides.py +188 -0
- numpy/_core/overrides.pyi +47 -0
- numpy/_core/printoptions.py +32 -0
- numpy/_core/printoptions.pyi +28 -0
- numpy/_core/records.py +1088 -0
- numpy/_core/records.pyi +340 -0
- numpy/_core/shape_base.py +996 -0
- numpy/_core/shape_base.pyi +182 -0
- numpy/_core/strings.py +1813 -0
- numpy/_core/strings.pyi +536 -0
- numpy/_core/tests/_locales.py +72 -0
- numpy/_core/tests/_natype.py +144 -0
- numpy/_core/tests/data/astype_copy.pkl +0 -0
- numpy/_core/tests/data/generate_umath_validation_data.cpp +170 -0
- numpy/_core/tests/data/recarray_from_file.fits +0 -0
- numpy/_core/tests/data/umath-validation-set-README.txt +15 -0
- numpy/_core/tests/data/umath-validation-set-arccos.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-arccosh.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-arcsin.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-arcsinh.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-arctan.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-arctanh.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-cbrt.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-cos.csv +1375 -0
- numpy/_core/tests/data/umath-validation-set-cosh.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-exp.csv +412 -0
- numpy/_core/tests/data/umath-validation-set-exp2.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-expm1.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-log.csv +271 -0
- numpy/_core/tests/data/umath-validation-set-log10.csv +1629 -0
- numpy/_core/tests/data/umath-validation-set-log1p.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-log2.csv +1629 -0
- numpy/_core/tests/data/umath-validation-set-sin.csv +1370 -0
- numpy/_core/tests/data/umath-validation-set-sinh.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-tan.csv +1429 -0
- numpy/_core/tests/data/umath-validation-set-tanh.csv +1429 -0
- numpy/_core/tests/examples/cython/checks.pyx +373 -0
- numpy/_core/tests/examples/cython/meson.build +43 -0
- numpy/_core/tests/examples/cython/setup.py +39 -0
- numpy/_core/tests/examples/limited_api/limited_api1.c +17 -0
- numpy/_core/tests/examples/limited_api/limited_api2.pyx +11 -0
- numpy/_core/tests/examples/limited_api/limited_api_latest.c +19 -0
- numpy/_core/tests/examples/limited_api/meson.build +59 -0
- numpy/_core/tests/examples/limited_api/setup.py +24 -0
- numpy/_core/tests/test__exceptions.py +90 -0
- numpy/_core/tests/test_abc.py +54 -0
- numpy/_core/tests/test_api.py +655 -0
- numpy/_core/tests/test_argparse.py +90 -0
- numpy/_core/tests/test_array_api_info.py +113 -0
- numpy/_core/tests/test_array_coercion.py +928 -0
- numpy/_core/tests/test_array_interface.py +222 -0
- numpy/_core/tests/test_arraymethod.py +84 -0
- numpy/_core/tests/test_arrayobject.py +75 -0
- numpy/_core/tests/test_arrayprint.py +1324 -0
- numpy/_core/tests/test_casting_floatingpoint_errors.py +154 -0
- numpy/_core/tests/test_casting_unittests.py +955 -0
- numpy/_core/tests/test_conversion_utils.py +209 -0
- numpy/_core/tests/test_cpu_dispatcher.py +48 -0
- numpy/_core/tests/test_cpu_features.py +450 -0
- numpy/_core/tests/test_custom_dtypes.py +393 -0
- numpy/_core/tests/test_cython.py +352 -0
- numpy/_core/tests/test_datetime.py +2792 -0
- numpy/_core/tests/test_defchararray.py +858 -0
- numpy/_core/tests/test_deprecations.py +460 -0
- numpy/_core/tests/test_dlpack.py +190 -0
- numpy/_core/tests/test_dtype.py +2110 -0
- numpy/_core/tests/test_einsum.py +1351 -0
- numpy/_core/tests/test_errstate.py +131 -0
- numpy/_core/tests/test_extint128.py +217 -0
- numpy/_core/tests/test_finfo.py +86 -0
- numpy/_core/tests/test_function_base.py +504 -0
- numpy/_core/tests/test_getlimits.py +171 -0
- numpy/_core/tests/test_half.py +593 -0
- numpy/_core/tests/test_hashtable.py +36 -0
- numpy/_core/tests/test_indexerrors.py +122 -0
- numpy/_core/tests/test_indexing.py +1692 -0
- numpy/_core/tests/test_item_selection.py +167 -0
- numpy/_core/tests/test_limited_api.py +102 -0
- numpy/_core/tests/test_longdouble.py +370 -0
- numpy/_core/tests/test_mem_overlap.py +933 -0
- numpy/_core/tests/test_mem_policy.py +453 -0
- numpy/_core/tests/test_memmap.py +248 -0
- numpy/_core/tests/test_multiarray.py +11008 -0
- numpy/_core/tests/test_multiprocessing.py +55 -0
- numpy/_core/tests/test_multithreading.py +353 -0
- numpy/_core/tests/test_nditer.py +3533 -0
- numpy/_core/tests/test_nep50_promotions.py +287 -0
- numpy/_core/tests/test_numeric.py +4295 -0
- numpy/_core/tests/test_numerictypes.py +650 -0
- numpy/_core/tests/test_overrides.py +800 -0
- numpy/_core/tests/test_print.py +202 -0
- numpy/_core/tests/test_protocols.py +46 -0
- numpy/_core/tests/test_records.py +544 -0
- numpy/_core/tests/test_regression.py +2677 -0
- numpy/_core/tests/test_scalar_ctors.py +203 -0
- numpy/_core/tests/test_scalar_methods.py +328 -0
- numpy/_core/tests/test_scalarbuffer.py +153 -0
- numpy/_core/tests/test_scalarinherit.py +105 -0
- numpy/_core/tests/test_scalarmath.py +1168 -0
- numpy/_core/tests/test_scalarprint.py +403 -0
- numpy/_core/tests/test_shape_base.py +904 -0
- numpy/_core/tests/test_simd.py +1345 -0
- numpy/_core/tests/test_simd_module.py +105 -0
- numpy/_core/tests/test_stringdtype.py +1855 -0
- numpy/_core/tests/test_strings.py +1515 -0
- numpy/_core/tests/test_ufunc.py +3405 -0
- numpy/_core/tests/test_umath.py +4962 -0
- numpy/_core/tests/test_umath_accuracy.py +132 -0
- numpy/_core/tests/test_umath_complex.py +631 -0
- numpy/_core/tests/test_unicode.py +369 -0
- numpy/_core/umath.py +60 -0
- numpy/_core/umath.pyi +232 -0
- numpy/_distributor_init.py +15 -0
- numpy/_distributor_init.pyi +1 -0
- numpy/_expired_attrs_2_0.py +78 -0
- numpy/_expired_attrs_2_0.pyi +61 -0
- numpy/_globals.py +121 -0
- numpy/_globals.pyi +17 -0
- numpy/_pyinstaller/__init__.py +0 -0
- numpy/_pyinstaller/__init__.pyi +0 -0
- numpy/_pyinstaller/hook-numpy.py +36 -0
- numpy/_pyinstaller/hook-numpy.pyi +6 -0
- numpy/_pyinstaller/tests/__init__.py +16 -0
- numpy/_pyinstaller/tests/pyinstaller-smoke.py +32 -0
- numpy/_pyinstaller/tests/test_pyinstaller.py +35 -0
- numpy/_pytesttester.py +201 -0
- numpy/_pytesttester.pyi +18 -0
- numpy/_typing/__init__.py +173 -0
- numpy/_typing/_add_docstring.py +153 -0
- numpy/_typing/_array_like.py +106 -0
- numpy/_typing/_char_codes.py +213 -0
- numpy/_typing/_dtype_like.py +114 -0
- numpy/_typing/_extended_precision.py +15 -0
- numpy/_typing/_nbit.py +19 -0
- numpy/_typing/_nbit_base.py +94 -0
- numpy/_typing/_nbit_base.pyi +39 -0
- numpy/_typing/_nested_sequence.py +79 -0
- numpy/_typing/_scalars.py +20 -0
- numpy/_typing/_shape.py +8 -0
- numpy/_typing/_ufunc.py +7 -0
- numpy/_typing/_ufunc.pyi +975 -0
- numpy/_utils/__init__.py +95 -0
- numpy/_utils/__init__.pyi +28 -0
- numpy/_utils/_convertions.py +18 -0
- numpy/_utils/_convertions.pyi +4 -0
- numpy/_utils/_inspect.py +192 -0
- numpy/_utils/_inspect.pyi +70 -0
- numpy/_utils/_pep440.py +486 -0
- numpy/_utils/_pep440.pyi +118 -0
- numpy/char/__init__.py +2 -0
- numpy/char/__init__.pyi +111 -0
- numpy/conftest.py +248 -0
- numpy/core/__init__.py +33 -0
- numpy/core/__init__.pyi +0 -0
- numpy/core/_dtype.py +10 -0
- numpy/core/_dtype.pyi +0 -0
- numpy/core/_dtype_ctypes.py +10 -0
- numpy/core/_dtype_ctypes.pyi +0 -0
- numpy/core/_internal.py +27 -0
- numpy/core/_multiarray_umath.py +57 -0
- numpy/core/_utils.py +21 -0
- numpy/core/arrayprint.py +10 -0
- numpy/core/defchararray.py +10 -0
- numpy/core/einsumfunc.py +10 -0
- numpy/core/fromnumeric.py +10 -0
- numpy/core/function_base.py +10 -0
- numpy/core/getlimits.py +10 -0
- numpy/core/multiarray.py +25 -0
- numpy/core/numeric.py +12 -0
- numpy/core/numerictypes.py +10 -0
- numpy/core/overrides.py +10 -0
- numpy/core/overrides.pyi +7 -0
- numpy/core/records.py +10 -0
- numpy/core/shape_base.py +10 -0
- numpy/core/umath.py +10 -0
- numpy/ctypeslib/__init__.py +13 -0
- numpy/ctypeslib/__init__.pyi +15 -0
- numpy/ctypeslib/_ctypeslib.py +603 -0
- numpy/ctypeslib/_ctypeslib.pyi +236 -0
- numpy/doc/ufuncs.py +138 -0
- numpy/dtypes.py +41 -0
- numpy/dtypes.pyi +630 -0
- numpy/exceptions.py +246 -0
- numpy/exceptions.pyi +27 -0
- numpy/f2py/__init__.py +86 -0
- numpy/f2py/__init__.pyi +5 -0
- numpy/f2py/__main__.py +5 -0
- numpy/f2py/__version__.py +1 -0
- numpy/f2py/__version__.pyi +1 -0
- numpy/f2py/_backends/__init__.py +9 -0
- numpy/f2py/_backends/__init__.pyi +5 -0
- numpy/f2py/_backends/_backend.py +44 -0
- numpy/f2py/_backends/_backend.pyi +46 -0
- numpy/f2py/_backends/_distutils.py +76 -0
- numpy/f2py/_backends/_distutils.pyi +13 -0
- numpy/f2py/_backends/_meson.py +244 -0
- numpy/f2py/_backends/_meson.pyi +62 -0
- numpy/f2py/_backends/meson.build.template +58 -0
- numpy/f2py/_isocbind.py +62 -0
- numpy/f2py/_isocbind.pyi +13 -0
- numpy/f2py/_src_pyf.py +247 -0
- numpy/f2py/_src_pyf.pyi +28 -0
- numpy/f2py/auxfuncs.py +1004 -0
- numpy/f2py/auxfuncs.pyi +262 -0
- numpy/f2py/capi_maps.py +811 -0
- numpy/f2py/capi_maps.pyi +33 -0
- numpy/f2py/cb_rules.py +665 -0
- numpy/f2py/cb_rules.pyi +17 -0
- numpy/f2py/cfuncs.py +1563 -0
- numpy/f2py/cfuncs.pyi +31 -0
- numpy/f2py/common_rules.py +143 -0
- numpy/f2py/common_rules.pyi +9 -0
- numpy/f2py/crackfortran.py +3725 -0
- numpy/f2py/crackfortran.pyi +266 -0
- numpy/f2py/diagnose.py +149 -0
- numpy/f2py/diagnose.pyi +1 -0
- numpy/f2py/f2py2e.py +788 -0
- numpy/f2py/f2py2e.pyi +74 -0
- numpy/f2py/f90mod_rules.py +269 -0
- numpy/f2py/f90mod_rules.pyi +16 -0
- numpy/f2py/func2subr.py +329 -0
- numpy/f2py/func2subr.pyi +7 -0
- numpy/f2py/rules.py +1629 -0
- numpy/f2py/rules.pyi +41 -0
- numpy/f2py/setup.cfg +3 -0
- numpy/f2py/src/fortranobject.c +1436 -0
- numpy/f2py/src/fortranobject.h +173 -0
- numpy/f2py/symbolic.py +1518 -0
- numpy/f2py/symbolic.pyi +219 -0
- numpy/f2py/tests/__init__.py +16 -0
- numpy/f2py/tests/src/abstract_interface/foo.f90 +34 -0
- numpy/f2py/tests/src/abstract_interface/gh18403_mod.f90 +6 -0
- numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c +235 -0
- numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap +1 -0
- numpy/f2py/tests/src/assumed_shape/foo_free.f90 +34 -0
- numpy/f2py/tests/src/assumed_shape/foo_mod.f90 +41 -0
- numpy/f2py/tests/src/assumed_shape/foo_use.f90 +19 -0
- numpy/f2py/tests/src/assumed_shape/precision.f90 +4 -0
- numpy/f2py/tests/src/block_docstring/foo.f +6 -0
- numpy/f2py/tests/src/callback/foo.f +62 -0
- numpy/f2py/tests/src/callback/gh17797.f90 +7 -0
- numpy/f2py/tests/src/callback/gh18335.f90 +17 -0
- numpy/f2py/tests/src/callback/gh25211.f +10 -0
- numpy/f2py/tests/src/callback/gh25211.pyf +18 -0
- numpy/f2py/tests/src/callback/gh26681.f90 +18 -0
- numpy/f2py/tests/src/cli/gh_22819.pyf +6 -0
- numpy/f2py/tests/src/cli/hi77.f +3 -0
- numpy/f2py/tests/src/cli/hiworld.f90 +3 -0
- numpy/f2py/tests/src/common/block.f +11 -0
- numpy/f2py/tests/src/common/gh19161.f90 +10 -0
- numpy/f2py/tests/src/crackfortran/accesstype.f90 +13 -0
- numpy/f2py/tests/src/crackfortran/common_with_division.f +17 -0
- numpy/f2py/tests/src/crackfortran/data_common.f +8 -0
- numpy/f2py/tests/src/crackfortran/data_multiplier.f +5 -0
- numpy/f2py/tests/src/crackfortran/data_stmts.f90 +20 -0
- numpy/f2py/tests/src/crackfortran/data_with_comments.f +8 -0
- numpy/f2py/tests/src/crackfortran/foo_deps.f90 +6 -0
- numpy/f2py/tests/src/crackfortran/gh15035.f +16 -0
- numpy/f2py/tests/src/crackfortran/gh17859.f +12 -0
- numpy/f2py/tests/src/crackfortran/gh22648.pyf +7 -0
- numpy/f2py/tests/src/crackfortran/gh23533.f +5 -0
- numpy/f2py/tests/src/crackfortran/gh23598.f90 +4 -0
- numpy/f2py/tests/src/crackfortran/gh23598Warn.f90 +11 -0
- numpy/f2py/tests/src/crackfortran/gh23879.f90 +20 -0
- numpy/f2py/tests/src/crackfortran/gh27697.f90 +12 -0
- numpy/f2py/tests/src/crackfortran/gh2848.f90 +13 -0
- numpy/f2py/tests/src/crackfortran/operators.f90 +49 -0
- numpy/f2py/tests/src/crackfortran/privatemod.f90 +11 -0
- numpy/f2py/tests/src/crackfortran/publicmod.f90 +10 -0
- numpy/f2py/tests/src/crackfortran/pubprivmod.f90 +10 -0
- numpy/f2py/tests/src/crackfortran/unicode_comment.f90 +4 -0
- numpy/f2py/tests/src/f2cmap/.f2py_f2cmap +1 -0
- numpy/f2py/tests/src/f2cmap/isoFortranEnvMap.f90 +9 -0
- numpy/f2py/tests/src/isocintrin/isoCtests.f90 +34 -0
- numpy/f2py/tests/src/kind/foo.f90 +20 -0
- numpy/f2py/tests/src/mixed/foo.f +5 -0
- numpy/f2py/tests/src/mixed/foo_fixed.f90 +8 -0
- numpy/f2py/tests/src/mixed/foo_free.f90 +8 -0
- numpy/f2py/tests/src/modules/gh25337/data.f90 +8 -0
- numpy/f2py/tests/src/modules/gh25337/use_data.f90 +6 -0
- numpy/f2py/tests/src/modules/gh26920/two_mods_with_no_public_entities.f90 +21 -0
- numpy/f2py/tests/src/modules/gh26920/two_mods_with_one_public_routine.f90 +21 -0
- numpy/f2py/tests/src/modules/module_data_docstring.f90 +12 -0
- numpy/f2py/tests/src/modules/use_modules.f90 +20 -0
- numpy/f2py/tests/src/negative_bounds/issue_20853.f90 +7 -0
- numpy/f2py/tests/src/parameter/constant_array.f90 +45 -0
- numpy/f2py/tests/src/parameter/constant_both.f90 +57 -0
- numpy/f2py/tests/src/parameter/constant_compound.f90 +15 -0
- numpy/f2py/tests/src/parameter/constant_integer.f90 +22 -0
- numpy/f2py/tests/src/parameter/constant_non_compound.f90 +23 -0
- numpy/f2py/tests/src/parameter/constant_real.f90 +23 -0
- numpy/f2py/tests/src/quoted_character/foo.f +14 -0
- numpy/f2py/tests/src/regression/AB.inc +1 -0
- numpy/f2py/tests/src/regression/assignOnlyModule.f90 +25 -0
- numpy/f2py/tests/src/regression/datonly.f90 +17 -0
- numpy/f2py/tests/src/regression/f77comments.f +26 -0
- numpy/f2py/tests/src/regression/f77fixedform.f95 +5 -0
- numpy/f2py/tests/src/regression/f90continuation.f90 +9 -0
- numpy/f2py/tests/src/regression/incfile.f90 +5 -0
- numpy/f2py/tests/src/regression/inout.f90 +9 -0
- numpy/f2py/tests/src/regression/lower_f2py_fortran.f90 +5 -0
- numpy/f2py/tests/src/regression/mod_derived_types.f90 +23 -0
- numpy/f2py/tests/src/return_character/foo77.f +45 -0
- numpy/f2py/tests/src/return_character/foo90.f90 +48 -0
- numpy/f2py/tests/src/return_complex/foo77.f +45 -0
- numpy/f2py/tests/src/return_complex/foo90.f90 +48 -0
- numpy/f2py/tests/src/return_integer/foo77.f +56 -0
- numpy/f2py/tests/src/return_integer/foo90.f90 +59 -0
- numpy/f2py/tests/src/return_logical/foo77.f +56 -0
- numpy/f2py/tests/src/return_logical/foo90.f90 +59 -0
- numpy/f2py/tests/src/return_real/foo77.f +45 -0
- numpy/f2py/tests/src/return_real/foo90.f90 +48 -0
- numpy/f2py/tests/src/routines/funcfortranname.f +5 -0
- numpy/f2py/tests/src/routines/funcfortranname.pyf +11 -0
- numpy/f2py/tests/src/routines/subrout.f +4 -0
- numpy/f2py/tests/src/routines/subrout.pyf +10 -0
- numpy/f2py/tests/src/size/foo.f90 +44 -0
- numpy/f2py/tests/src/string/char.f90 +29 -0
- numpy/f2py/tests/src/string/fixed_string.f90 +34 -0
- numpy/f2py/tests/src/string/gh24008.f +8 -0
- numpy/f2py/tests/src/string/gh24662.f90 +7 -0
- numpy/f2py/tests/src/string/gh25286.f90 +14 -0
- numpy/f2py/tests/src/string/gh25286.pyf +12 -0
- numpy/f2py/tests/src/string/gh25286_bc.pyf +12 -0
- numpy/f2py/tests/src/string/scalar_string.f90 +9 -0
- numpy/f2py/tests/src/string/string.f +12 -0
- numpy/f2py/tests/src/value_attrspec/gh21665.f90 +9 -0
- numpy/f2py/tests/test_abstract_interface.py +26 -0
- numpy/f2py/tests/test_array_from_pyobj.py +678 -0
- numpy/f2py/tests/test_assumed_shape.py +50 -0
- numpy/f2py/tests/test_block_docstring.py +20 -0
- numpy/f2py/tests/test_callback.py +263 -0
- numpy/f2py/tests/test_character.py +641 -0
- numpy/f2py/tests/test_common.py +23 -0
- numpy/f2py/tests/test_crackfortran.py +421 -0
- numpy/f2py/tests/test_data.py +71 -0
- numpy/f2py/tests/test_docs.py +66 -0
- numpy/f2py/tests/test_f2cmap.py +17 -0
- numpy/f2py/tests/test_f2py2e.py +983 -0
- numpy/f2py/tests/test_isoc.py +56 -0
- numpy/f2py/tests/test_kind.py +52 -0
- numpy/f2py/tests/test_mixed.py +35 -0
- numpy/f2py/tests/test_modules.py +83 -0
- numpy/f2py/tests/test_parameter.py +129 -0
- numpy/f2py/tests/test_pyf_src.py +43 -0
- numpy/f2py/tests/test_quoted_character.py +18 -0
- numpy/f2py/tests/test_regression.py +187 -0
- numpy/f2py/tests/test_return_character.py +48 -0
- numpy/f2py/tests/test_return_complex.py +67 -0
- numpy/f2py/tests/test_return_integer.py +55 -0
- numpy/f2py/tests/test_return_logical.py +65 -0
- numpy/f2py/tests/test_return_real.py +109 -0
- numpy/f2py/tests/test_routines.py +29 -0
- numpy/f2py/tests/test_semicolon_split.py +75 -0
- numpy/f2py/tests/test_size.py +45 -0
- numpy/f2py/tests/test_string.py +100 -0
- numpy/f2py/tests/test_symbolic.py +500 -0
- numpy/f2py/tests/test_value_attrspec.py +15 -0
- numpy/f2py/tests/util.py +442 -0
- numpy/f2py/use_rules.py +99 -0
- numpy/f2py/use_rules.pyi +9 -0
- numpy/fft/__init__.py +213 -0
- numpy/fft/__init__.pyi +38 -0
- numpy/fft/_helper.py +235 -0
- numpy/fft/_helper.pyi +44 -0
- numpy/fft/_pocketfft.py +1693 -0
- numpy/fft/_pocketfft.pyi +137 -0
- numpy/fft/_pocketfft_umath.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/fft/tests/__init__.py +0 -0
- numpy/fft/tests/test_helper.py +167 -0
- numpy/fft/tests/test_pocketfft.py +589 -0
- numpy/lib/__init__.py +97 -0
- numpy/lib/__init__.pyi +52 -0
- numpy/lib/_array_utils_impl.py +62 -0
- numpy/lib/_array_utils_impl.pyi +10 -0
- numpy/lib/_arraypad_impl.py +926 -0
- numpy/lib/_arraypad_impl.pyi +88 -0
- numpy/lib/_arraysetops_impl.py +1158 -0
- numpy/lib/_arraysetops_impl.pyi +462 -0
- numpy/lib/_arrayterator_impl.py +224 -0
- numpy/lib/_arrayterator_impl.pyi +45 -0
- numpy/lib/_datasource.py +700 -0
- numpy/lib/_datasource.pyi +30 -0
- numpy/lib/_format_impl.py +1036 -0
- numpy/lib/_format_impl.pyi +56 -0
- numpy/lib/_function_base_impl.py +5758 -0
- numpy/lib/_function_base_impl.pyi +2324 -0
- numpy/lib/_histograms_impl.py +1085 -0
- numpy/lib/_histograms_impl.pyi +40 -0
- numpy/lib/_index_tricks_impl.py +1048 -0
- numpy/lib/_index_tricks_impl.pyi +267 -0
- numpy/lib/_iotools.py +900 -0
- numpy/lib/_iotools.pyi +116 -0
- numpy/lib/_nanfunctions_impl.py +2001 -0
- numpy/lib/_nanfunctions_impl.pyi +48 -0
- numpy/lib/_npyio_impl.py +2583 -0
- numpy/lib/_npyio_impl.pyi +299 -0
- numpy/lib/_polynomial_impl.py +1465 -0
- numpy/lib/_polynomial_impl.pyi +338 -0
- numpy/lib/_scimath_impl.py +642 -0
- numpy/lib/_scimath_impl.pyi +93 -0
- numpy/lib/_shape_base_impl.py +1289 -0
- numpy/lib/_shape_base_impl.pyi +236 -0
- numpy/lib/_stride_tricks_impl.py +582 -0
- numpy/lib/_stride_tricks_impl.pyi +73 -0
- numpy/lib/_twodim_base_impl.py +1201 -0
- numpy/lib/_twodim_base_impl.pyi +408 -0
- numpy/lib/_type_check_impl.py +710 -0
- numpy/lib/_type_check_impl.pyi +348 -0
- numpy/lib/_ufunclike_impl.py +199 -0
- numpy/lib/_ufunclike_impl.pyi +60 -0
- numpy/lib/_user_array_impl.py +310 -0
- numpy/lib/_user_array_impl.pyi +226 -0
- numpy/lib/_utils_impl.py +784 -0
- numpy/lib/_utils_impl.pyi +22 -0
- numpy/lib/_version.py +153 -0
- numpy/lib/_version.pyi +17 -0
- numpy/lib/array_utils.py +7 -0
- numpy/lib/array_utils.pyi +6 -0
- numpy/lib/format.py +24 -0
- numpy/lib/format.pyi +24 -0
- numpy/lib/introspect.py +94 -0
- numpy/lib/introspect.pyi +3 -0
- numpy/lib/mixins.py +180 -0
- numpy/lib/mixins.pyi +78 -0
- numpy/lib/npyio.py +1 -0
- numpy/lib/npyio.pyi +5 -0
- numpy/lib/recfunctions.py +1681 -0
- numpy/lib/recfunctions.pyi +444 -0
- numpy/lib/scimath.py +13 -0
- numpy/lib/scimath.pyi +12 -0
- numpy/lib/stride_tricks.py +1 -0
- numpy/lib/stride_tricks.pyi +4 -0
- numpy/lib/tests/__init__.py +0 -0
- numpy/lib/tests/data/py2-np0-objarr.npy +0 -0
- numpy/lib/tests/data/py2-objarr.npy +0 -0
- numpy/lib/tests/data/py2-objarr.npz +0 -0
- numpy/lib/tests/data/py3-objarr.npy +0 -0
- numpy/lib/tests/data/py3-objarr.npz +0 -0
- numpy/lib/tests/data/python3.npy +0 -0
- numpy/lib/tests/data/win64python2.npy +0 -0
- numpy/lib/tests/test__datasource.py +328 -0
- numpy/lib/tests/test__iotools.py +358 -0
- numpy/lib/tests/test__version.py +64 -0
- numpy/lib/tests/test_array_utils.py +32 -0
- numpy/lib/tests/test_arraypad.py +1427 -0
- numpy/lib/tests/test_arraysetops.py +1302 -0
- numpy/lib/tests/test_arrayterator.py +45 -0
- numpy/lib/tests/test_format.py +1054 -0
- numpy/lib/tests/test_function_base.py +4705 -0
- numpy/lib/tests/test_histograms.py +855 -0
- numpy/lib/tests/test_index_tricks.py +693 -0
- numpy/lib/tests/test_io.py +2857 -0
- numpy/lib/tests/test_loadtxt.py +1099 -0
- numpy/lib/tests/test_mixins.py +215 -0
- numpy/lib/tests/test_nanfunctions.py +1438 -0
- numpy/lib/tests/test_packbits.py +376 -0
- numpy/lib/tests/test_polynomial.py +325 -0
- numpy/lib/tests/test_recfunctions.py +1042 -0
- numpy/lib/tests/test_regression.py +231 -0
- numpy/lib/tests/test_shape_base.py +813 -0
- numpy/lib/tests/test_stride_tricks.py +655 -0
- numpy/lib/tests/test_twodim_base.py +559 -0
- numpy/lib/tests/test_type_check.py +473 -0
- numpy/lib/tests/test_ufunclike.py +97 -0
- numpy/lib/tests/test_utils.py +80 -0
- numpy/lib/user_array.py +1 -0
- numpy/lib/user_array.pyi +1 -0
- numpy/linalg/__init__.py +95 -0
- numpy/linalg/__init__.pyi +71 -0
- numpy/linalg/_linalg.py +3657 -0
- numpy/linalg/_linalg.pyi +548 -0
- numpy/linalg/_umath_linalg.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/linalg/_umath_linalg.pyi +60 -0
- numpy/linalg/lapack_lite.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/linalg/lapack_lite.pyi +143 -0
- numpy/linalg/tests/__init__.py +0 -0
- numpy/linalg/tests/test_deprecations.py +21 -0
- numpy/linalg/tests/test_linalg.py +2442 -0
- numpy/linalg/tests/test_regression.py +182 -0
- numpy/ma/API_CHANGES.txt +135 -0
- numpy/ma/LICENSE +24 -0
- numpy/ma/README.rst +236 -0
- numpy/ma/__init__.py +53 -0
- numpy/ma/__init__.pyi +458 -0
- numpy/ma/core.py +8929 -0
- numpy/ma/core.pyi +3720 -0
- numpy/ma/extras.py +2266 -0
- numpy/ma/extras.pyi +297 -0
- numpy/ma/mrecords.py +762 -0
- numpy/ma/mrecords.pyi +96 -0
- numpy/ma/tests/__init__.py +0 -0
- numpy/ma/tests/test_arrayobject.py +40 -0
- numpy/ma/tests/test_core.py +6008 -0
- numpy/ma/tests/test_deprecations.py +65 -0
- numpy/ma/tests/test_extras.py +1945 -0
- numpy/ma/tests/test_mrecords.py +495 -0
- numpy/ma/tests/test_old_ma.py +939 -0
- numpy/ma/tests/test_regression.py +83 -0
- numpy/ma/tests/test_subclassing.py +469 -0
- numpy/ma/testutils.py +294 -0
- numpy/ma/testutils.pyi +69 -0
- numpy/matlib.py +380 -0
- numpy/matlib.pyi +580 -0
- numpy/matrixlib/__init__.py +12 -0
- numpy/matrixlib/__init__.pyi +3 -0
- numpy/matrixlib/defmatrix.py +1119 -0
- numpy/matrixlib/defmatrix.pyi +218 -0
- numpy/matrixlib/tests/__init__.py +0 -0
- numpy/matrixlib/tests/test_defmatrix.py +455 -0
- numpy/matrixlib/tests/test_interaction.py +360 -0
- numpy/matrixlib/tests/test_masked_matrix.py +240 -0
- numpy/matrixlib/tests/test_matrix_linalg.py +110 -0
- numpy/matrixlib/tests/test_multiarray.py +17 -0
- numpy/matrixlib/tests/test_numeric.py +18 -0
- numpy/matrixlib/tests/test_regression.py +31 -0
- numpy/polynomial/__init__.py +187 -0
- numpy/polynomial/__init__.pyi +31 -0
- numpy/polynomial/_polybase.py +1191 -0
- numpy/polynomial/_polybase.pyi +262 -0
- numpy/polynomial/_polytypes.pyi +501 -0
- numpy/polynomial/chebyshev.py +2001 -0
- numpy/polynomial/chebyshev.pyi +180 -0
- numpy/polynomial/hermite.py +1738 -0
- numpy/polynomial/hermite.pyi +106 -0
- numpy/polynomial/hermite_e.py +1640 -0
- numpy/polynomial/hermite_e.pyi +106 -0
- numpy/polynomial/laguerre.py +1673 -0
- numpy/polynomial/laguerre.pyi +100 -0
- numpy/polynomial/legendre.py +1603 -0
- numpy/polynomial/legendre.pyi +100 -0
- numpy/polynomial/polynomial.py +1625 -0
- numpy/polynomial/polynomial.pyi +109 -0
- numpy/polynomial/polyutils.py +759 -0
- numpy/polynomial/polyutils.pyi +307 -0
- numpy/polynomial/tests/__init__.py +0 -0
- numpy/polynomial/tests/test_chebyshev.py +618 -0
- numpy/polynomial/tests/test_classes.py +613 -0
- numpy/polynomial/tests/test_hermite.py +553 -0
- numpy/polynomial/tests/test_hermite_e.py +554 -0
- numpy/polynomial/tests/test_laguerre.py +535 -0
- numpy/polynomial/tests/test_legendre.py +566 -0
- numpy/polynomial/tests/test_polynomial.py +691 -0
- numpy/polynomial/tests/test_polyutils.py +123 -0
- numpy/polynomial/tests/test_printing.py +557 -0
- numpy/polynomial/tests/test_symbol.py +217 -0
- numpy/py.typed +0 -0
- numpy/random/LICENSE.md +71 -0
- numpy/random/__init__.pxd +14 -0
- numpy/random/__init__.py +213 -0
- numpy/random/__init__.pyi +124 -0
- numpy/random/_bounded_integers.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_bounded_integers.pxd +29 -0
- numpy/random/_bounded_integers.pyi +1 -0
- numpy/random/_common.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_common.pxd +107 -0
- numpy/random/_common.pyi +16 -0
- numpy/random/_examples/cffi/extending.py +44 -0
- numpy/random/_examples/cffi/parse.py +53 -0
- numpy/random/_examples/cython/extending.pyx +77 -0
- numpy/random/_examples/cython/extending_distributions.pyx +117 -0
- numpy/random/_examples/cython/meson.build +53 -0
- numpy/random/_examples/numba/extending.py +86 -0
- numpy/random/_examples/numba/extending_distributions.py +67 -0
- numpy/random/_generator.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_generator.pyi +862 -0
- numpy/random/_mt19937.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_mt19937.pyi +27 -0
- numpy/random/_pcg64.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_pcg64.pyi +41 -0
- numpy/random/_philox.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_philox.pyi +36 -0
- numpy/random/_pickle.py +88 -0
- numpy/random/_pickle.pyi +43 -0
- numpy/random/_sfc64.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/_sfc64.pyi +25 -0
- numpy/random/bit_generator.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/bit_generator.pxd +35 -0
- numpy/random/bit_generator.pyi +123 -0
- numpy/random/c_distributions.pxd +119 -0
- numpy/random/lib/libnpyrandom.a +0 -0
- numpy/random/mtrand.cpython-313t-aarch64-linux-musl.so +0 -0
- numpy/random/mtrand.pyi +759 -0
- numpy/random/tests/__init__.py +0 -0
- numpy/random/tests/data/__init__.py +0 -0
- numpy/random/tests/data/generator_pcg64_np121.pkl.gz +0 -0
- numpy/random/tests/data/generator_pcg64_np126.pkl.gz +0 -0
- numpy/random/tests/data/mt19937-testset-1.csv +1001 -0
- numpy/random/tests/data/mt19937-testset-2.csv +1001 -0
- numpy/random/tests/data/pcg64-testset-1.csv +1001 -0
- numpy/random/tests/data/pcg64-testset-2.csv +1001 -0
- numpy/random/tests/data/pcg64dxsm-testset-1.csv +1001 -0
- numpy/random/tests/data/pcg64dxsm-testset-2.csv +1001 -0
- numpy/random/tests/data/philox-testset-1.csv +1001 -0
- numpy/random/tests/data/philox-testset-2.csv +1001 -0
- numpy/random/tests/data/sfc64-testset-1.csv +1001 -0
- numpy/random/tests/data/sfc64-testset-2.csv +1001 -0
- numpy/random/tests/data/sfc64_np126.pkl.gz +0 -0
- numpy/random/tests/test_direct.py +595 -0
- numpy/random/tests/test_extending.py +131 -0
- numpy/random/tests/test_generator_mt19937.py +2825 -0
- numpy/random/tests/test_generator_mt19937_regressions.py +221 -0
- numpy/random/tests/test_random.py +1724 -0
- numpy/random/tests/test_randomstate.py +2099 -0
- numpy/random/tests/test_randomstate_regression.py +213 -0
- numpy/random/tests/test_regression.py +175 -0
- numpy/random/tests/test_seed_sequence.py +79 -0
- numpy/random/tests/test_smoke.py +882 -0
- numpy/rec/__init__.py +2 -0
- numpy/rec/__init__.pyi +23 -0
- numpy/strings/__init__.py +2 -0
- numpy/strings/__init__.pyi +97 -0
- numpy/testing/__init__.py +22 -0
- numpy/testing/__init__.pyi +107 -0
- numpy/testing/_private/__init__.py +0 -0
- numpy/testing/_private/__init__.pyi +0 -0
- numpy/testing/_private/extbuild.py +250 -0
- numpy/testing/_private/extbuild.pyi +25 -0
- numpy/testing/_private/utils.py +2830 -0
- numpy/testing/_private/utils.pyi +505 -0
- numpy/testing/overrides.py +84 -0
- numpy/testing/overrides.pyi +10 -0
- numpy/testing/print_coercion_tables.py +207 -0
- numpy/testing/print_coercion_tables.pyi +26 -0
- numpy/testing/tests/__init__.py +0 -0
- numpy/testing/tests/test_utils.py +2123 -0
- numpy/tests/__init__.py +0 -0
- numpy/tests/test__all__.py +10 -0
- numpy/tests/test_configtool.py +51 -0
- numpy/tests/test_ctypeslib.py +383 -0
- numpy/tests/test_lazyloading.py +42 -0
- numpy/tests/test_matlib.py +59 -0
- numpy/tests/test_numpy_config.py +47 -0
- numpy/tests/test_numpy_version.py +54 -0
- numpy/tests/test_public_api.py +804 -0
- numpy/tests/test_reloading.py +76 -0
- numpy/tests/test_scripts.py +48 -0
- numpy/tests/test_warnings.py +79 -0
- numpy/typing/__init__.py +233 -0
- numpy/typing/__init__.pyi +3 -0
- numpy/typing/mypy_plugin.py +200 -0
- numpy/typing/tests/__init__.py +0 -0
- numpy/typing/tests/data/fail/arithmetic.pyi +126 -0
- numpy/typing/tests/data/fail/array_constructors.pyi +34 -0
- numpy/typing/tests/data/fail/array_like.pyi +15 -0
- numpy/typing/tests/data/fail/array_pad.pyi +6 -0
- numpy/typing/tests/data/fail/arrayprint.pyi +15 -0
- numpy/typing/tests/data/fail/arrayterator.pyi +14 -0
- numpy/typing/tests/data/fail/bitwise_ops.pyi +17 -0
- numpy/typing/tests/data/fail/char.pyi +63 -0
- numpy/typing/tests/data/fail/chararray.pyi +61 -0
- numpy/typing/tests/data/fail/comparisons.pyi +27 -0
- numpy/typing/tests/data/fail/constants.pyi +3 -0
- numpy/typing/tests/data/fail/datasource.pyi +16 -0
- numpy/typing/tests/data/fail/dtype.pyi +17 -0
- numpy/typing/tests/data/fail/einsumfunc.pyi +12 -0
- numpy/typing/tests/data/fail/flatiter.pyi +38 -0
- numpy/typing/tests/data/fail/fromnumeric.pyi +148 -0
- numpy/typing/tests/data/fail/histograms.pyi +12 -0
- numpy/typing/tests/data/fail/index_tricks.pyi +14 -0
- numpy/typing/tests/data/fail/lib_function_base.pyi +60 -0
- numpy/typing/tests/data/fail/lib_polynomial.pyi +29 -0
- numpy/typing/tests/data/fail/lib_utils.pyi +3 -0
- numpy/typing/tests/data/fail/lib_version.pyi +6 -0
- numpy/typing/tests/data/fail/linalg.pyi +52 -0
- numpy/typing/tests/data/fail/ma.pyi +155 -0
- numpy/typing/tests/data/fail/memmap.pyi +5 -0
- numpy/typing/tests/data/fail/modules.pyi +17 -0
- numpy/typing/tests/data/fail/multiarray.pyi +52 -0
- numpy/typing/tests/data/fail/ndarray.pyi +11 -0
- numpy/typing/tests/data/fail/ndarray_misc.pyi +49 -0
- numpy/typing/tests/data/fail/nditer.pyi +8 -0
- numpy/typing/tests/data/fail/nested_sequence.pyi +17 -0
- numpy/typing/tests/data/fail/npyio.pyi +24 -0
- numpy/typing/tests/data/fail/numerictypes.pyi +5 -0
- numpy/typing/tests/data/fail/random.pyi +62 -0
- numpy/typing/tests/data/fail/rec.pyi +17 -0
- numpy/typing/tests/data/fail/scalars.pyi +86 -0
- numpy/typing/tests/data/fail/shape.pyi +7 -0
- numpy/typing/tests/data/fail/shape_base.pyi +8 -0
- numpy/typing/tests/data/fail/stride_tricks.pyi +9 -0
- numpy/typing/tests/data/fail/strings.pyi +52 -0
- numpy/typing/tests/data/fail/testing.pyi +28 -0
- numpy/typing/tests/data/fail/twodim_base.pyi +39 -0
- numpy/typing/tests/data/fail/type_check.pyi +12 -0
- numpy/typing/tests/data/fail/ufunc_config.pyi +21 -0
- numpy/typing/tests/data/fail/ufunclike.pyi +21 -0
- numpy/typing/tests/data/fail/ufuncs.pyi +17 -0
- numpy/typing/tests/data/fail/warnings_and_errors.pyi +5 -0
- numpy/typing/tests/data/misc/extended_precision.pyi +9 -0
- numpy/typing/tests/data/mypy.ini +8 -0
- numpy/typing/tests/data/pass/arithmetic.py +614 -0
- numpy/typing/tests/data/pass/array_constructors.py +138 -0
- numpy/typing/tests/data/pass/array_like.py +43 -0
- numpy/typing/tests/data/pass/arrayprint.py +37 -0
- numpy/typing/tests/data/pass/arrayterator.py +28 -0
- numpy/typing/tests/data/pass/bitwise_ops.py +131 -0
- numpy/typing/tests/data/pass/comparisons.py +316 -0
- numpy/typing/tests/data/pass/dtype.py +57 -0
- numpy/typing/tests/data/pass/einsumfunc.py +36 -0
- numpy/typing/tests/data/pass/flatiter.py +26 -0
- numpy/typing/tests/data/pass/fromnumeric.py +272 -0
- numpy/typing/tests/data/pass/index_tricks.py +62 -0
- numpy/typing/tests/data/pass/lib_user_array.py +22 -0
- numpy/typing/tests/data/pass/lib_utils.py +19 -0
- numpy/typing/tests/data/pass/lib_version.py +18 -0
- numpy/typing/tests/data/pass/literal.py +52 -0
- numpy/typing/tests/data/pass/ma.py +199 -0
- numpy/typing/tests/data/pass/mod.py +149 -0
- numpy/typing/tests/data/pass/modules.py +45 -0
- numpy/typing/tests/data/pass/multiarray.py +77 -0
- numpy/typing/tests/data/pass/ndarray_conversion.py +81 -0
- numpy/typing/tests/data/pass/ndarray_misc.py +199 -0
- numpy/typing/tests/data/pass/ndarray_shape_manipulation.py +47 -0
- numpy/typing/tests/data/pass/nditer.py +4 -0
- numpy/typing/tests/data/pass/numeric.py +90 -0
- numpy/typing/tests/data/pass/numerictypes.py +17 -0
- numpy/typing/tests/data/pass/random.py +1498 -0
- numpy/typing/tests/data/pass/recfunctions.py +164 -0
- numpy/typing/tests/data/pass/scalars.py +249 -0
- numpy/typing/tests/data/pass/shape.py +19 -0
- numpy/typing/tests/data/pass/simple.py +170 -0
- numpy/typing/tests/data/pass/ufunc_config.py +64 -0
- numpy/typing/tests/data/pass/ufunclike.py +52 -0
- numpy/typing/tests/data/pass/ufuncs.py +16 -0
- numpy/typing/tests/data/pass/warnings_and_errors.py +6 -0
- numpy/typing/tests/data/reveal/arithmetic.pyi +719 -0
- numpy/typing/tests/data/reveal/array_api_info.pyi +70 -0
- numpy/typing/tests/data/reveal/array_constructors.pyi +277 -0
- numpy/typing/tests/data/reveal/arraypad.pyi +27 -0
- numpy/typing/tests/data/reveal/arrayprint.pyi +25 -0
- numpy/typing/tests/data/reveal/arraysetops.pyi +74 -0
- numpy/typing/tests/data/reveal/arrayterator.pyi +27 -0
- numpy/typing/tests/data/reveal/bitwise_ops.pyi +166 -0
- numpy/typing/tests/data/reveal/char.pyi +225 -0
- numpy/typing/tests/data/reveal/chararray.pyi +138 -0
- numpy/typing/tests/data/reveal/comparisons.pyi +264 -0
- numpy/typing/tests/data/reveal/constants.pyi +14 -0
- numpy/typing/tests/data/reveal/ctypeslib.pyi +81 -0
- numpy/typing/tests/data/reveal/datasource.pyi +23 -0
- numpy/typing/tests/data/reveal/dtype.pyi +132 -0
- numpy/typing/tests/data/reveal/einsumfunc.pyi +39 -0
- numpy/typing/tests/data/reveal/emath.pyi +54 -0
- numpy/typing/tests/data/reveal/fft.pyi +37 -0
- numpy/typing/tests/data/reveal/flatiter.pyi +86 -0
- numpy/typing/tests/data/reveal/fromnumeric.pyi +347 -0
- numpy/typing/tests/data/reveal/getlimits.pyi +53 -0
- numpy/typing/tests/data/reveal/histograms.pyi +25 -0
- numpy/typing/tests/data/reveal/index_tricks.pyi +70 -0
- numpy/typing/tests/data/reveal/lib_function_base.pyi +409 -0
- numpy/typing/tests/data/reveal/lib_polynomial.pyi +147 -0
- numpy/typing/tests/data/reveal/lib_utils.pyi +17 -0
- numpy/typing/tests/data/reveal/lib_version.pyi +20 -0
- numpy/typing/tests/data/reveal/linalg.pyi +154 -0
- numpy/typing/tests/data/reveal/ma.pyi +1098 -0
- numpy/typing/tests/data/reveal/matrix.pyi +73 -0
- numpy/typing/tests/data/reveal/memmap.pyi +19 -0
- numpy/typing/tests/data/reveal/mod.pyi +178 -0
- numpy/typing/tests/data/reveal/modules.pyi +51 -0
- numpy/typing/tests/data/reveal/multiarray.pyi +197 -0
- numpy/typing/tests/data/reveal/nbit_base_example.pyi +20 -0
- numpy/typing/tests/data/reveal/ndarray_assignability.pyi +82 -0
- numpy/typing/tests/data/reveal/ndarray_conversion.pyi +83 -0
- numpy/typing/tests/data/reveal/ndarray_misc.pyi +246 -0
- numpy/typing/tests/data/reveal/ndarray_shape_manipulation.pyi +47 -0
- numpy/typing/tests/data/reveal/nditer.pyi +49 -0
- numpy/typing/tests/data/reveal/nested_sequence.pyi +25 -0
- numpy/typing/tests/data/reveal/npyio.pyi +83 -0
- numpy/typing/tests/data/reveal/numeric.pyi +170 -0
- numpy/typing/tests/data/reveal/numerictypes.pyi +16 -0
- numpy/typing/tests/data/reveal/polynomial_polybase.pyi +217 -0
- numpy/typing/tests/data/reveal/polynomial_polyutils.pyi +218 -0
- numpy/typing/tests/data/reveal/polynomial_series.pyi +138 -0
- numpy/typing/tests/data/reveal/random.pyi +1546 -0
- numpy/typing/tests/data/reveal/rec.pyi +171 -0
- numpy/typing/tests/data/reveal/scalars.pyi +191 -0
- numpy/typing/tests/data/reveal/shape.pyi +13 -0
- numpy/typing/tests/data/reveal/shape_base.pyi +52 -0
- numpy/typing/tests/data/reveal/stride_tricks.pyi +27 -0
- numpy/typing/tests/data/reveal/strings.pyi +196 -0
- numpy/typing/tests/data/reveal/testing.pyi +198 -0
- numpy/typing/tests/data/reveal/twodim_base.pyi +225 -0
- numpy/typing/tests/data/reveal/type_check.pyi +67 -0
- numpy/typing/tests/data/reveal/ufunc_config.pyi +29 -0
- numpy/typing/tests/data/reveal/ufunclike.pyi +31 -0
- numpy/typing/tests/data/reveal/ufuncs.pyi +142 -0
- numpy/typing/tests/data/reveal/warnings_and_errors.pyi +11 -0
- numpy/typing/tests/test_isfile.py +38 -0
- numpy/typing/tests/test_runtime.py +110 -0
- numpy/typing/tests/test_typing.py +205 -0
- numpy/version.py +11 -0
- numpy/version.pyi +9 -0
- numpy-2.4.0.dist-info/METADATA +139 -0
- numpy-2.4.0.dist-info/RECORD +915 -0
- numpy-2.4.0.dist-info/WHEEL +5 -0
- numpy-2.4.0.dist-info/entry_points.txt +13 -0
- numpy-2.4.0.dist-info/licenses/LICENSE.txt +935 -0
- numpy-2.4.0.dist-info/licenses/numpy/_core/include/numpy/libdivide/LICENSE.txt +21 -0
- numpy-2.4.0.dist-info/licenses/numpy/_core/src/common/pythoncapi-compat/COPYING +14 -0
- numpy-2.4.0.dist-info/licenses/numpy/_core/src/highway/LICENSE +371 -0
- numpy-2.4.0.dist-info/licenses/numpy/_core/src/multiarray/dragon4_LICENSE.txt +27 -0
- numpy-2.4.0.dist-info/licenses/numpy/_core/src/npysort/x86-simd-sort/LICENSE.md +28 -0
- numpy-2.4.0.dist-info/licenses/numpy/_core/src/umath/svml/LICENSE +30 -0
- numpy-2.4.0.dist-info/licenses/numpy/fft/pocketfft/LICENSE.md +25 -0
- numpy-2.4.0.dist-info/licenses/numpy/linalg/lapack_lite/LICENSE.txt +48 -0
- numpy-2.4.0.dist-info/licenses/numpy/ma/LICENSE +24 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/LICENSE.md +71 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/src/distributions/LICENSE.md +61 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/src/mt19937/LICENSE.md +61 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/src/pcg64/LICENSE.md +22 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/src/philox/LICENSE.md +31 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/src/sfc64/LICENSE.md +27 -0
- numpy-2.4.0.dist-info/licenses/numpy/random/src/splitmix64/LICENSE.md +9 -0
- numpy.libs/libgcc_s-2d945d6c-767fb991.so.1 +0 -0
- numpy.libs/libgcc_s-2d945d6c.so.1 +0 -0
- numpy.libs/libgfortran-67378ab2-e7e7cfab.so.5.0.0 +0 -0
- numpy.libs/libscipy_openblas64_-1fc386ee.so +0 -0
- 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)
|