├── .codeclimate.yml
├── .github
├── dependabot.yml
└── workflows
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .pre-commit-hooks.yaml
├── .travis.yml
├── .travis
├── prep_cp2k.sh
├── prep_cron.sh
├── prep_flap.sh
├── prep_regular.sh
├── prep_rosetta.sh
└── prep_wannier90.sh
├── LICENSE
├── MANIFEST.in
├── README.md
├── environment.yml
├── examples
├── example_after.f90
└── example_before.f90
├── fortran_tests
├── after
│ ├── example.f90
│ ├── example_swapcase.f90
│ ├── example_swapcase.f90-enabled
│ ├── test_fypp.f90
│ ├── test_invalid.f90
│ ├── test_namelist_block_select.f90
│ └── where_forall.f90
├── before
│ ├── example.f90
│ ├── example_swapcase.f90
│ ├── test_fypp.f90
│ ├── test_invalid.f90
│ ├── test_namelist_block_select.f90
│ └── where_forall.f90
└── test_results
│ └── expected_results
├── fprettify.py
├── fprettify
├── __init__.py
├── fparse_utils.py
├── tests
│ └── __init__.py
└── version.py
├── hooks.yml
├── pyproject.toml
├── requirements.txt
├── run_tests.py
├── setup.cfg
└── setup.py
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | duplication:
3 | enabled: true
4 | exclude_fingerprints:
5 | - 8f0fa17586b70a9f8b584173ab0c400f
6 | - 2520b12215b2d5a47e145adbeddea955
7 | - 1dfb6bf58fa716f94c029daf456c4fe1
8 | config:
9 | languages:
10 | - python
11 | fixme:
12 | enabled: true
13 | radon:
14 | enabled: true
15 | ratings:
16 | paths:
17 | - "**.py"
18 | exclude_paths: []
19 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
8 | - package-ecosystem: "pip"
9 | directory: "/"
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Checkout repository
13 | uses: actions/checkout@v4
14 |
15 | - name: Setup Python
16 | uses: actions/setup-python@v5
17 | with:
18 | python-version: "3.x"
19 |
20 | - name: Build package
21 | run: |
22 | python -m pip install --upgrade pip
23 | pip install build
24 | python -m build
25 |
26 | - name: Publish to Test PyPi
27 | if: ${{ startsWith(github.ref, 'refs/tags') }}
28 | uses: pypa/gh-action-pypi-publish@master
29 | with:
30 | user: __token__
31 | password: ${{ secrets.TEST_PYPI_API_TOKEN }}
32 | repository_url: https://test.pypi.org/legacy/
33 |
34 | - name: Publish to PyPi
35 | if: ${{ startsWith(github.ref, 'refs/tags') }}
36 | uses: pypa/gh-action-pypi-publish@master
37 | with:
38 | user: __token__
39 | password: ${{ secrets.PYPI_API_TOKEN }}
40 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | pull_request:
6 | schedule:
7 | - cron: "0 0 * * 3"
8 | workflow_dispatch:
9 |
10 | jobs:
11 | resources:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v4
16 |
17 | - name: Create resource cache
18 | id: cache
19 | uses: actions/cache@v4
20 | with:
21 | path: ./fortran_tests/before/*/
22 | key: resources-${{ github.event_name }}
23 |
24 | - name: Prepare tests (default)
25 | if: ${{ steps.cache.outputs.cache-hit != 'true' }}
26 | run: |
27 | .travis/prep_regular.sh
28 |
29 | - name: Prepare tests (schedule)
30 | if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name == 'schedule' }}
31 | run: |
32 | .travis/prep_cron.sh
33 |
34 | pip:
35 | needs:
36 | - resources
37 | runs-on: ${{ matrix.os }}
38 | strategy:
39 | fail-fast: false
40 | matrix:
41 | os: [ubuntu-latest]
42 | python: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"]
43 |
44 | steps:
45 | - name: Checkout code
46 | uses: actions/checkout@v4
47 |
48 | - name: Load resources
49 | uses: actions/cache@v4
50 | with:
51 | path: ./fortran_tests/before/*/
52 | key: resources-${{ github.event_name }}
53 |
54 | - uses: actions/setup-python@v5
55 | with:
56 | python-version: ${{ matrix.python }}
57 |
58 | - name: Install project & dependencies
59 | run: pip install .[dev]
60 |
61 | - name: Run tests
62 | run: |
63 | coverage run --source=fprettify setup.py test
64 |
65 | - name: Coverage upload
66 | run: coveralls --service=github
67 | env:
68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69 | COVERALLS_FLAG_NAME: ${{ matrix.python }}
70 | COVERALLS_PARALLEL: true
71 |
72 | coverage:
73 | needs:
74 | - pip
75 | runs-on: ubuntu-latest
76 |
77 | steps:
78 | - uses: actions/setup-python@v5
79 | with:
80 | python-version: "3.x"
81 |
82 | - name: Install dependencies
83 | run: pip install coveralls
84 |
85 | - name: Coverage upload
86 | run: coveralls --service=github --finish
87 | env:
88 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
89 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .coverage.*
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 | *,cover
46 | .hypothesis/
47 |
48 | # Translations
49 | *.mo
50 | *.pot
51 |
52 | # Django stuff:
53 | *.log
54 | local_settings.py
55 |
56 | # Flask stuff:
57 | instance/
58 | .webassets-cache
59 |
60 | # Scrapy stuff:
61 | .scrapy
62 |
63 | # Sphinx documentation
64 | docs/_build/
65 |
66 | # PyBuilder
67 | target/
68 |
69 | # IPython Notebook
70 | .ipynb_checkpoints
71 |
72 | # pyenv
73 | .python-version
74 |
75 | # celery beat schedule file
76 | celerybeat-schedule
77 |
78 | # dotenv
79 | .env
80 |
81 | # virtualenv
82 | .venv/
83 | venv/
84 | ENV/
85 |
86 | # Spyder project settings
87 | .spyderproject
88 |
89 | # Rope project settings
90 | .ropeproject
91 |
92 | # ctags
93 | tags
94 |
95 | # setuptools_scm autogeneated version
96 | _version.py
97 |
98 | # fortran temporary test files
99 | fortran_tests/
100 |
--------------------------------------------------------------------------------
/.pre-commit-hooks.yaml:
--------------------------------------------------------------------------------
1 | - id: fprettify
2 | name: auto-formatter for modern fortran source code
3 | description: imposes strict whitespace formatting for modern (F90+) Fortran code
4 | entry: fprettify
5 | language: python
6 | files: \.[fF]\d*$
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: xenial # required for Python >= 3.7
2 | language: python
3 | python:
4 | - 3.5
5 | - 3.9
6 | before_install:
7 | - if [[ $TRAVIS_PYTHON_VERSION == "3.9" ]]; then export DO_COVERAGE=1; fi
8 | - if [[ "$TRAVIS_EVENT_TYPE" = "cron" ]]; then unset DO_COVERAGE; fi
9 | install:
10 | - pip install -U -r requirements.txt
11 | - if [[ $DO_COVERAGE ]]; then pip install coveralls; fi
12 | before_script:
13 | - ".travis/prep_regular.sh"
14 | - if [[ "$TRAVIS_EVENT_TYPE" = "cron" ]]; then .travis/prep_cron.sh; fi
15 | script:
16 | - if ! [[ $DO_COVERAGE ]]; then python setup.py test; fi
17 | - if [[ $DO_COVERAGE ]]; then coverage run --source=fprettify setup.py test; fi
18 | after_success:
19 | - if [[ $DO_COVERAGE ]]; then coveralls; fi
20 | deploy:
21 | provider: pypi
22 | user: pseewald
23 | password:
24 | secure: eI+t+10Tzjrkt7gjiBjgTS0xyOAkw5FlUuksHiUVnbI9JDGTxKuA3J9p9JjJKK9gRnljVaqCRhv4UYTxSCTtPlxpCKEFVMHGnjr2nT6IwETTi3R5tvzZzwuReh+jO5CSb9A1hF/iys4cKl+782Bgy6YH4j2jIq60FWFLBCMQiYGza62+jF6U37C5Cmw11DxqJABW4zA1g3y1Y4VQxOXnawPH7Zp6Ag5lk/R/fpthCZo/gnYkQKbkyl7mBng5xn4t6heIGiUnYf8Tqyd46UYYHCBzo2CtR+qkzFd07dtw5Ia3uCOGxfrdaFN+Fpf8gVlMAFq/83eRDa0qSHTO1hY5mbguN1UeVB/LrQNVd82fcBfHncjsSL6/GDiu/VzCW4i7Reh4KQmalBmwReKdC/4yQ+T05OZVtu1W7FyQHJW3Z0jSvpLVttkCSD5kSWvG+pyiEpbUtUsNjr9QosbiA1JhQ+XjhdkqiJU1jZ+oP330EwDnWlD74DgJNQRIQeA2mBMeuJxG87jHwudRetXTK2GW1Idh8YWqbm7pEQ5dGLbGHm1hl0XZ2HEGbYt//fXz47wo3aWX/1wE5e4a88OS8XQ4zMN6PBGAEqRuwQo8WfhfrWGQ8NYFMRwJ0Byo0AeBBj3pYNoGj4Y45+6ETnqkFaxMGbALK+iVr2jEBTbpeOcHJYQ=
25 | distributions: sdist bdist_wheel
26 | on:
27 | tags: true
28 | python: 3.9
29 |
--------------------------------------------------------------------------------
/.travis/prep_cp2k.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | wget https://github.com/pseewald/cp2k/archive/fprettify-test.tar.gz
3 | mkdir fortran_tests/before/cp2k
4 | tar -xf fprettify-test.tar.gz -C fortran_tests/before/cp2k --strip-components=1 cp2k-fprettify-test/src
5 | rm fprettify-test.tar.gz
6 |
--------------------------------------------------------------------------------
/.travis/prep_cron.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | .travis/prep_cp2k.sh
3 |
--------------------------------------------------------------------------------
/.travis/prep_flap.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | wget https://github.com/pseewald/FLAP/archive/fprettify-test.tar.gz
3 | mkdir fortran_tests/before/FLAP && tar -xf fprettify-test.tar.gz -C fortran_tests/before/FLAP --strip-components=1
4 | rm fprettify-test.tar.gz
5 |
--------------------------------------------------------------------------------
/.travis/prep_regular.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | .travis/prep_rosetta.sh
3 | .travis/prep_flap.sh
4 | .travis/prep_wannier90.sh
5 |
--------------------------------------------------------------------------------
/.travis/prep_rosetta.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | wget https://github.com/pseewald/RosettaCodeData/archive/fprettify-test.tar.gz
3 | mkdir fortran_tests/before/RosettaCodeData && tar -xf fprettify-test.tar.gz -C fortran_tests/before/RosettaCodeData --strip-components=1
4 | rm fprettify-test.tar.gz
5 |
--------------------------------------------------------------------------------
/.travis/prep_wannier90.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | wget https://github.com/pseewald/wannier90/archive/fprettify-test.tar.gz
3 | mkdir fortran_tests/before/wannier90 && tar -xf fprettify-test.tar.gz -C fortran_tests/before/wannier90 --strip-components=1
4 | rm fprettify-test.tar.gz
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2016-2019 Patrick Seewald, CP2K developers group
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fprettify
2 |
3 | [](https://github.com/pseewald/fprettify/actions/workflows/test.yml)
4 | [](https://coveralls.io/github/pseewald/fprettify?branch=master)
5 | 
6 | 
7 | [](https://codeclimate.com/github/pseewald/fprettify)
8 |
9 | fprettify is an auto-formatter for modern Fortran code that imposes strict whitespace formatting, written in Python.
10 |
11 | **NOTE:** I'm looking for help to maintain this repository, see [#127](https://github.com/pseewald/fprettify/issues/127).
12 |
13 | ## Features
14 |
15 | - Auto-indentation.
16 | - Line continuations are aligned with the previous opening delimiter `(`, `[` or `(/` or with an assignment operator `=` or `=>`. If none of the above is present, a default hanging indent is applied.
17 | - Consistent amount of whitespace around operators and delimiters.
18 | - Removal of extraneous whitespace and consecutive blank lines.
19 | - Change letter case (upper case / lower case conventions) of intrinsics
20 | - Tested for editor integration.
21 | - By default, fprettify causes whitespace changes only and thus preserves revision history.
22 | - fprettify can handle cpp and [fypp](https://github.com/aradi/fypp) preprocessor directives.
23 |
24 | ## Limitations
25 |
26 | - Works only for modern Fortran (Fortran 90 upwards).
27 | - Feature missing? Please create an issue.
28 |
29 | ## Requirements
30 |
31 | - Python 3 (Python 2.7 no longer supported)
32 | - [ConfigArgParse](https://pypi.org/project/ConfigArgParse): optional, enables use of config file
33 |
34 | ## Examples
35 |
36 | Compare `examples/*before.f90` (original Fortran files) with `examples/*after.f90` (reformatted Fortran files) to see what fprettify does. A quick demonstration:
37 |
38 | ```Fortran
39 | program demo
40 | integer :: endif,if,elseif
41 | integer,DIMENSION(2) :: function
42 | endif=3;if=2
43 | if(endif==2)then
44 | endif=5
45 | elseif=if+4*(endif+&
46 | 2**10)
47 | elseif(endif==3)then
48 | function(if)=endif/elseif
49 | print*,endif
50 | endif
51 | end program
52 | ```
53 |
54 | ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩ `fprettify` ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩
55 |
56 | ```Fortran
57 | program demo
58 | integer :: endif, if, elseif
59 | integer, DIMENSION(2) :: function
60 | endif = 3; if = 2
61 | if (endif == 2) then
62 | endif = 5
63 | elseif = if + 4*(endif + &
64 | 2**10)
65 | elseif (endif == 3) then
66 | function(if) = endif/elseif
67 | print *, endif
68 | endif
69 | end program
70 | ```
71 |
72 | ## Installation
73 |
74 | The latest release can be installed using pip:
75 |
76 | ```sh
77 | pip install --upgrade fprettify
78 | ```
79 |
80 | Installation from source requires Python Setuptools:
81 |
82 | ```sh
83 | pip install .
84 | ```
85 |
86 | For local installation, use `--user` option.
87 |
88 | If you use the [Conda](https://docs.conda.io/) package manager, fprettify is available from the [conda-forge](https://conda-forge.org/) channel:
89 |
90 | ```sh
91 | conda install -c conda-forge fprettify
92 | ```
93 |
94 | ## Command line tool
95 |
96 | Autoformat file1, file2, ... inplace by
97 |
98 | ```sh
99 | fprettify file1, file2, ...
100 | ```
101 |
102 | The default indent is 3. If you prefer something else, use `--indent n` argument.
103 |
104 | In order to apply fprettify recursively to an entire Fortran project instead of a single file, use the `-r` option.
105 |
106 | For more options, read
107 |
108 | ```sh
109 | fprettify -h
110 | ```
111 |
112 | ## Editor integration
113 |
114 | For editor integration, use
115 |
116 | ```sh
117 | fprettify --silent
118 | ```
119 |
120 | For instance, with Vim, use fprettify with `gq` by putting the following commands in your `.vimrc`:
121 |
122 | ```vim
123 | autocmd Filetype fortran setlocal formatprg=fprettify\ --silent
124 | ```
125 |
126 | ## Deactivation and manual formatting (experimental feature)
127 |
128 | fprettify can be deactivated for selected lines: a single line followed by an inline comment starting with `!&` is not auto-formatted and consecutive lines that are enclosed between two comment lines `!&<` and `!&>` are not auto-formatted. This is useful for cases where manual alignment is preferred over auto-formatting. Furthermore, deactivation is necessary when non-standard Fortran syntax (such as advanced usage of preprocessor directives) prevents proper formatting. As an example, consider the following snippet of fprettify formatted code:
129 |
130 | ```fortran
131 | A = [-1, 10, 0, &
132 | 0, 1000, 0, &
133 | 0, -1, 1]
134 | ```
135 |
136 | In order to manually align the columns, fprettify needs to be deactivated by
137 |
138 | ```fortran
139 | A = [-1, 10, 0, & !&
140 | 0, 1000, 0, & !&
141 | 0, -1, 1] !&
142 | ```
143 |
144 | or, equivalently by
145 |
146 | ```fortran
147 | !&<
148 | A = [-1, 10, 0, &
149 | 0, 1000, 0, &
150 | 0, -1, 1]
151 | !&>
152 | ```
153 |
154 | ## Contributing / Testing
155 |
156 | The testing mechanism allows you to easily test fprettify with any Fortran project of your choice. Simply clone or copy your entire project into `fortran_tests/before` and run `python setup.py test`. The directory `fortran_tests/after` contains the test output (reformatted Fortran files). If testing fails, please submit an issue!
157 |
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | name: devel
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - configargparse
6 | - importlib-metadata
7 |
--------------------------------------------------------------------------------
/examples/example_after.f90:
--------------------------------------------------------------------------------
1 | ../fortran_tests/after/example.f90
--------------------------------------------------------------------------------
/examples/example_before.f90:
--------------------------------------------------------------------------------
1 | ../fortran_tests/before/example.f90
--------------------------------------------------------------------------------
/fortran_tests/after/example.f90:
--------------------------------------------------------------------------------
1 | module example
2 | implicit none
3 | private
4 | public :: dp, test_routine, &
5 | test_function, test_type, str_function
6 | integer, parameter :: dp = selected_real_kind(15, 307)
7 | type test_type
8 | real(kind=dp) :: r = 1.0d-3
9 | integer :: i
10 | end type test_type
11 |
12 | contains
13 |
14 | subroutine test_routine( &
15 | r, i, j, k, l)
16 | integer, intent(in) :: r, i, j, k
17 | integer, intent(out) :: l
18 |
19 | l = test_function(r, i, j, k)
20 | end &
21 | subroutine
22 |
23 | pure function test_function(r, i, j, &
24 | k) &
25 | result(l)
26 | integer, intent(in) :: r, i, j, k
27 | integer :: l
28 |
29 | l = r + i + j + k
30 | end function
31 | function &
32 | str_function(a) result(l)
33 | character(len=*) :: a
34 | integer :: l
35 |
36 | if (len(a) < 5) then
37 | l = 0
38 | else
39 | l = 1
40 | end if
41 | end function
42 |
43 | end module
44 |
45 | program example_prog
46 | use example, only: dp, test_routine, test_function, test_type, str_function
47 |
48 | implicit none
49 | integer :: r, i, j, k, l, my_integer, m
50 | integer, dimension(5) :: arr
51 | integer, dimension(20) :: big_arr
52 | integer :: endif
53 | type(test_type) :: t
54 | real(kind=dp) :: r1, r2, r3, r4, r5, r6
55 | integer, pointer :: point
56 |
57 | point => null()
58 |
59 | ! 1) white space formatting !
60 | !***************************!
61 | ! example 1.1
62 | r = 1; i = -2; j = 3; k = 4; l = 5
63 | r2 = 0.0_dp; r3 = 1.0_dp; r4 = 2.0_dp; r5 = 3.0_dp; r6 = 4.0_dp
64 | r1 = -(r2**i*(r3 + r5*(-r4) - r6)) - 2.e+2
65 | if (r .eq. 2 .and. r <= 5) i = 3
66 | write (*, *) (merge(3, 1, i <= 2))
67 | write (*, *) test_function(r, i, j, k)
68 | t%r = 4.0_dp
69 | t%i = str_function("t % i = ")
70 |
71 | ! example 1.2
72 | my_integer = 2
73 | i = 3
74 | j = 5
75 |
76 | big_arr = [1, 2, 3, 4, 5, &
77 | 6, 7, 8, 9, 10, &
78 | 11, 12, 13, 14, 15, &
79 | 16, 17, 18, 19, 20]
80 |
81 | ! example 1.3: disabling auto-formatter:
82 | my_integer = 2 !&
83 | i = 3 !&
84 | j = 5 !&
85 |
86 | !&<
87 | my_integer = 2
88 | i = 3
89 | j = 5
90 | !&>
91 |
92 | big_arr = [ 1, 2, 3, 4, 5, & !&
93 | 6, 7, 8, 9, 10, & !&
94 | 11, 12, 13, 14, 15, & !&
95 | 16, 17, 18, 19, 20] !&
96 |
97 | ! example 1.4:
98 |
99 | big_arr = [1, 2, 3, 4, 5,&
100 | & 6, 7, 8, 9, 10, &
101 | & 11, 12, 13, 14, 15,&
102 | &16, 17, 18, 19, 20]
103 |
104 | ! 2) auto indentation for loops !
105 | !*******************************!
106 |
107 | ! example 2.1
108 | l = 0
109 | do r = 1, 10
110 | select case (r)
111 | case (1)
112 | do_label: do i = 1, 100
113 | if (i <= 2) then
114 | m = 0
115 | do while (m < 4)
116 | m = m + 1
117 | do k = 1, 3
118 | if (k == 1) l = l + 1
119 | end do
120 | end do
121 | end if
122 | end do do_label
123 | case (2)
124 | l = i + j + k
125 | end select
126 | end do
127 |
128 | ! example 2.2
129 | do m = 1, 2
130 | do r = 1, 3
131 | write (*, *) r
132 | do k = 1, 4
133 | do l = 1, 3
134 | do i = 4, 5
135 | do my_integer = 1, 1
136 | do j = 1, 2
137 | write (*, *) test_function(m, r, k, l) + i
138 | end do
139 | end do
140 | end do
141 | end do
142 | end do
143 | end do
144 | end do
145 |
146 | ! 3) auto alignment for linebreaks !
147 | !************************************!
148 |
149 | ! example 3.1
150 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + 3*(2 + 1)
151 |
152 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + &
153 | 3*(2 + 1)
154 |
155 | l = test_function(1, 2, &
156 | test_function(1, 2, 3, 4), 4) + &
157 | 3*(2 + 1)
158 |
159 | l = test_function(1, 2, &
160 | test_function(1, 2, 3, &
161 | 4), 4) + &
162 | 3*(2 + 1)
163 |
164 | ! example 3.2
165 | arr = [1, (/3, 4, 5/), 6] + [1, 2, 3, 4, 5]
166 |
167 | arr = [1, (/3, 4, 5/), &
168 | 6] + [1, 2, 3, 4, 5]
169 |
170 | arr = [1, (/3, 4, 5/), &
171 | 6] + &
172 | [1, 2, 3, 4, 5]
173 |
174 | arr = [1, (/3, 4, &
175 | 5/), &
176 | 6] + &
177 | [1, 2, 3, 4, 5]
178 |
179 | ! example 3.3
180 | l = test_function(1, 2, &
181 | 3, 4)
182 |
183 | l = test_function( &
184 | 1, 2, 3, 4)
185 |
186 | arr = [1, 2, &
187 | 3, 4, 5]
188 | arr = [ &
189 | 1, 2, 3, 4, 5]
190 |
191 | ! 4) more complex formatting and tricky test cases !
192 | !**************************************************!
193 |
194 | ! example 4.1
195 | l = 0
196 | do r = 1, 10
197 | select case (r)
198 | case (1)
199 | do i = 1, 100; if (i <= 2) then! comment
200 | do j = 1, 5
201 | do k = 1, 3
202 | l = l + 1
203 | ! unindented comment
204 | ! indented comment
205 | end do; end do
206 | elseif (.not. j == 4) then
207 | my_integer = 4
208 | else
209 | write (*, *) " hello"
210 | end if
211 | end do
212 | case (2)
213 | l = i + j + k
214 | end select
215 | end do
216 |
217 | ! example 4.2
218 | if ( &
219 | l == &
220 | 111) &
221 | then
222 | do k = 1, 2
223 | if (k == 1) &
224 | l = test_function(1, &
225 | test_function(r=4, i=5, &
226 | j=6, k=test_function(1, 2*(3*(1 + 1)), str_function(")a!(b['(;=dfe"), &
227 | 9) + &
228 | test_function(1, 2, 3, 4)), 9, 10) &
229 | ! test_function(1,2,3,4)),9,10) &
230 | ! +13*str_function('') + str_function('"')
231 | + 13*str_function('') + str_function('"')
232 | end & ! comment
233 | ! comment
234 | do
235 | end if
236 |
237 | ! example 4.3
238 | arr = [1, (/3, 4, &
239 | 5/), &
240 | 6] + &
241 | [1, 2, 3, 4, 5]; arr = [1, 2, &
242 | 3, 4, 5]
243 |
244 | ! example 4.4
245 | endif = 3
246 | if (endif == 2) then
247 | endif = 5
248 | else if (endif == 3) then
249 | write (*, *) endif
250 | end if
251 |
252 | ! example 4.5
253 | do i = 1, 2; if (.true.) then
254 | write (*, *) "hello"
255 | end if; end do
256 |
257 | end program
258 |
--------------------------------------------------------------------------------
/fortran_tests/after/example_swapcase.f90:
--------------------------------------------------------------------------------
1 |
2 | MODULE exAmple
3 | IMPLICIT NONE
4 | PRIVATE
5 | PUBLIC :: dp, test_routine, &
6 | test_function, test_type, str_function
7 |
8 | ! Comment, should not change case nor spaces
9 | !!$ INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND ( 15 , 307)
10 | !!$ TYPE test_type
11 | !!$ REAL (kind =dp ) :: r = 1.0d-3
12 | !!$ INTEGER :: i
13 | !!$ END TYPE test_type
14 | !!$
15 | !!$
16 | !!$CONTAINS
17 | !!$
18 | !!$
19 | !!$ SUBROUTINE test_routine( &
20 | !!$ r, i, j, k, l)
21 | !!$ INTEGER, INTENT(in) :: r, i, j, k
22 | !!$ INTEGER, INTENT (out) :: l
23 | !!$
24 | !!$ l = test_function(r,i,j,k)
25 | !!$ END &
26 | !!$SUBROUTINE
27 |
28 | INTEGER, PARAMETER :: SELECTED_REAL_KIND = 1*2
29 | INTEGER, PARAMETER :: dp1 = SELECTED_REAL_KIND(15, 307) ! SELECTED_REAL_KIND ( 15 , 307) !should not change case in comment
30 |
31 | character(len=*), parameter :: a = 'INTEGER, PARAMETER'//'b'!should not change case in string
32 | character(len=*), parameter :: b = "INTEGER, PARAMETER" !should not change case in string
33 | character(len=*), parameter :: c = 'INTEGER, "PARAMETER"' !should not change case in string
34 | character(len=*), parameter :: d = "INTEGER, 'PARAMETER" !should not change case in string
35 |
36 | INTEGER(kind=int64), parameter :: l64 = 2_int64
37 | REAL(kind=real64), parameter :: r64a = 2._real64
38 | REAL(kind=real64), parameter :: r64b = 2.0_real64
39 | REAL(kind=real64), parameter :: r64c = .0_real64
40 | REAL(kind=real64), parameter :: r64a = 2.e3_real64
41 | REAL(kind=real64), parameter :: r64b = 2.0e3_real64
42 | REAL(kind=real64), parameter :: r64c = .0e3_real64
43 |
44 | INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(15, 307)
45 | TYPE test_type
46 | REAL(kind=dp) :: r = 1.0d-3
47 | INTEGER :: i
48 | END TYPE test_type
49 |
50 | CONTAINS
51 |
52 | SUBROUTINE test_routine( &
53 | r, i, j, k, l)
54 | USE iso_fortran_env, only: int64
55 | INTEGER, INTENT(in) :: r, i, j, k
56 | INTEGER, INTENT(out) :: l
57 |
58 | INTEGER(kind=int64) :: l64
59 |
60 | l = test_function(r, i, j, k)
61 |
62 | l64 = 2_int64
63 | IF (l .EQ. 2) l = max(l64, 2_int64)
64 | IF (l .EQ. 2) l = max(l64, 2_int64)
65 | IF (l .EQ. 2) l = max
66 |
67 | END &
68 | SUBROUTINE
69 |
70 | PURE FUNCTION test_function(r, i, j, &
71 | k) &
72 | RESULT(l)
73 | INTEGER, INTENT(in) :: r, i, j, k
74 | INTEGER :: l
75 |
76 | l = r + i + j + k
77 | END FUNCTION
78 | FUNCTION &
79 | str_function(a) RESULT(l)
80 | CHARACTER(len=*) :: a
81 | INTEGER :: l
82 |
83 | IF (LEN(a) < 5) THEN
84 | l = 0
85 | ELSE
86 | l = 1
87 | END IF
88 | END FUNCTION
89 |
90 | END MODULE
91 |
92 | PROGRAM example_prog
93 | USE example, ONLY: dp, test_routine, test_function, test_type, str_function
94 |
95 | IMPLICIT NONE
96 | INTEGER :: r, i, j, k, l, my_integer, m
97 | INTEGER, DIMENSION(5) :: arr
98 | INTEGER, DIMENSION(20) :: big_arr
99 | INTEGER :: ENDIF
100 | TYPE(test_type) :: t
101 | REAL(kind=dp) :: r1, r2, r3, r4, r5, r6
102 | INTEGER, POINTER :: point
103 |
104 | point => NULL()
105 |
106 | ! 1) white space formatting !
107 | !***************************!
108 | ! example 1.1
109 | r = 1; i = -2; j = 3; k = 4; l = 5
110 | r2 = 0.0_dp; r3 = 1.0_dp; r4 = 2.0_dp; r5 = 3.0_dp; r6 = 4.0_dp
111 | r1 = -(r2**i*(r3 + r5*(-r4) - r6)) - 2.e+2
112 | IF (r .EQ. 2 .AND. r <= 5) i = 3
113 | WRITE (*, *) (MERGE(3, 1, i <= 2))
114 | WRITE (*, *) test_function(r, i, j, k)
115 | t%r = 4.0_dp
116 | t%i = str_function("t % i = ")
117 |
118 | ! example 1.2
119 | my_integer = 2
120 | i = 3
121 | j = 5
122 |
123 | big_arr = [1, 2, 3, 4, 5, &
124 | 6, 7, 8, 9, 10, &
125 | 11, 12, 13, 14, 15, &
126 | 16, 17, 18, 19, 20]
127 |
128 | ! example 1.3: disabling auto-formatter:
129 | my_integer = 2 !&
130 | i = 3 !&
131 | j = 5 !&
132 |
133 | !&<
134 | my_integer = 2
135 | i = 3
136 | j = 5
137 | !&>
138 |
139 | big_arr = [ 1, 2, 3, 4, 5, & !&
140 | 6, 7, 8, 9, 10, & !&
141 | 11, 12, 13, 14, 15, & !&
142 | 16, 17, 18, 19, 20] !&
143 |
144 | ! example 1.4:
145 |
146 | big_arr = [1, 2, 3, 4, 5,&
147 | & 6, 7, 8, 9, 10, &
148 | & 11, 12, 13, 14, 15,&
149 | &16, 17, 18, 19, 20]
150 |
151 | ! 2) auto indentation for loops !
152 | !*******************************!
153 |
154 | ! example 2.1
155 | l = 0
156 | DO r = 1, 10
157 | SELECT CASE (r)
158 | CASE (1)
159 | do_label: DO i = 1, 100
160 | IF (i <= 2) THEN
161 | m = 0
162 | DO WHILE (m < 4)
163 | m = m + 1
164 | DO k = 1, 3
165 | IF (k == 1) l = l + 1
166 | END DO
167 | END DO
168 | END IF
169 | END DO do_label
170 | CASE (2)
171 | l = i + j + k
172 | END SELECT
173 | END DO
174 |
175 | ! example 2.2
176 | DO m = 1, 2
177 | DO r = 1, 3
178 | WRITE (*, *) r
179 | DO k = 1, 4
180 | DO l = 1, 3
181 | DO i = 4, 5
182 | DO my_integer = 1, 1
183 | DO j = 1, 2
184 | WRITE (*, *) test_function(m, r, k, l) + i
185 | END DO
186 | END DO
187 | END DO
188 | END DO
189 | END DO
190 | END DO
191 | END DO
192 |
193 | ! 3) auto alignment for linebreaks !
194 | !************************************!
195 |
196 | ! example 3.1
197 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + 3*(2 + 1)
198 |
199 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + &
200 | 3*(2 + 1)
201 |
202 | l = test_function(1, 2, &
203 | test_function(1, 2, 3, 4), 4) + &
204 | 3*(2 + 1)
205 |
206 | l = test_function(1, 2, &
207 | test_function(1, 2, 3, &
208 | 4), 4) + &
209 | 3*(2 + 1)
210 |
211 | ! example 3.2
212 | arr = [1, (/3, 4, 5/), 6] + [1, 2, 3, 4, 5]
213 |
214 | arr = [1, (/3, 4, 5/), &
215 | 6] + [1, 2, 3, 4, 5]
216 |
217 | arr = [1, (/3, 4, 5/), &
218 | 6] + &
219 | [1, 2, 3, 4, 5]
220 |
221 | arr = [1, (/3, 4, &
222 | 5/), &
223 | 6] + &
224 | [1, 2, 3, 4, 5]
225 |
226 | ! example 3.3
227 | l = test_function(1, 2, &
228 | 3, 4)
229 |
230 | l = test_function( &
231 | 1, 2, 3, 4)
232 |
233 | arr = [1, 2, &
234 | 3, 4, 5]
235 | arr = [ &
236 | 1, 2, 3, 4, 5]
237 |
238 | ! 4) more complex formatting and tricky test cases !
239 | !**************************************************!
240 |
241 | ! example 4.1
242 | l = 0
243 | DO r = 1, 10
244 | SELECT CASE (r)
245 | CASE (1)
246 | DO i = 1, 100; IF (i <= 2) THEN! comment
247 | DO j = 1, 5
248 | DO k = 1, 3
249 | l = l + 1
250 | ! unindented comment
251 | ! indented comment
252 | END DO; END DO
253 | ELSEIF (.NOT. j == 4) THEN
254 | my_integer = 4
255 | ELSE
256 | WRITE (*, *) " hello"
257 | END IF
258 | END DO
259 | CASE (2)
260 | l = i + j + k
261 | END SELECT
262 | END DO
263 |
264 | ! example 4.2
265 | IF ( &
266 | l == &
267 | 111) &
268 | THEN
269 | DO k = 1, 2
270 | IF (k == 1) &
271 | l = test_function(1, &
272 | test_function(r=4, i=5, &
273 | j=6, k=test_function(1, 2*(3*(1 + 1)), str_function(")a!(b['(;=dfe"), &
274 | 9) + &
275 | test_function(1, 2, 3, 4)), 9, 10) &
276 | ! test_function(1,2,3,4)),9,10) &
277 | ! +13*str_function('') + str_function('"')
278 | + 13*str_function('') + str_function('"')
279 | END & ! comment
280 | ! comment
281 | DO
282 | END IF
283 |
284 | ! example 4.3
285 | arr = [1, (/3, 4, &
286 | 5/), &
287 | 6] + &
288 | [1, 2, 3, 4, 5]; arr = [1, 2, &
289 | 3, 4, 5]
290 |
291 | ! example 4.4
292 | ENDIF = 3
293 | IF (ENDIF == 2) THEN
294 | ENDIF = 5
295 | ELSE IF (ENDIF == 3) THEN
296 | WRITE (*, *) ENDIF
297 | END IF
298 |
299 | ! example 4.5
300 | DO i = 1, 2; IF (.TRUE.) THEN
301 | WRITE (*, *) "hello"
302 | END IF; END DO
303 |
304 | END PROGRAM
305 |
--------------------------------------------------------------------------------
/fortran_tests/after/example_swapcase.f90-enabled:
--------------------------------------------------------------------------------
1 |
2 | module exAmple
3 | implicit none
4 | private
5 | public :: dp, test_routine, &
6 | test_function, test_type, str_function
7 |
8 | ! Comment, should not change case nor spaces
9 | !!$ INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND ( 15 , 307)
10 | !!$ TYPE test_type
11 | !!$ REAL (kind =dp ) :: r = 1.0d-3
12 | !!$ INTEGER :: i
13 | !!$ END TYPE test_type
14 | !!$
15 | !!$
16 | !!$CONTAINS
17 | !!$
18 | !!$
19 | !!$ SUBROUTINE test_routine( &
20 | !!$ r, i, j, k, l)
21 | !!$ INTEGER, INTENT(in) :: r, i, j, k
22 | !!$ INTEGER, INTENT (out) :: l
23 | !!$
24 | !!$ l = test_function(r,i,j,k)
25 | !!$ END &
26 | !!$SUBROUTINE
27 |
28 | integer, parameter :: SELECTED_REAL_KIND = 1*2
29 | integer, parameter :: dp1 = selected_real_kind(15, 307) ! SELECTED_REAL_KIND ( 15 , 307) !should not change case in comment
30 |
31 | character(len=*), parameter :: a = 'INTEGER, PARAMETER'//'b'!should not change case in string
32 | character(len=*), parameter :: b = "INTEGER, PARAMETER" !should not change case in string
33 | character(len=*), parameter :: c = 'INTEGER, "PARAMETER"' !should not change case in string
34 | character(len=*), parameter :: d = "INTEGER, 'PARAMETER" !should not change case in string
35 |
36 | integer(kind=INT64), parameter :: l64 = 2_INT64
37 | real(kind=REAL64), parameter :: r64a = 2._REAL64
38 | real(kind=REAL64), parameter :: r64b = 2.0_REAL64
39 | real(kind=REAL64), parameter :: r64c = .0_REAL64
40 | real(kind=REAL64), parameter :: r64a = 2.E3_REAL64
41 | real(kind=REAL64), parameter :: r64b = 2.0E3_REAL64
42 | real(kind=REAL64), parameter :: r64c = .0E3_REAL64
43 |
44 | integer, parameter :: dp = selected_real_kind(15, 307)
45 | type test_type
46 | real(kind=dp) :: r = 1.0D-3
47 | integer :: i
48 | end type test_type
49 |
50 | contains
51 |
52 | subroutine test_routine( &
53 | r, i, j, k, l)
54 | use ISO_FORTRAN_ENV, only: INT64
55 | integer, intent(in) :: r, i, j, k
56 | integer, intent(out) :: l
57 |
58 | integer(kind=INT64) :: l64
59 |
60 | l = test_function(r, i, j, k)
61 |
62 | l64 = 2_INT64
63 | if (l .eq. 2) l = max(l64, 2_INT64)
64 | if (l .eq. 2) l = max(l64, 2_INT64)
65 | if (l .eq. 2) l = max
66 |
67 | end &
68 | subroutine
69 |
70 | pure function test_function(r, i, j, &
71 | k) &
72 | result(l)
73 | integer, intent(in) :: r, i, j, k
74 | integer :: l
75 |
76 | l = r + i + j + k
77 | end function
78 | function &
79 | str_function(a) result(l)
80 | character(len=*) :: a
81 | integer :: l
82 |
83 | if (len(a) < 5) then
84 | l = 0
85 | else
86 | l = 1
87 | endif
88 | end function
89 |
90 | end module
91 |
92 | program example_prog
93 | use example, only: dp, test_routine, test_function, test_type, str_function
94 |
95 | implicit none
96 | integer :: r, i, j, k, l, my_integer, m
97 | integer, dimension(5) :: arr
98 | integer, dimension(20) :: big_arr
99 | integer :: endif
100 | type(test_type) :: t
101 | real(kind=dp) :: r1, r2, r3, r4, r5, r6
102 | integer, pointer :: point
103 |
104 | point => null()
105 |
106 | ! 1) white space formatting !
107 | !***************************!
108 | ! example 1.1
109 | r = 1; i = -2; j = 3; k = 4; l = 5
110 | r2 = 0.0_DP; r3 = 1.0_DP; r4 = 2.0_DP; r5 = 3.0_DP; r6 = 4.0_DP
111 | r1 = -(r2**i*(r3 + r5*(-r4) - r6)) - 2.E+2
112 | if (r .eq. 2 .and. r <= 5) i = 3
113 | write (*, *) (merge(3, 1, i <= 2))
114 | write (*, *) test_function(r, i, j, k)
115 | t%r = 4.0_DP
116 | t%i = str_function("t % i = ")
117 |
118 | ! example 1.2
119 | my_integer = 2
120 | i = 3
121 | j = 5
122 |
123 | big_arr = [1, 2, 3, 4, 5, &
124 | 6, 7, 8, 9, 10, &
125 | 11, 12, 13, 14, 15, &
126 | 16, 17, 18, 19, 20]
127 |
128 | ! example 1.3: disabling auto-formatter:
129 | my_integer = 2 !&
130 | i = 3 !&
131 | j = 5 !&
132 |
133 | !&<
134 | my_integer = 2
135 | i = 3
136 | j = 5
137 | !&>
138 |
139 | big_arr = [ 1, 2, 3, 4, 5, & !&
140 | 6, 7, 8, 9, 10, & !&
141 | 11, 12, 13, 14, 15, & !&
142 | 16, 17, 18, 19, 20] !&
143 |
144 | ! example 1.4:
145 |
146 | big_arr = [1, 2, 3, 4, 5,&
147 | & 6, 7, 8, 9, 10, &
148 | & 11, 12, 13, 14, 15,&
149 | &16, 17, 18, 19, 20]
150 |
151 | ! 2) auto indentation for loops !
152 | !*******************************!
153 |
154 | ! example 2.1
155 | l = 0
156 | do r = 1, 10
157 | select case (r)
158 | case (1)
159 | do_label: do i = 1, 100
160 | if (i <= 2) then
161 | m = 0
162 | do while (m < 4)
163 | m = m + 1
164 | do k = 1, 3
165 | if (k == 1) l = l + 1
166 | end do
167 | enddo
168 | endif
169 | enddo do_label
170 | case (2)
171 | l = i + j + k
172 | end select
173 | enddo
174 |
175 | ! example 2.2
176 | do m = 1, 2
177 | do r = 1, 3
178 | write (*, *) r
179 | do k = 1, 4
180 | do l = 1, 3
181 | do i = 4, 5
182 | do my_integer = 1, 1
183 | do j = 1, 2
184 | write (*, *) test_function(m, r, k, l) + i
185 | enddo
186 | enddo
187 | enddo
188 | enddo
189 | enddo
190 | enddo
191 | enddo
192 |
193 | ! 3) auto alignment for linebreaks !
194 | !************************************!
195 |
196 | ! example 3.1
197 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + 3*(2 + 1)
198 |
199 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + &
200 | 3*(2 + 1)
201 |
202 | l = test_function(1, 2, &
203 | test_function(1, 2, 3, 4), 4) + &
204 | 3*(2 + 1)
205 |
206 | l = test_function(1, 2, &
207 | test_function(1, 2, 3, &
208 | 4), 4) + &
209 | 3*(2 + 1)
210 |
211 | ! example 3.2
212 | arr = [1, (/3, 4, 5/), 6] + [1, 2, 3, 4, 5]
213 |
214 | arr = [1, (/3, 4, 5/), &
215 | 6] + [1, 2, 3, 4, 5]
216 |
217 | arr = [1, (/3, 4, 5/), &
218 | 6] + &
219 | [1, 2, 3, 4, 5]
220 |
221 | arr = [1, (/3, 4, &
222 | 5/), &
223 | 6] + &
224 | [1, 2, 3, 4, 5]
225 |
226 | ! example 3.3
227 | l = test_function(1, 2, &
228 | 3, 4)
229 |
230 | l = test_function( &
231 | 1, 2, 3, 4)
232 |
233 | arr = [1, 2, &
234 | 3, 4, 5]
235 | arr = [ &
236 | 1, 2, 3, 4, 5]
237 |
238 | ! 4) more complex formatting and tricky test cases !
239 | !**************************************************!
240 |
241 | ! example 4.1
242 | l = 0
243 | do r = 1, 10
244 | select case (r)
245 | case (1)
246 | do i = 1, 100; if (i <= 2) then! comment
247 | do j = 1, 5
248 | do k = 1, 3
249 | l = l + 1
250 | ! unindented comment
251 | ! indented comment
252 | end do; enddo
253 | elseif (.not. j == 4) then
254 | my_integer = 4
255 | else
256 | write (*, *) " hello"
257 | endif
258 | enddo
259 | case (2)
260 | l = i + j + k
261 | end select
262 | enddo
263 |
264 | ! example 4.2
265 | if ( &
266 | l == &
267 | 111) &
268 | then
269 | do k = 1, 2
270 | if (k == 1) &
271 | l = test_function(1, &
272 | test_function(r=4, i=5, &
273 | j=6, k=test_function(1, 2*(3*(1 + 1)), str_function(")a!(b['(;=dfe"), &
274 | 9) + &
275 | test_function(1, 2, 3, 4)), 9, 10) &
276 | ! test_function(1,2,3,4)),9,10) &
277 | ! +13*str_function('') + str_function('"')
278 | + 13*str_function('') + str_function('"')
279 | end & ! comment
280 | ! comment
281 | do
282 | endif
283 |
284 | ! example 4.3
285 | arr = [1, (/3, 4, &
286 | 5/), &
287 | 6] + &
288 | [1, 2, 3, 4, 5]; arr = [1, 2, &
289 | 3, 4, 5]
290 |
291 | ! example 4.4
292 | endif = 3
293 | if (endif == 2) then
294 | endif = 5
295 | else if (endif == 3) then
296 | write (*, *) endif
297 | endif
298 |
299 | ! example 4.5
300 | do i = 1, 2; if (.true.) then
301 | write (*, *) "hello"
302 | endif; enddo
303 |
304 | end program
305 |
--------------------------------------------------------------------------------
/fortran_tests/after/test_fypp.f90:
--------------------------------------------------------------------------------
1 | #:if DEBUG > 0
2 | print *, "Some debug information"
3 | #:endif
4 |
5 | #:set LOGLEVEL = 2
6 | print *, "LOGLEVEL: ${LOGLEVEL}$"
7 |
8 | #:del LOGLEVEL
9 |
10 | #:def assertTrue(cond)
11 | #:if DEBUG > 0
12 | if (.not. ${cond}$) then
13 | print *, "Assert failed in file ${_FILE_}$, line ${_LINE_}$"
14 | error stop
15 | end if
16 | #:endif
17 | #:enddef assertTrue
18 |
19 | ! Invoked via direct call (argument needs no quotation)
20 | @:assertTrue(size(myArray) > 0)
21 |
22 | ! Invoked as Python expression (argument needs quotation)
23 | $:assertTrue('size(myArray) > 0')
24 |
25 | program test
26 | #:if defined('WITH_MPI')
27 | use mpi
28 | #:elif defined('WITH_OPENMP')
29 | use openmp
30 | #:else
31 | use serial
32 | #:endif
33 | end program
34 |
35 | interface myfunc
36 | #:for dtype in ['real', 'dreal', 'complex', 'dcomplex']
37 | module procedure myfunc_${dtype}$
38 | #:endfor
39 | end interface myfunc
40 |
41 | logical, parameter :: hasMpi = #{if defined('MPI')}# .true. #{else}# .false. #{endif}#
42 |
43 | character(*), parameter :: comp_date = "${time.strftime('%Y-%m-%d')}$"
44 |
45 | #:include "macrodefs.fypp"
46 |
47 | #:if var1 > var2 &
48 | & or var2> var4
49 | print *, "Doing something here"
50 | #:endif
51 |
52 | #! Callable needs only string argument
53 | #:def debug_code(code)
54 | #:if DEBUG > 0
55 | $:code
56 | #:endif
57 | #:enddef debug_code
58 |
59 | #! Pass code block as first positional argument
60 | #:call debug_code
61 | if (size(array) > 100) then
62 | print *, "DEBUG: spuriously large array"
63 | end if
64 | #:endcall debug_code
65 |
66 | #! Callable needs also non-string argument types
67 | #:def repeat_code(code, repeat)
68 | #:for ind in range(repeat)
69 | $:code
70 | #:endfor
71 | #:enddef repeat_code
72 |
73 | #! Pass code block as positional argument and 3 as keyword argument "repeat"
74 | #:call repeat_code(repeat=3)
75 | this will be repeated 3 times
76 | #:endcall repeat_code
77 |
78 | #! This will not show up in the output
79 | #! Also the newline characters at the end of the lines will be suppressed
80 |
81 | #! Definitions are read, but no output (e.g. newlines) will be produced
82 | #:mute
83 | #:include "macrodefs.fypp"
84 | #:endmute
85 |
86 | #:if DEBUGLEVEL < 0
87 | #:stop 'Negative debug level not allowed!'
88 | #:endif
89 |
90 | #:def mymacro(RANK)
91 | #! Macro only works for RANK 1 and above
92 | #:assert RANK > 0
93 | #:enddef mymacro
94 |
95 | program test
96 | #:if defined('MPI')
97 | use mpi
98 | #:endif
99 | end program
100 |
101 | #{if 1 > 2}#Some code#{endif}#
102 |
103 | @:mymacro(a 0
164 | if (.not. (${cond}$)) then
165 | print *, "Assert failed!"
166 | error stop
167 | end if
168 | #:endif
169 | #:enddef
170 |
171 | #:def macro(X, *VARARGS)
172 | X = ${X}$, VARARGS = #{for ARG in VARARGS}#${ARG}$#{endfor}#
173 | #:enddef macro
174 |
175 | $:macro(1,2, 3) #! Returns "X=1, VARARGS=23"
176 |
177 | ! Rather ugly
178 | print *, #{call choose_code}# a(:) #{nextarg}# size(a) #{endcall}#
179 |
180 | ! This form is more readable
181 | print *, ${choose_code('a(:)', 'size(a)')}$
182 |
183 | ! Alternatively, you may use a direct call (see next section)
184 | print *, @{choose_code(a(:), size(a))}@
185 |
186 | @:assertEqual(size(coords, dim=2), &
187 | & size( atomtypes))
188 |
189 | #! Using choose_code() macro defined in previous section
190 | print *, @{choose_code(a(:),size(a))}@
191 |
192 | #:if a > b &
193 | & or b > c &
194 | & or c>d
195 | $:somePythonFunction( param1, &
196 | ¶m2)
197 |
198 | #:mute
199 |
200 | #! Enable debug feature if the preprocessor variable DEBUG has been defined
201 | #:set DEBUG = defined('DEBUG')
202 |
203 | #! Stops the code, if the condition passed to it is not fulfilled
204 | #! Only included in debug mode.
205 | #:def ensure(cond, msg=None)
206 | #:if DEBUG
207 | if (.not. (${cond}$)) then
208 | write (*, *) 'Run-time check failed'
209 | write (*, *) 'Condition: ${cond.replace("'", "''")}$'
210 | #:if msg is not None
211 | write (*, *) 'Message: ', ${msg}$
212 | #:endif
213 | write (*, *) 'File: ${_FILE_}$'
214 | write (*, *) 'Line: ', ${_LINE_}$
215 | stop
216 | end if
217 | #:endif
218 | #:enddef ensure
219 |
220 | #! Includes code if in debug mode.
221 | #:def debug_code(code)
222 | #:if DEBUG
223 | $:code
224 | #:endif
225 | #:enddef debug_code
226 |
227 | #:endmute
228 |
229 | #:include 'checks.fypp'
230 |
231 | module testmod
232 | implicit none
233 |
234 | contains
235 |
236 | subroutine someFunction(ind, uplo)
237 | integer, intent(in) :: ind
238 | character, intent(in) :: uplo
239 |
240 | @:ensure(ind > 0, msg="Index must be positive")
241 | @:ensure(uplo == 'U' .or. uplo == 'L')
242 |
243 | ! Do something useful here
244 |
245 | #:call debug_code
246 | print *, 'We are in debug mode'
247 | print *, 'The value of ind is', ind
248 | #:endcall debug_code
249 |
250 | end subroutine someFunction
251 |
252 | end module testmod
253 |
254 | #:def ranksuffix(RANK)
255 | $:'' if RANK == 0 else '(' + ':' + ',:' * (RANK - 1) + ')'
256 | #:enddef ranksuffix
257 |
258 | #:set PRECISIONS = ['sp', 'dp']
259 | #:set RANKS = range(0, 8)
260 |
261 | module errorcalc
262 | implicit none
263 |
264 | integer, parameter :: sp = kind(1.0)
265 | integer, parameter :: dp = kind(1.0d0)
266 |
267 | interface maxRelError
268 | #:for PREC in PRECISIONS
269 | #:for RANK in RANKS
270 | module procedure maxRelError_${RANK}$_${PREC}$
271 | #:endfor
272 | #:endfor
273 | end interface maxRelError
274 |
275 | contains
276 |
277 | #:for PREC in PRECISIONS
278 | #:for RANK in RANKS
279 |
280 | function maxRelError_${RANK}$_${PREC}$ (obtained, reference) result(res)
281 | real(${PREC}$), intent(in) :: obtained${ranksuffix(RANK)}$
282 | real(${PREC}$), intent(in) :: reference${ranksuffix(RANK)}$
283 | real(${PREC}$) :: res
284 |
285 | #:if RANK == 0
286 | res = abs((obtained - reference)/reference)
287 | #:else
288 | res = maxval(abs((obtained - reference)/reference))
289 | #:endif
290 |
291 | end function maxRelError_${RANK}$_${PREC}$
292 |
293 | #:endfor
294 | #:endfor
295 |
296 | end module errorcalc
297 |
298 | #:def maxRelError_template(RANK, PREC)
299 | function maxRelError_${RANK}$_${PREC}$ (obtained, reference) result(res)
300 | real(${PREC}$), intent(in) :: obtained${ranksuffix(RANK)}$
301 | real(${PREC}$), intent(in) :: reference${ranksuffix(RANK)}$
302 | real(${PREC}$) :: res
303 |
304 | #:if RANK == 0
305 | res = abs((obtained - reference)/reference)
306 | #:else
307 | res = maxval(abs((obtained - reference)/reference))
308 | #:endif
309 |
310 | end function maxRelError_${RANK}$_${PREC}$
311 | #:enddef maxRelError_template
312 |
313 | #:for PREC in PRECISIONS
314 | #:for RANK in RANKS
315 | $:maxRelError_template(RANK, PREC)
316 | #:endfor
317 | #:endfor
318 |
319 | end module errorcalc
320 |
321 | ! tests for fypp directives inside Fortran continuation lines
322 | call test(arg1, &
323 | ${a if a > b else b}$, arg3, &
324 | #:if c>d
325 | c, &
326 | #:else
327 | d, &
328 | #:endif
329 | arg4)
330 |
331 | ! test for nested fypp / fortran constructs
332 | ! this is globally consistent even though the logical scopes can not be matched correctly
333 |
334 | #:if do
335 | do x = 1, 3
336 | ax = x*0.1
337 | #:else
338 | ax = 0.1
339 | #:endif
340 | r = ax
341 | #:if do
342 | end do
343 | #:endif
344 |
345 | r2 = r**2
346 |
--------------------------------------------------------------------------------
/fortran_tests/after/test_invalid.f90:
--------------------------------------------------------------------------------
1 | implicit none
2 | private
3 | public :: dp, test_routine, &
4 | test_function, test_type, str_function
5 | integer, parameter :: dp = selected_real_kind(15, 307)
6 | type test_type
7 | real(kind=dp) :: r = 1.0d-3
8 | integer :: i
9 | end type test_type
10 |
11 | contains
12 |
13 | subroutine test_routine( &
14 | r, i, j, k, l)
15 | integer, intent(in) :: r, i, j, k
16 | integer, intent(out) :: l
17 |
18 | l = test_function(r, i, j, k)
19 |
20 | pure function test_function(r, i, j, &
21 | k &
22 | result(l)
23 | integer, intent(in) :: r, i, j, k
24 | integer :: l
25 |
26 | l = r + i + j + k
27 | end function
28 | function &
29 | str_function(a) result(l)
30 | character(len=*) :: a
31 | integer :: l
32 |
33 | if (len(a) < 5) then
34 | l = 0
35 | else
36 | l = 1
37 | end function
38 |
39 | end module
40 |
41 | program example_prog
42 | use example, only: dp, test_routine, test_function, test_type, str_function
43 |
44 | implicit none
45 | integer :: r, i, j, k, l, my_integer, m
46 | integer, dimension(5) :: arr
47 | integer, dimension(20) :: big_arr
48 | integer :: endif
49 | type(test_type) :: t
50 | real(kind=dp) :: r1, r2, r3, r4, r5, r6
51 | integer, pointer :: point
52 |
53 | point => null()
54 |
55 | r1 = -(r2**i*r3 + r5*(-r4 &
56 | - 3) - r6)) - 2.e+2
57 | r1 = -(r2**i*r3 + (r5*(-r4 &
58 | - 3) - r6 - 2.e+2
59 | if (r .eq. 2 .and. r <= 5) i = 3
60 | write (*, *) ( &
61 | merge(3, 1, i <= 2)
62 | write (*, *) test_function(r, i, j, k)
63 | END MODULE
64 | END PROGRAM
65 | END IF
66 | END DO
67 | FUNCTION a(b)
68 | integer :: a
69 | END FUNCTION
70 | END SUBROUTINE
71 |
72 |
--------------------------------------------------------------------------------
/fortran_tests/after/test_namelist_block_select.f90:
--------------------------------------------------------------------------------
1 | module a_mod
2 | integer :: a_variable, another_variable
3 |
4 | private :: a_variable, &
5 | another_variable
6 | contains
7 |
8 | subroutine test_type(bohoo)
9 | class(*), intent(in) :: bohoo
10 |
11 | select type (bohoo)
12 | type is (real)
13 | write (*, *) 'T'
14 | type is (integer)
15 | write (*, *) 'F'
16 | class default
17 | end select
18 |
19 | return
20 |
21 | end subroutine test_type
22 |
23 | end module a_mod
24 |
25 | program test
26 | use a_mod
27 |
28 | integer :: block_test = 2, block = 2
29 | real :: res, factor = 2.81
30 |
31 | namelist /test_nml/ block, block_test, res, factor
32 |
33 | block = 5
34 |
35 | block
36 | real :: another_real
37 | another_real = 4.5
38 | end block
39 |
40 | call test_type(block)
41 |
42 | block ! have more vars
43 | real :: block
44 | call test_type(block)
45 | end block
46 |
47 | block = block*5/block_test + 1
48 | ! whitespace 2
49 | ! res = factor*5/block_test + 1
50 | res = factor*5/block_test + 1
51 | ! whitespace 3
52 | ! res = factor * 5 / block_test + 1
53 | res = factor*5/block_test + 1
54 |
55 | stop
56 |
57 | end program test
58 |
--------------------------------------------------------------------------------
/fortran_tests/after/where_forall.f90:
--------------------------------------------------------------------------------
1 | ! Forall-construct
2 |
3 | ! Example 1
4 |
5 | forall (I=3:N + 1, J=3:N + 1)
6 | C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
7 | D(I, J) = C(I, J)
8 | end forall
9 |
10 | ! Example 2
11 |
12 | forall (I=3:N + 1, J=3:N + 1)
13 | C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
14 | D(I, J) = C(I, J)
15 | end forall
16 |
17 | ! Example 3
18 |
19 | forall (I=3:N + 1, J=3:N + 1)
20 | C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
21 | D(I, J) = C(I, J)
22 | end forall
23 |
24 | ! Where-construct
25 |
26 | ! Example 1
27 |
28 | where (C /= 0)
29 | A = B/C
30 | elsewhere
31 | A = 0.0
32 | end where
33 |
34 | ! Example 2
35 |
36 | where (C /= 0)
37 | A = B/C
38 | elsewhere
39 | A = 0.0
40 | end where
41 |
42 | ! Example 3
43 |
44 | where (C /= 0)
45 | A = B/C
46 | elsewhere
47 | A = 0.0
48 | end where
49 |
--------------------------------------------------------------------------------
/fortran_tests/before/example.f90:
--------------------------------------------------------------------------------
1 | module example
2 | implicit none
3 | private
4 | public :: dp, test_routine, &
5 | test_function, test_type, str_function
6 | integer, parameter :: dp = selected_real_kind ( 15 , 307)
7 | type test_type
8 | real (kind =dp ) :: r = 1.0d-3
9 | integer :: i
10 | end type test_type
11 |
12 | contains
13 |
14 |
15 | subroutine test_routine( &
16 | r, i, j, k, l)
17 | integer, intent(in) :: r, i, j, k
18 | integer, intent (out) :: l
19 |
20 | l = test_function(r,i,j,k)
21 | end &
22 | subroutine
23 |
24 | pure function test_function(r, i, j, &
25 | k) &
26 | result(l)
27 | integer, intent(in) :: r, i, j, k
28 | integer :: l
29 |
30 | l=r + i +j +k
31 | end function
32 | function &
33 | str_function(a) result(l)
34 | character(len=*) :: a
35 | integer :: l
36 |
37 | if(len(a)<5)then
38 | l=0
39 | else
40 | l=1
41 | endif
42 | end function
43 |
44 | end module
45 |
46 | program example_prog
47 | use example, only: dp, test_routine, test_function, test_type,str_function
48 |
49 | implicit none
50 | integer :: r,i,j,k,l,my_integer,m
51 | integer, dimension(5) :: arr
52 | integer, dimension(20) :: big_arr
53 | integer :: endif
54 | type(test_type) :: t
55 | real(kind=dp) :: r1, r2, r3, r4, r5, r6
56 | integer, pointer :: point
57 |
58 | point=> null( )
59 |
60 | ! 1) white space formatting !
61 | !***************************!
62 | ! example 1.1
63 | r=1;i=-2;j=3;k=4;l=5
64 | r2 = 0.0_dp; r3= 1.0_dp; r4 =2.0_dp; r5=3.0_dp; r6 = 4.0_dp
65 | r1=-(r2**i*(r3+r5*(-r4)-r6))-2.e+2
66 | if( r.eq.2.and.r<=5) i=3
67 | write(*, *)(merge(3, 1, i<=2))
68 | write(*, *)test_function(r,i,j , k)
69 | t % r = 4.0_dp
70 | t%i = str_function( "t % i = " )
71 |
72 | ! example 1.2
73 | my_integer=2
74 | i=3
75 | j=5
76 |
77 | big_arr = [1, 2, 3, 4, 5, &
78 | 6, 7, 8, 9, 10, &
79 | 11, 12, 13, 14, 15, &
80 | 16, 17, 18, 19, 20]
81 |
82 | ! example 1.3: disabling auto-formatter:
83 | my_integer = 2 !&
84 | i = 3 !&
85 | j = 5 !&
86 |
87 | !&<
88 | my_integer = 2
89 | i = 3
90 | j = 5
91 | !&>
92 |
93 | big_arr = [ 1, 2, 3, 4, 5, & !&
94 | 6, 7, 8, 9, 10, & !&
95 | 11, 12, 13, 14, 15, & !&
96 | 16, 17, 18, 19, 20] !&
97 |
98 | ! example 1.4:
99 |
100 | big_arr = [1, 2, 3, 4, 5,&
101 | & 6, 7, 8, 9, 10, &
102 | & 11, 12, 13, 14, 15,&
103 | &16, 17, 18, 19, 20]
104 |
105 | ! 2) auto indentation for loops !
106 | !*******************************!
107 |
108 | ! example 2.1
109 | l = 0
110 | do r= 1 , 10
111 | select case (r)
112 | case(1)
113 | do_label: do i = 1,100
114 | if (i<=2) then
115 | m =0
116 | do while(m <4)
117 | m =m+1
118 | do k=1,3
119 | if (k==1) l =l +1
120 | end do
121 | enddo
122 | endif
123 | enddo do_label
124 | case ( 2 )
125 | l=i + j + k
126 | end select
127 | enddo
128 |
129 | ! example 2.2
130 | do m = 1, 2
131 | do r = 1, 3
132 | write (*, *) r
133 | do k = 1, 4
134 | do l = 1, 3
135 | do i = 4, 5
136 | do my_integer = 1, 1
137 | do j = 1, 2
138 | write (*, *) test_function(m, r, k, l) + i
139 | enddo
140 | enddo
141 | enddo
142 | enddo
143 | enddo
144 | enddo
145 | enddo
146 |
147 | ! 3) auto alignment for linebreaks !
148 | !************************************!
149 |
150 | ! example 3.1
151 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + 3 *(2+1)
152 |
153 | l = test_function (1, 2, test_function(1,2, 3, 4),4) +&
154 | 3*(2+ 1 )
155 |
156 | l = test_function(1, 2, &
157 | test_function(1, 2, 3, 4), 4)+ &
158 | 3 * (2+1)
159 |
160 | l = test_function(1, 2, &
161 | test_function(1, 2, 3, &
162 | 4), 4) + &
163 | 3*(2 + 1)
164 |
165 | ! example 3.2
166 | arr = [1, (/3,4, 5/), 6] + [ 1, 2,3, 4,5 ]
167 |
168 | arr = [1,(/ 3, 4, 5 /) , &
169 | 6] +[1,2, 3, 4, 5 ]
170 |
171 | arr = [1,(/3,4,5/), &
172 | 6]+ &
173 | [1, 2, 3, 4, 5]
174 |
175 | arr = [1, (/3, 4, &
176 | 5/), &
177 | 6] + &
178 | [1, 2,3, 4, 5 ]
179 |
180 | ! example 3.3
181 | l = test_function(1, 2, &
182 | 3, 4)
183 |
184 | l = test_function( &
185 | 1, 2, 3, 4)
186 |
187 | arr = [1, 2, &
188 | 3, 4, 5]
189 | arr = [ &
190 | 1, 2, 3, 4, 5]
191 |
192 | ! 4) more complex formatting and tricky test cases !
193 | !**************************************************!
194 |
195 | ! example 4.1
196 | l = 0
197 | do r = 1, 10
198 | select case ( r )
199 | case( 1)
200 | do i=1,100;if (i<=2) then! comment
201 | do j = 1,5
202 | do k= 1, 3
203 | l = l + 1
204 | ! unindented comment
205 | ! indented comment
206 | end do; enddo
207 | elseif ( .not. j ==4 ) then
208 | my_integer = 4
209 | else
210 | write (*,*) " hello"
211 | endif
212 | enddo
213 | case(2 )
214 | l = i+ j + k
215 | end select
216 | enddo
217 |
218 | ! example 4.2
219 | if ( &
220 | l == &
221 | 111) &
222 | then
223 | do k = 1, 2
224 | if (k == 1) &
225 | l = test_function(1, &
226 | test_function(r=4, i=5, &
227 | j=6, k=test_function(1,2*(3*(1 +1)), str_function ( ")a!(b['(;=dfe"), &
228 | 9) + &
229 | test_function(1, 2, 3, 4)), 9, 10) &
230 | ! test_function(1,2,3,4)),9,10) &
231 | ! +13*str_function('') + str_function('"')
232 | + 13*str_function('') + str_function('"')
233 | end & ! comment
234 | ! comment
235 | do
236 | endif
237 |
238 | ! example 4.3
239 | arr = [1,(/3,4, &
240 | 5 /),&
241 | 6 ]+ &
242 | [1,2, 3, 4,5] ; arr = [1, 2,&
243 | 3, 4, 5]
244 |
245 | ! example 4.4
246 | endif = 3
247 | if(endif==2)then
248 | endif=5
249 | else if(endif==3)then
250 | write(*,*)endif
251 | endif
252 |
253 | ! example 4.5
254 | do i=1,2;if(.true.)then
255 | write(*, *)"hello"
256 | endif; enddo
257 |
258 | end program
259 |
--------------------------------------------------------------------------------
/fortran_tests/before/example_swapcase.f90:
--------------------------------------------------------------------------------
1 |
2 | MODULE exAmple
3 | IMPLICIT NONE
4 | PRIVATE
5 | PUBLIC :: dp, test_routine, &
6 | test_function, test_type, str_function
7 |
8 | ! Comment, should not change case nor spaces
9 | !!$ INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND ( 15 , 307)
10 | !!$ TYPE test_type
11 | !!$ REAL (kind =dp ) :: r = 1.0d-3
12 | !!$ INTEGER :: i
13 | !!$ END TYPE test_type
14 | !!$
15 | !!$
16 | !!$CONTAINS
17 | !!$
18 | !!$
19 | !!$ SUBROUTINE test_routine( &
20 | !!$ r, i, j, k, l)
21 | !!$ INTEGER, INTENT(in) :: r, i, j, k
22 | !!$ INTEGER, INTENT (out) :: l
23 | !!$
24 | !!$ l = test_function(r,i,j,k)
25 | !!$ END &
26 | !!$SUBROUTINE
27 |
28 | INTEGER, PARAMETER :: SELECTED_REAL_KIND = 1*2
29 | INTEGER, PARAMETER :: dp1 = SELECTED_REAL_KIND ( 15 , 307) ! SELECTED_REAL_KIND ( 15 , 307) !should not change case in comment
30 |
31 | character(len=*), parameter :: a = 'INTEGER, PARAMETER' // 'b'!should not change case in string
32 | character(len=*), parameter :: b = "INTEGER, PARAMETER" !should not change case in string
33 | character(len=*), parameter :: c = 'INTEGER, "PARAMETER"' !should not change case in string
34 | character(len=*), parameter :: d = "INTEGER, 'PARAMETER" !should not change case in string
35 |
36 |
37 | INTEGER(kind=int64), parameter :: l64 = 2_int64
38 | REAL(kind=real64), parameter :: r64a = 2._real64
39 | REAL(kind=real64), parameter :: r64b = 2.0_real64
40 | REAL(kind=real64), parameter :: r64c = .0_real64
41 | REAL(kind=real64), parameter :: r64a = 2.e3_real64
42 | REAL(kind=real64), parameter :: r64b = 2.0e3_real64
43 | REAL(kind=real64), parameter :: r64c = .0e3_real64
44 |
45 | INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND ( 15 , 307)
46 | TYPE test_type
47 | REAL (kind =dp ) :: r = 1.0d-3
48 | INTEGER :: i
49 | END TYPE test_type
50 |
51 |
52 | CONTAINS
53 |
54 |
55 | SUBROUTINE test_routine( &
56 | r, i, j, k, l)
57 | USE iso_fortran_env, only: int64
58 | INTEGER, INTENT(in) :: r, i, j, k
59 | INTEGER, INTENT (out) :: l
60 |
61 | INTEGER(kind=int64) :: l64
62 |
63 | l = test_function(r,i,j,k)
64 |
65 | l64 = 2_int64
66 | IF (l.EQ.2) l=max(l64, 2_int64)
67 | IF (l.EQ.2) l=max (l64, 2_int64)
68 | IF (l.EQ.2) l=max
69 |
70 | END &
71 | SUBROUTINE
72 |
73 | PURE FUNCTION test_function(r, i, j, &
74 | k) &
75 | RESULT(l)
76 | INTEGER, INTENT(in) :: r, i, j, k
77 | INTEGER :: l
78 |
79 | l=r + i +j +k
80 | END FUNCTION
81 | FUNCTION &
82 | str_function(a) RESULT(l)
83 | CHARACTER(len=*) :: a
84 | INTEGER :: l
85 |
86 | IF(LEN(a)<5)THEN
87 | l=0
88 | ELSE
89 | l=1
90 | ENDIF
91 | END FUNCTION
92 |
93 | END MODULE
94 |
95 | PROGRAM example_prog
96 | USE example, ONLY: dp, test_routine, test_function, test_type,str_function
97 |
98 | IMPLICIT NONE
99 | INTEGER :: r,i,j,k,l,my_integer,m
100 | INTEGER, DIMENSION(5) :: arr
101 | INTEGER, DIMENSION(20) :: big_arr
102 | INTEGER :: ENDIF
103 | TYPE(test_type) :: t
104 | REAL(kind=dp) :: r1, r2, r3, r4, r5, r6
105 | INTEGER, POINTER :: point
106 |
107 | point=> NULL( )
108 |
109 | ! 1) white space formatting !
110 | !***************************!
111 | ! example 1.1
112 | r=1;i=-2;j=3;k=4;l=5
113 | r2 = 0.0_dp; r3= 1.0_dp; r4 =2.0_dp; r5=3.0_dp; r6 = 4.0_dp
114 | r1=-(r2**i*(r3+r5*(-r4)-r6))-2.e+2
115 | IF( r.EQ.2.AND.r<=5) i=3
116 | WRITE(*, *)(MERGE(3, 1, i<=2))
117 | WRITE(*, *)test_function(r,i,j , k)
118 | t % r = 4.0_dp
119 | t%i = str_function( "t % i = " )
120 |
121 | ! example 1.2
122 | my_integer=2
123 | i=3
124 | j=5
125 |
126 | big_arr = [1, 2, 3, 4, 5, &
127 | 6, 7, 8, 9, 10, &
128 | 11, 12, 13, 14, 15, &
129 | 16, 17, 18, 19, 20]
130 |
131 | ! example 1.3: disabling auto-formatter:
132 | my_integer = 2 !&
133 | i = 3 !&
134 | j = 5 !&
135 |
136 | !&<
137 | my_integer = 2
138 | i = 3
139 | j = 5
140 | !&>
141 |
142 | big_arr = [ 1, 2, 3, 4, 5, & !&
143 | 6, 7, 8, 9, 10, & !&
144 | 11, 12, 13, 14, 15, & !&
145 | 16, 17, 18, 19, 20] !&
146 |
147 | ! example 1.4:
148 |
149 | big_arr = [1, 2, 3, 4, 5,&
150 | & 6, 7, 8, 9, 10, &
151 | & 11, 12, 13, 14, 15,&
152 | &16, 17, 18, 19, 20]
153 |
154 | ! 2) auto indentation for loops !
155 | !*******************************!
156 |
157 | ! example 2.1
158 | l = 0
159 | DO r= 1 , 10
160 | SELECT CASE (r)
161 | CASE(1)
162 | do_label: DO i = 1,100
163 | IF (i<=2) THEN
164 | m =0
165 | DO WHILE(m <4)
166 | m =m+1
167 | DO k=1,3
168 | IF (k==1) l =l +1
169 | END DO
170 | ENDDO
171 | ENDIF
172 | ENDDO do_label
173 | CASE ( 2 )
174 | l=i + j + k
175 | END SELECT
176 | ENDDO
177 |
178 | ! example 2.2
179 | DO m = 1, 2
180 | DO r = 1, 3
181 | WRITE (*, *) r
182 | DO k = 1, 4
183 | DO l = 1, 3
184 | DO i = 4, 5
185 | DO my_integer = 1, 1
186 | DO j = 1, 2
187 | WRITE (*, *) test_function(m, r, k, l) + i
188 | ENDDO
189 | ENDDO
190 | ENDDO
191 | ENDDO
192 | ENDDO
193 | ENDDO
194 | ENDDO
195 |
196 | ! 3) auto alignment for linebreaks !
197 | !************************************!
198 |
199 | ! example 3.1
200 | l = test_function(1, 2, test_function(1, 2, 3, 4), 4) + 3 *(2+1)
201 |
202 | l = test_function (1, 2, test_function(1,2, 3, 4),4) +&
203 | 3*(2+ 1 )
204 |
205 | l = test_function(1, 2, &
206 | test_function(1, 2, 3, 4), 4)+ &
207 | 3 * (2+1)
208 |
209 | l = test_function(1, 2, &
210 | test_function(1, 2, 3, &
211 | 4), 4) + &
212 | 3*(2 + 1)
213 |
214 | ! example 3.2
215 | arr = [1, (/3,4, 5/), 6] + [ 1, 2,3, 4,5 ]
216 |
217 | arr = [1,(/ 3, 4, 5 /) , &
218 | 6] +[1,2, 3, 4, 5 ]
219 |
220 | arr = [1,(/3,4,5/), &
221 | 6]+ &
222 | [1, 2, 3, 4, 5]
223 |
224 | arr = [1, (/3, 4, &
225 | 5/), &
226 | 6] + &
227 | [1, 2,3, 4, 5 ]
228 |
229 | ! example 3.3
230 | l = test_function(1, 2, &
231 | 3, 4)
232 |
233 | l = test_function( &
234 | 1, 2, 3, 4)
235 |
236 | arr = [1, 2, &
237 | 3, 4, 5]
238 | arr = [ &
239 | 1, 2, 3, 4, 5]
240 |
241 | ! 4) more complex formatting and tricky test cases !
242 | !**************************************************!
243 |
244 | ! example 4.1
245 | l = 0
246 | DO r = 1, 10
247 | SELECT CASE ( r )
248 | CASE( 1)
249 | DO i=1,100;IF (i<=2) THEN! comment
250 | DO j = 1,5
251 | DO k= 1, 3
252 | l = l + 1
253 | ! unindented comment
254 | ! indented comment
255 | END DO; ENDDO
256 | ELSEIF ( .NOT. j ==4 ) THEN
257 | my_integer = 4
258 | ELSE
259 | WRITE (*,*) " hello"
260 | ENDIF
261 | ENDDO
262 | CASE(2 )
263 | l = i+ j + k
264 | END SELECT
265 | ENDDO
266 |
267 | ! example 4.2
268 | IF ( &
269 | l == &
270 | 111) &
271 | THEN
272 | DO k = 1, 2
273 | IF (k == 1) &
274 | l = test_function(1, &
275 | test_function(r=4, i=5, &
276 | j=6, k=test_function(1,2*(3*(1 +1)), str_function ( ")a!(b['(;=dfe"), &
277 | 9) + &
278 | test_function(1, 2, 3, 4)), 9, 10) &
279 | ! test_function(1,2,3,4)),9,10) &
280 | ! +13*str_function('') + str_function('"')
281 | + 13*str_function('') + str_function('"')
282 | END & ! comment
283 | ! comment
284 | DO
285 | ENDIF
286 |
287 | ! example 4.3
288 | arr = [1,(/3,4, &
289 | 5 /),&
290 | 6 ]+ &
291 | [1,2, 3, 4,5] ; arr = [1, 2,&
292 | 3, 4, 5]
293 |
294 | ! example 4.4
295 | ENDIF = 3
296 | IF(ENDIF==2)THEN
297 | ENDIF=5
298 | ELSE IF(ENDIF==3)THEN
299 | WRITE(*,*)ENDIF
300 | ENDIF
301 |
302 | ! example 4.5
303 | DO i=1,2;IF(.TRUE.)THEN
304 | WRITE(*, *)"hello"
305 | ENDIF; ENDDO
306 |
307 | END PROGRAM
308 |
--------------------------------------------------------------------------------
/fortran_tests/before/test_fypp.f90:
--------------------------------------------------------------------------------
1 | #:if DEBUG > 0
2 | print *, "Some debug information"
3 | #:endif
4 |
5 | #:set LOGLEVEL = 2
6 | print *, "LOGLEVEL: ${LOGLEVEL}$"
7 |
8 | #:del LOGLEVEL
9 |
10 | #:def assertTrue(cond)
11 | #:if DEBUG > 0
12 | if (.not. ${cond}$ ) then
13 | print*,"Assert failed in file ${_FILE_}$, line ${_LINE_}$"
14 | error stop
15 | end if
16 | #:endif
17 | #:enddef assertTrue
18 |
19 | ! Invoked via direct call (argument needs no quotation)
20 | @:assertTrue(size(myArray) > 0)
21 |
22 | ! Invoked as Python expression (argument needs quotation)
23 | $:assertTrue('size(myArray) > 0')
24 |
25 | program test
26 | #:if defined('WITH_MPI')
27 | use mpi
28 | #:elif defined('WITH_OPENMP')
29 | use openmp
30 | #:else
31 | use serial
32 | #:endif
33 | end program
34 |
35 | interface myfunc
36 | #:for dtype in ['real', 'dreal', 'complex', 'dcomplex']
37 | module procedure myfunc_${dtype}$
38 | #:endfor
39 | end interface myfunc
40 |
41 | logical,parameter :: hasMpi = #{if defined('MPI')}# .true. #{else}# .false. #{endif}#
42 |
43 | character(*), parameter :: comp_date ="${time.strftime('%Y-%m-%d')}$"
44 |
45 | #:include "macrodefs.fypp"
46 |
47 | #:if var1 > var2 &
48 | & or var2> var4
49 | print *,"Doing something here"
50 | #:endif
51 |
52 | #! Callable needs only string argument
53 | #:def debug_code(code)
54 | #:if DEBUG > 0
55 | $:code
56 | #:endif
57 | #:enddef debug_code
58 |
59 | #! Pass code block as first positional argument
60 | #:call debug_code
61 | if (size(array) > 100) then
62 | print *,"DEBUG: spuriously large array"
63 | end if
64 | #:endcall debug_code
65 |
66 | #! Callable needs also non-string argument types
67 | #:def repeat_code(code, repeat)
68 | #:for ind in range(repeat)
69 | $:code
70 | #:endfor
71 | #:enddef repeat_code
72 |
73 | #! Pass code block as positional argument and 3 as keyword argument "repeat"
74 | #:call repeat_code(repeat=3)
75 | this will be repeated 3 times
76 | #:endcall repeat_code
77 |
78 | #! This will not show up in the output
79 | #! Also the newline characters at the end of the lines will be suppressed
80 |
81 | #! Definitions are read, but no output (e.g. newlines) will be produced
82 | #:mute
83 | #:include "macrodefs.fypp"
84 | #:endmute
85 |
86 | #:if DEBUGLEVEL < 0
87 | #:stop 'Negative debug level not allowed!'
88 | #:endif
89 |
90 | #:def mymacro(RANK)
91 | #! Macro only works for RANK 1 and above
92 | #:assert RANK > 0
93 | #:enddef mymacro
94 |
95 | program test
96 | #:if defined('MPI')
97 | use mpi
98 | #:endif
99 | end program
100 |
101 | #{if 1 > 2}#Some code#{endif}#
102 |
103 | @:mymacro(a 0
164 | if (.not. (${cond}$)) then
165 | print *,"Assert failed!"
166 | error stop
167 | end if
168 | #:endif
169 | #:enddef
170 |
171 | #:def macro(X, *VARARGS)
172 | X=${X}$, VARARGS=#{for ARG in VARARGS}#${ARG}$#{endfor}#
173 | #:enddef macro
174 |
175 | $:macro(1,2, 3) #! Returns "X=1, VARARGS=23"
176 |
177 | ! Rather ugly
178 | print *, #{call choose_code}# a(:) #{nextarg}# size(a) #{endcall}#
179 |
180 | ! This form is more readable
181 | print *, ${choose_code('a(:)', 'size(a)')}$
182 |
183 | ! Alternatively, you may use a direct call (see next section)
184 | print *, @{choose_code(a(:), size(a))}@
185 |
186 | @:assertEqual(size(coords, dim=2), &
187 | & size( atomtypes))
188 |
189 | #! Using choose_code() macro defined in previous section
190 | print *, @{choose_code(a(:),size(a))}@
191 |
192 | #:if a > b &
193 | & or b > c &
194 | & or c>d
195 | $:somePythonFunction( param1, &
196 | ¶m2)
197 |
198 | #:mute
199 |
200 | #! Enable debug feature if the preprocessor variable DEBUG has been defined
201 | #:set DEBUG = defined('DEBUG')
202 |
203 |
204 | #! Stops the code, if the condition passed to it is not fulfilled
205 | #! Only included in debug mode.
206 | #:def ensure(cond, msg=None)
207 | #:if DEBUG
208 | if (.not. (${cond}$)) then
209 | write(*,*) 'Run-time check failed'
210 | write(*,*) 'Condition: ${cond.replace("'", "''")}$'
211 | #:if msg is not None
212 | write(*,*) 'Message: ', ${msg}$
213 | #:endif
214 | write(*,*)'File: ${_FILE_}$'
215 | write(*,*) 'Line: ', ${_LINE_}$
216 | stop
217 | end if
218 | #:endif
219 | #:enddef ensure
220 |
221 |
222 | #! Includes code if in debug mode.
223 | #:def debug_code(code)
224 | #:if DEBUG
225 | $:code
226 | #:endif
227 | #:enddef debug_code
228 |
229 | #:endmute
230 |
231 | #:include 'checks.fypp'
232 |
233 | module testmod
234 | implicit none
235 |
236 | contains
237 |
238 | subroutine someFunction(ind, uplo)
239 | integer, intent(in) :: ind
240 | character, intent(in) :: uplo
241 |
242 | @:ensure(ind > 0, msg="Index must be positive")
243 | @:ensure(uplo == 'U' .or. uplo == 'L')
244 |
245 | ! Do something useful here
246 |
247 | #:call debug_code
248 | print *, 'We are in debug mode'
249 | print *, 'The value of ind is', ind
250 | #:endcall debug_code
251 |
252 | end subroutine someFunction
253 |
254 | end module testmod
255 |
256 |
257 | #:def ranksuffix(RANK)
258 | $:'' if RANK == 0 else '(' + ':' + ',:' * (RANK - 1) + ')'
259 | #:enddef ranksuffix
260 |
261 | #:set PRECISIONS = ['sp', 'dp']
262 | #:set RANKS = range(0, 8)
263 |
264 | module errorcalc
265 | implicit none
266 |
267 | integer, parameter :: sp = kind(1.0)
268 | integer, parameter :: dp = kind(1.0d0)
269 |
270 | interface maxRelError
271 | #:for PREC in PRECISIONS
272 | #:for RANK in RANKS
273 | module procedure maxRelError_${RANK}$_${PREC}$
274 | #:endfor
275 | #:endfor
276 | end interface maxRelError
277 |
278 | contains
279 |
280 | #:for PREC in PRECISIONS
281 | #:for RANK in RANKS
282 |
283 | function maxRelError_${RANK}$_${PREC}$(obtained, reference) result(res)
284 | real(${PREC}$), intent(in) :: obtained${ranksuffix(RANK)}$
285 | real(${PREC}$), intent(in) :: reference${ranksuffix(RANK)}$
286 | real(${PREC}$) :: res
287 |
288 | #:if RANK == 0
289 | res = abs((obtained - reference) / reference)
290 | #:else
291 | res = maxval(abs((obtained - reference) / reference))
292 | #:endif
293 |
294 | end function maxRelError_${RANK}$_${PREC}$
295 |
296 | #:endfor
297 | #:endfor
298 |
299 | end module errorcalc
300 |
301 | #:def maxRelError_template(RANK, PREC)
302 | function maxRelError_${RANK}$_${PREC}$(obtained, reference) result(res)
303 | real(${PREC}$), intent(in) :: obtained${ranksuffix(RANK)}$
304 | real(${PREC}$), intent(in) :: reference${ranksuffix(RANK)}$
305 | real(${PREC}$) :: res
306 |
307 | #:if RANK == 0
308 | res = abs((obtained - reference) / reference)
309 | #:else
310 | res = maxval(abs((obtained - reference) / reference))
311 | #:endif
312 |
313 | end function maxRelError_${RANK}$_${PREC}$
314 | #:enddef maxRelError_template
315 |
316 | #:for PREC in PRECISIONS
317 | #:for RANK in RANKS
318 | $:maxRelError_template(RANK, PREC)
319 | #:endfor
320 | #:endfor
321 |
322 | end module errorcalc
323 |
324 | ! tests for fypp directives inside Fortran continuation lines
325 | call test(arg1,&
326 | ${a if a > b else b}$, arg3, &
327 | #:if c>d
328 | c,&
329 | #:else
330 | d,&
331 | #:endif
332 | arg4)
333 |
334 | ! test for nested fypp / fortran constructs
335 | ! this is globally consistent even though the logical scopes can not be matched correctly
336 |
337 | #:if do
338 | do x=1,3
339 | ax=x*0.1
340 | #:else
341 | ax=0.1
342 | #:endif
343 | r=ax
344 | #:if do
345 | enddo
346 | #:endif
347 |
348 | r2 = r**2
349 |
--------------------------------------------------------------------------------
/fortran_tests/before/test_invalid.f90:
--------------------------------------------------------------------------------
1 | implicit none
2 | private
3 | public :: dp, test_routine, &
4 | test_function, test_type, str_function
5 | integer, parameter :: dp = selected_real_kind ( 15 , 307)
6 | type test_type
7 | real (kind =dp ) :: r = 1.0d-3
8 | integer :: i
9 | end type test_type
10 |
11 | contains
12 |
13 |
14 | subroutine test_routine( &
15 | r, i, j, k, l)
16 | integer, intent(in) :: r, i, j, k
17 | integer, intent (out) :: l
18 |
19 | l = test_function(r,i,j,k)
20 |
21 | pure function test_function(r, i, j, &
22 | k &
23 | result(l)
24 | integer, intent(in) :: r, i, j, k
25 | integer :: l
26 |
27 | l=r + i +j +k
28 | end function
29 | function &
30 | str_function(a) result(l)
31 | character(len=*) :: a
32 | integer :: l
33 |
34 | if(len(a)<5)then
35 | l=0
36 | else
37 | l=1
38 | end function
39 |
40 | end module
41 |
42 | program example_prog
43 | use example, only: dp, test_routine, test_function, test_type,str_function
44 |
45 | implicit none
46 | integer :: r,i,j,k,l,my_integer,m
47 | integer, dimension(5) :: arr
48 | integer, dimension(20) :: big_arr
49 | integer :: endif
50 | type(test_type) :: t
51 | real(kind=dp) :: r1, r2, r3, r4, r5, r6
52 | integer, pointer :: point
53 |
54 | point=> null( )
55 |
56 | r1=-(r2**i*r3+r5*(-r4 &
57 | - 3)-r6))-2.e+2
58 | r1=-(r2**i*r3+(r5*(-r4 &
59 | - 3)-r6-2.e+2
60 | if( r.eq.2.and.r<=5) i=3
61 | write(*, *)(&
62 | merge(3, 1, i<=2)
63 | write(*, *) test_function(r,i,j , k)
64 | END MODULE
65 | ENDPROGRAM
66 | ENDIF
67 | ENDDO
68 | FUNCTION a(b)
69 | integer :: a
70 | ENDFUNCTION
71 | END SUBROUTINE
72 |
73 |
--------------------------------------------------------------------------------
/fortran_tests/before/test_namelist_block_select.f90:
--------------------------------------------------------------------------------
1 | module a_mod
2 | integer :: a_variable, another_variable
3 |
4 | private :: a_variable, &
5 | another_variable
6 | contains
7 |
8 | subroutine test_type(bohoo)
9 | class(*), intent(in) :: bohoo
10 |
11 | select type(bohoo)
12 | type is(real)
13 | write(*,*) 'T'
14 | type is(integer)
15 | write(*,*) 'F'
16 | class default
17 | end select
18 |
19 | return
20 |
21 | end subroutine test_type
22 |
23 | end module a_mod
24 |
25 | program test
26 | use a_mod
27 |
28 | integer :: block_test=2, block = 2
29 | real :: res, factor = 2.81
30 |
31 | namelist/test_nml/block, block_test, res, factor
32 |
33 | block = 5
34 |
35 | block
36 | real :: another_real
37 | another_real = 4.5
38 | end block
39 |
40 | call test_type(block)
41 |
42 | block ! have more vars
43 | real :: block
44 | call test_type(block)
45 | end block
46 |
47 | block = block*5/block_test+1
48 | ! whitespace 2
49 | ! res = factor*5/block_test + 1
50 | res = factor*5/block_test + 1
51 | ! whitespace 3
52 | ! res = factor * 5 / block_test + 1
53 | res = factor * 5 / block_test + 1
54 |
55 | stop
56 |
57 | end program test
58 |
--------------------------------------------------------------------------------
/fortran_tests/before/where_forall.f90:
--------------------------------------------------------------------------------
1 | ! Forall-construct
2 |
3 | ! Example 1
4 |
5 | forall(I = 3:N + 1, J = 3:N + 1)
6 | C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
7 | D(I, J) = C(I, J)
8 | end forall
9 |
10 | ! Example 2
11 |
12 | forall(I = 3:N + 1, J = 3:N + 1)
13 | C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
14 | D(I, J) = C(I, J)
15 | end forall
16 |
17 | ! Example 3
18 |
19 | forall(I = 3:N + 1, J = 3:N + 1)
20 | C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
21 | D(I, J) = C(I, J)
22 | end forall
23 |
24 | ! Where-construct
25 |
26 | ! Example 1
27 |
28 | where (C/=0)
29 | A=B/C
30 | elsewhere
31 | A=0.0
32 | end where
33 |
34 | ! Example 2
35 |
36 | where (C/=0)
37 | A=B/C
38 | elsewhere
39 | A=0.0
40 | end where
41 |
42 | ! Example 3
43 |
44 | where (C/=0)
45 | A=B/C
46 | elsewhere
47 | A=0.0
48 | end where
49 |
--------------------------------------------------------------------------------
/fprettify.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | ###############################################################################
4 | # This file is part of fprettify.
5 | # Copyright (C) 2016-2019 Patrick Seewald, CP2K developers group
6 | #
7 | # fprettify is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # fprettify is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with fprettify. If not, see .
19 | ###############################################################################
20 |
21 | """wrapper script to run fprettify"""
22 |
23 | from fprettify import run # pragma: no cover
24 |
25 | if __name__ == '__main__': # pragma: no cover
26 | run()
27 |
--------------------------------------------------------------------------------
/fprettify/fparse_utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ###############################################################################
3 | # This file is part of fprettify.
4 | # Copyright (C) 2016-2019 Patrick Seewald, CP2K developers group
5 | #
6 | # fprettify is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # fprettify is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with fprettify. If not, see .
18 | ###############################################################################
19 |
20 | """This is a collection of Fortran parsing utilities."""
21 |
22 | import re
23 | from collections import deque
24 |
25 | RE_FLAGS = re.IGNORECASE | re.UNICODE
26 |
27 | # FIXME bad ass regex!
28 | VAR_DECL_RE = re.compile(
29 | r"^ *(?Pinteger(?: *\* *[0-9]+)?|logical|character(?: *\* *[0-9]+)?|real(?: *\* *[0-9]+)?|complex(?: *\* *[0-9]+)?|type) *(?P\((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*\))? *(?P(?: *, *[a-zA-Z_0-9]+(?: *\((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*\))?)+)? *(?P::)?(?P[^\n]+)\n?", RE_FLAGS)
30 |
31 | OMP_COND_RE = re.compile(r"^\s*(!\$ )", RE_FLAGS)
32 | OMP_DIR_RE = re.compile(r"^\s*(!\$OMP)", RE_FLAGS)
33 |
34 | # supported preprocessors
35 | FYPP_LINE_STR = r"^(#!|#:|\$:|@:)"
36 | FYPP_WITHOUT_PREPRO_STR = r"^(#!|\$:|@:)"
37 | CPP_STR = r"^#[^!:{}]"
38 | COMMENT_LINE_STR = r"^!"
39 | FYPP_OPEN_STR = r"(#{|\${|@{)"
40 | FYPP_CLOSE_STR = r"(}#|}\$|}@)"
41 | NOTFORTRAN_LINE_RE = re.compile(r"("+FYPP_LINE_STR+r"|"+CPP_STR+r"|"+COMMENT_LINE_STR+r")", RE_FLAGS)
42 | NOTFORTRAN_FYPP_LINE_RE = re.compile(r"("+CPP_STR+r"|"+COMMENT_LINE_STR+r")", RE_FLAGS)
43 | FYPP_LINE_RE = re.compile(FYPP_LINE_STR, RE_FLAGS)
44 | FYPP_WITHOUT_PREPRO_RE = re.compile(FYPP_WITHOUT_PREPRO_STR, RE_FLAGS)
45 | FYPP_OPEN_RE = re.compile(FYPP_OPEN_STR, RE_FLAGS)
46 | FYPP_CLOSE_RE = re.compile(FYPP_CLOSE_STR, RE_FLAGS)
47 |
48 | STR_OPEN_RE = re.compile(r"("+FYPP_OPEN_STR+r"|"+r"'|\"|!)", RE_FLAGS)
49 | CPP_RE = re.compile(CPP_STR, RE_FLAGS)
50 |
51 | class fline_parser(object):
52 | def __init__(self):
53 | pass
54 | def search(self, line):
55 | pass
56 |
57 | class parser_re(fline_parser):
58 | def __init__(self, regex, spec=True):
59 | self._re = regex
60 | self.spec = spec
61 |
62 | def search(self, line):
63 | return self._re.search(line)
64 |
65 | def split(self, line):
66 | return self._re.split(line)
67 |
68 | class FprettifyException(Exception):
69 | """Base class for all custom exceptions"""
70 |
71 | def __init__(self, msg, filename, line_nr):
72 | super(FprettifyException, self).__init__(msg)
73 | self.filename = filename
74 | self.line_nr = line_nr
75 |
76 |
77 | class FprettifyParseException(FprettifyException):
78 | """Exception for unparseable Fortran code (user's fault)."""
79 |
80 | pass
81 |
82 |
83 | class FprettifyInternalException(FprettifyException):
84 | """Exception for potential internal errors (fixme's)."""
85 |
86 | pass
87 |
88 |
89 | class CharFilter(object):
90 | """
91 | An iterator to wrap the iterator returned by `enumerate(string)`
92 | and ignore comments and characters inside strings
93 | """
94 |
95 | def __init__(self, string, filter_comments=True, filter_strings=True,
96 | filter_fypp=True):
97 | self._content = string
98 | self._it = enumerate(self._content)
99 | self._instring = ''
100 | self._infypp = False
101 | self._incomment = ''
102 | self._instring = ''
103 | self._filter_comments = filter_comments
104 | self._filter_strings = filter_strings
105 | if filter_fypp:
106 | self._notfortran_re = NOTFORTRAN_LINE_RE
107 | else:
108 | self._notfortran_re = NOTFORTRAN_FYPP_LINE_RE
109 |
110 |
111 | def update(self, string, filter_comments=True, filter_strings=True,
112 | filter_fypp=True):
113 | self._content = string
114 | self._it = enumerate(self._content)
115 | self._filter_comments = filter_comments
116 | self._filter_strings = filter_strings
117 | if filter_fypp:
118 | self._notfortran_re = NOTFORTRAN_LINE_RE
119 | else:
120 | self._notfortran_re = NOTFORTRAN_FYPP_LINE_RE
121 |
122 | def __iter__(self):
123 | return self
124 |
125 | def __next__(self):
126 |
127 | pos, char = next(self._it)
128 |
129 | char2 = self._content[pos:pos+2]
130 |
131 | if not self._instring:
132 | if not self._incomment:
133 | if FYPP_OPEN_RE.search(char2):
134 | self._instring = char2
135 | self._infypp = True
136 | elif (self._notfortran_re.search(char2)):
137 | self._incomment = char
138 | elif char in ['"', "'"]:
139 | self._instring = char
140 | else:
141 | if self._infypp:
142 | if FYPP_CLOSE_RE.search(char2):
143 | self._instring = ''
144 | self._infypp = False
145 | if self._filter_strings:
146 | self.__next__()
147 | return self.__next__()
148 |
149 | elif char in ['"', "'"]:
150 | if self._instring == char:
151 | self._instring = ''
152 | if self._filter_strings:
153 | return self.__next__()
154 |
155 | if self._filter_comments:
156 | if self._incomment:
157 | raise StopIteration
158 |
159 | if self._filter_strings:
160 | if self._instring:
161 | return self.__next__()
162 |
163 | return (pos, char)
164 |
165 | def filter_all(self):
166 | filtered_str = ''
167 | for pos, char in self:
168 | filtered_str += char
169 | return filtered_str
170 |
171 | def instring(self):
172 | return self._instring
173 |
174 | class InputStream(object):
175 | """Class to read logical Fortran lines from a Fortran file."""
176 |
177 | def __init__(self, infile, filter_fypp=True, orig_filename=None):
178 | if not orig_filename:
179 | orig_filename = infile.name
180 | self.line_buffer = deque([])
181 | self.infile = infile
182 | self.line_nr = 0
183 | self.filename = orig_filename
184 | self.endpos = deque([])
185 | self.what_omp = deque([])
186 | if filter_fypp:
187 | self.notfortran_re = NOTFORTRAN_LINE_RE
188 | else:
189 | self.notfortran_re = NOTFORTRAN_FYPP_LINE_RE
190 |
191 | def next_fortran_line(self):
192 | """Reads a group of connected lines (connected with &, separated by newline or semicolon)
193 | returns a touple with the joined line, and a list with the original lines.
194 | Doesn't support multiline character constants!
195 | """
196 | joined_line = ""
197 | comments = []
198 | lines = []
199 | continuation = 0
200 | fypp_cont = 0
201 | instring = ''
202 |
203 | string_iter = CharFilter('')
204 | fypp_cont = 0
205 | while 1:
206 | if not self.line_buffer:
207 | line = self.infile.readline().replace("\t", 8 * " ")
208 | self.line_nr += 1
209 | # convert OMP-conditional fortran statements into normal fortran statements
210 | # but remember to convert them back
211 |
212 | what_omp = OMP_COND_RE.search(line)
213 |
214 | if what_omp:
215 | what_omp = what_omp.group(1)
216 | else:
217 | what_omp = ''
218 |
219 | if what_omp:
220 | line = line.replace(what_omp, '', 1)
221 | line_start = 0
222 |
223 | pos = -1
224 |
225 | # multiline string: prepend line continuation with '&'
226 | if string_iter.instring() and not line.lstrip().startswith('&'):
227 | line = '&' + line
228 |
229 | # update instead of CharFilter(line) to account for multiline strings
230 | string_iter.update(line)
231 | for pos, char in string_iter:
232 | if char == ';' or pos + 1 == len(line):
233 | self.endpos.append(pos - line_start)
234 | self.line_buffer.append(line[line_start:pos + 1])
235 | self.what_omp.append(what_omp)
236 | what_omp = ''
237 | line_start = pos + 1
238 |
239 | if pos + 1 < len(line):
240 | if fypp_cont:
241 | self.endpos.append(-1)
242 | self.line_buffer.append(line)
243 | self.what_omp.append(what_omp)
244 | else:
245 | for pos_add, char in CharFilter(line[pos+1:], filter_comments=False):
246 | char2 = line[pos+1+pos_add:pos+3+pos_add]
247 | if self.notfortran_re.search(char2):
248 | self.endpos.append(pos + pos_add - line_start)
249 | self.line_buffer.append(line[line_start:])
250 | self.what_omp.append(what_omp)
251 | break
252 |
253 | if not self.line_buffer:
254 | self.endpos.append(len(line))
255 | self.line_buffer.append(line)
256 | self.what_omp.append('')
257 |
258 |
259 | line = self.line_buffer.popleft()
260 | endpos = self.endpos.popleft()
261 | what_omp = self.what_omp.popleft()
262 |
263 | if not line:
264 | break
265 |
266 | lines.append(what_omp + line)
267 |
268 | line_core = line[:endpos + 1]
269 |
270 | if self.notfortran_re.search(line[endpos+1:endpos+3]) or fypp_cont:
271 | line_comments = line[endpos + 1:]
272 | else:
273 | line_comments = ''
274 |
275 | if line_core:
276 | newline = (line_core[-1] == '\n')
277 | else:
278 | newline = False
279 |
280 | line_core = line_core.strip()
281 |
282 | if line_core and not NOTFORTRAN_LINE_RE.search(line_core):
283 | continuation = 0
284 | if line_core.endswith('&'):
285 | continuation = 1
286 |
287 | if line_comments:
288 | if (FYPP_LINE_RE.search(line[endpos+1:endpos+3]) or fypp_cont) and line_comments.strip()[-1] == '&':
289 | fypp_cont = 1
290 | else:
291 | fypp_cont = 0
292 |
293 | line_core = line_core.strip('&')
294 |
295 | comments.append(line_comments.rstrip('\n'))
296 | if joined_line.strip():
297 | joined_line = joined_line.rstrip(
298 | '\n') + line_core + '\n' * newline
299 | else:
300 | joined_line = what_omp + line_core + '\n' * newline
301 |
302 | if not (continuation or fypp_cont):
303 | break
304 |
305 | return (joined_line, comments, lines)
306 |
--------------------------------------------------------------------------------
/fprettify/tests/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | ###############################################################################
4 | # This file is part of fprettify.
5 | # Copyright (C) 2016-2019 Patrick Seewald, CP2K developers group
6 | #
7 | # fprettify is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # fprettify is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with fprettify. If not, see .
19 | ###############################################################################
20 |
21 | """Dynamically create tests based on examples in examples/before."""
22 | from __future__ import (absolute_import, division,
23 | print_function, unicode_literals)
24 |
25 | import sys
26 | import os
27 | import unittest
28 | import hashlib
29 | import logging
30 | import io
31 | import re
32 | import difflib
33 | import subprocess
34 | import inspect
35 |
36 | sys.stderr = io.TextIOWrapper(
37 | sys.stderr.detach(), encoding='UTF-8', line_buffering=True)
38 |
39 | import fprettify
40 | from fprettify.fparse_utils import FprettifyParseException, FprettifyInternalException
41 |
42 |
43 | def joinpath(path1, path2):
44 | return os.path.normpath(os.path.join(path1, path2))
45 |
46 | MYPATH = os.path.dirname(os.path.abspath(
47 | inspect.getfile(inspect.currentframe())))
48 |
49 | BEFORE_DIR = joinpath(MYPATH, r'../../fortran_tests/before/')
50 | AFTER_DIR = joinpath(MYPATH, r'../../fortran_tests/after/')
51 | RESULT_DIR = joinpath(MYPATH, r'../../fortran_tests/test_results/')
52 | RESULT_FILE = joinpath(RESULT_DIR, r'expected_results')
53 | FAILED_FILE = joinpath(RESULT_DIR, r'failed_results')
54 |
55 | RUNSCRIPT = joinpath(MYPATH, r"../../fprettify.py")
56 |
57 | fprettify.set_fprettify_logger(logging.ERROR)
58 |
59 |
60 | class AlienInvasion(Exception):
61 | """Should not happen"""
62 | pass
63 |
64 |
65 | def eprint(*args, **kwargs):
66 | """
67 | Print to stderr - to print output compatible with default unittest output.
68 | """
69 |
70 | print(*args, file=sys.stderr, flush=True, **kwargs)
71 |
72 | class FPrettifyTestCase(unittest.TestCase):
73 | """
74 | test class to be recognized by unittest.
75 | """
76 |
77 | def shortDescription(self):
78 | """don't print doc string of testmethod"""
79 | return None
80 |
81 | def setUp(self):
82 | """
83 | setUp to be recognized by unittest.
84 | We have large files to compare, raise the limit
85 | """
86 | self.maxDiff = None
87 |
88 | @classmethod
89 | def setUpClass(cls):
90 | """
91 | setUpClass to be recognized by unittest.
92 | """
93 |
94 | cls.n_success = 0
95 | cls.n_parsefail = 0
96 | cls.n_internalfail = 0
97 | cls.n_unexpectedfail = 0
98 |
99 | eprint("-" * 70)
100 | eprint("recognized Fortran files")
101 | eprint(", ".join(fprettify.FORTRAN_EXTENSIONS))
102 | eprint("-" * 70)
103 | eprint("Testing with Fortran files in " + BEFORE_DIR)
104 | eprint("Writing formatted Fortran files to " + AFTER_DIR)
105 | eprint("Storing expected results in " + RESULT_FILE)
106 | eprint("Storing failed results in " + FAILED_FILE)
107 | eprint("-" * 70)
108 |
109 | @classmethod
110 | def tearDownClass(cls):
111 | """
112 | tearDownClass to be recognized by unittest. Used for test summary
113 | output.
114 | """
115 | if cls.n_parsefail + cls.n_internalfail > 0:
116 | format = "{:<20}{:<6}"
117 | eprint('\n' + "=" * 70)
118 | eprint("IGNORED errors: invalid or old Fortran")
119 | eprint("-" * 70)
120 | eprint(format.format("parse errors: ", cls.n_parsefail))
121 | eprint(format.format("internal errors: ", cls.n_internalfail))
122 |
123 | @staticmethod
124 | def write_result(filename, content, sep_str): # pragma: no cover
125 | with io.open(filename, 'a', encoding='utf-8') as outfile:
126 | outfile.write(sep_str.join(content) + '\n')
127 |
128 | def test_whitespace(self):
129 | """simple test for whitespace formatting options -w in [0, 1, 2]"""
130 | instring = "(/-a-b-(a+b-c)/(-c)*d**e,f[1]%v/)"
131 | outstring_exp = ["(/-a-b-(a+b-c)/(-c)*d**e,f[1]%v/)",
132 | "(/-a-b-(a+b-c)/(-c)*d**e, f[1]%v/)",
133 | "(/-a - b - (a + b - c)/(-c)*d**e, f[1]%v/)",
134 | "(/-a - b - (a + b - c) / (-c) * d**e, f[1]%v/)"]
135 |
136 | outstring = []
137 | for w, out in zip(range(0, 4), outstring_exp):
138 | args = ['-w', str(w)]
139 | self.assert_fprettify_result(args, instring, out)
140 |
141 | def test_type_selector(self):
142 | """test for whitespace formatting option -w 4"""
143 | instring = "A%component=func(mytype%a,mytype%abc+mytype%abcd)"
144 | outstring_exp = "A % component = func(mytype % a, mytype % abc + mytype % abcd)"
145 |
146 | self.assert_fprettify_result(['-w 4'], instring, outstring_exp)
147 |
148 | def test_indent(self):
149 | """simple test for indent options -i in [0, 3, 4]"""
150 |
151 | indents = [0, 3, 4]
152 |
153 | instring = "iF(teSt)ThEn\nCaLl subr(a,b,&\nc,(/d,&\ne,f/))\nEnD iF"
154 | outstring_exp = [
155 | "iF (teSt) ThEn\n" +
156 | " " * ind + "CaLl subr(a, b, &\n" +
157 | " " * (10 + ind) + "c, (/d, &\n" +
158 | " " * (15 + ind) + "e, f/))\nEnD iF"
159 | for ind in indents
160 | ]
161 |
162 | for ind, out in zip(indents, outstring_exp):
163 | args = ['-i', str(ind)]
164 | self.assert_fprettify_result(args, instring, out)
165 |
166 | def test_nested(self):
167 | """test correct indentation of nested loops"""
168 | instring = ("integer :: i,j\ndo i=1,2\ndo j=1,3\n"
169 | "print*,i,j,i*j\nend do\nend do")
170 | outstring_exp_default = ("integer :: i, j\ndo i = 1, 2\ndo j = 1, 3\n"
171 | " print *, i, j, i*j\nend do\nend do")
172 | outstring_exp_strict = ("integer :: i, j\ndo i = 1, 2\n do j = 1, 3\n"
173 | " print *, i, j, i*j\n end do\nend do")
174 |
175 | self.assert_fprettify_result([], instring, outstring_exp_default)
176 | self.assert_fprettify_result(['--strict-indent'], instring, outstring_exp_strict)
177 |
178 | def test_reset_indent(self):
179 | """test of reset indentation at file start"""
180 | instring = ("integer :: i,j\ndo i=1,2\ndo j=1,3\n"
181 | "print*,i,j,i*j\nend do\nend do",
182 | " module a\ninteger :: 1\n")
183 | outstring = ("integer :: i, j\ndo i = 1, 2\ndo j = 1, 3\n"
184 | " print *, i, j, i*j\nend do\nend do",
185 | "module a\n integer :: 1")
186 |
187 | for ind, out in zip(instring, outstring):
188 | self.assert_fprettify_result([],ind, out)
189 |
190 | def test_disable(self):
191 | """test disabling indentation and/or whitespace formatting"""
192 | instring = ("if(&\nl==111)&\n then\n do m =1, 2\n A=&\nB+C\n end do; endif")
193 | outstring_exp_default = ("if ( &\n l == 111) &\n then\n do m = 1, 2\n"
194 | " A = &\n B + C\n end do; end if")
195 | outstring_exp_nowhitespace = ("if(&\n l==111)&\n then\n do m =1, 2\n"
196 | " A=&\n B+C\n end do; endif")
197 | outstring_exp_noindent = ("if ( &\nl == 111) &\n then\n do m = 1, 2\n"
198 | " A = &\nB + C\n end do; end if")
199 |
200 | self.assert_fprettify_result([], instring, outstring_exp_default)
201 | self.assert_fprettify_result(['--disable-whitespace'], instring, outstring_exp_nowhitespace)
202 | self.assert_fprettify_result(['--disable-indent'], instring, outstring_exp_noindent)
203 | self.assert_fprettify_result(['--disable-indent', '--disable-whitespace'], instring, instring)
204 |
205 | def test_comments(self):
206 | """test options related to comments"""
207 | instring = ("TYPE mytype\n! c1\n !c2\n INTEGER :: a ! c3\n"
208 | " REAL :: b, & ! c4\n! c5\n ! c6\n"
209 | " d ! c7\nEND TYPE ! c8")
210 | outstring_exp_default = ("TYPE mytype\n! c1\n !c2\n INTEGER :: a ! c3\n"
211 | " REAL :: b, & ! c4\n ! c5\n ! c6\n"
212 | " d ! c7\nEND TYPE ! c8")
213 | outstring_exp_strip = ("TYPE mytype\n! c1\n !c2\n INTEGER :: a ! c3\n"
214 | " REAL :: b, & ! c4\n ! c5\n ! c6\n"
215 | " d ! c7\nEND TYPE ! c8")
216 |
217 | self.assert_fprettify_result([], instring, outstring_exp_default)
218 | self.assert_fprettify_result(['--strip-comments'], instring, outstring_exp_strip)
219 |
220 | def test_directive(self):
221 | """
222 | test deactivate directives '!&' (inline) and '!&<', '!&>' (block)
223 | and manual alignment (continuation line prefixed with '&')
224 | """
225 |
226 | # manual alignment
227 | instring = "align_me = [ -1, 10,0, &\n & 0,1000 , 0,&\n &0 , -1, 1]"
228 | outstring_exp = "align_me = [-1, 10, 0, &\n & 0, 1000, 0,&\n &0, -1, 1]"
229 | self.assert_fprettify_result([], instring, outstring_exp)
230 |
231 | # inline deactivate
232 | instring2 = '\n'.join(_ + ' !&' for _ in instring.splitlines())
233 | outstring_exp = instring2
234 | self.assert_fprettify_result([], instring2, outstring_exp)
235 |
236 | # block deactivate
237 | instring3 = '!&<\n' + instring + '\n!&>'
238 | outstring_exp = instring3
239 | self.assert_fprettify_result([], instring3, outstring_exp)
240 |
241 | def assert_fprettify_result(self, args, instring, outstring_exp):
242 | """
243 | assert that result of calling fprettify with args on instring gives
244 | outstring_exp
245 | """
246 | args.insert(0, RUNSCRIPT)
247 | p1 = subprocess.Popen(
248 | args, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
249 | outstring = p1.communicate(instring.encode(
250 | 'UTF-8'))[0].decode('UTF-8').rstrip()
251 | self.assertEqual(outstring_exp.rstrip(), outstring)
252 |
253 | def test_io(self):
254 | """simple test for io (file inplace, stdin & stdout)"""
255 |
256 | # io and unicode
257 | outstring = []
258 | instring = "CALL alien_invasion( 👽 )"
259 | outstring_exp = "CALL alien_invasion(👽)"
260 |
261 | alien_file = "alien_invasion.f90"
262 | if os.path.isfile(alien_file):
263 | raise AlienInvasion(
264 | "remove file alien_invasion.f90") # pragma: no cover
265 |
266 | try:
267 | with io.open(alien_file, 'w', encoding='utf-8') as infile:
268 | infile.write(instring)
269 |
270 | # testing stdin --> stdout
271 | p1 = subprocess.Popen(RUNSCRIPT,
272 | stdout=subprocess.PIPE, stdin=subprocess.PIPE)
273 | outstring.append(p1.communicate(
274 | instring.encode('UTF-8'))[0].decode('UTF-8'))
275 |
276 | # testing file --> stdout
277 | p1 = subprocess.Popen([RUNSCRIPT, alien_file, '--stdout'],
278 | stdout=subprocess.PIPE)
279 | outstring.append(p1.communicate(
280 | instring.encode('UTF-8')[0])[0].decode('UTF-8'))
281 |
282 | # testing file --> file (inplace)
283 | p1 = subprocess.Popen([RUNSCRIPT, alien_file])
284 | p1.wait()
285 |
286 | with io.open(alien_file, 'r', encoding='utf-8') as infile:
287 | outstring.append(infile.read())
288 |
289 | for outstr in outstring:
290 | self.assertEqual(outstring_exp, outstr.strip())
291 | except: # pragma: no cover
292 | if os.path.isfile(alien_file):
293 | os.remove(alien_file)
294 | raise
295 | else:
296 | os.remove(alien_file)
297 |
298 | def test_multi_alias(self):
299 | """test for issue #11 (multiple alias and alignment)"""
300 | instring="use A,only:B=>C,&\nD=>E"
301 | outstring="use A, only: B => C, &\n D => E"
302 | self.assert_fprettify_result([], instring, outstring)
303 |
304 | def test_use(self):
305 | """test for alignment of use statements"""
306 | instring1="use A,only:B,C,&\nD,E"
307 | instring2="use A,only:&\nB,C,D,E"
308 | outstring1="use A, only: B, C, &\n D, E"
309 | outstring2="use A, only: &\n B, C, D, E"
310 | self.assert_fprettify_result([], instring1, outstring1)
311 | self.assert_fprettify_result([], instring2, outstring2)
312 |
313 | def test_wrongkind(self):
314 | """test whitespacing of deprecated kind definition"""
315 | instring = ["REAL*8 :: r, f ! some reals",
316 | "REAL * 8 :: r, f ! some reals",
317 | "INTEGER * 4 :: c, i ! some integers",
318 | "INTEGER*4 :: c, i ! some integers"]
319 | outstring = ["REAL*8 :: r, f ! some reals",
320 | "REAL*8 :: r, f ! some reals",
321 | "INTEGER*4 :: c, i ! some integers",
322 | "INTEGER*4 :: c, i ! some integers"]
323 |
324 | for i in range(0, len(instring)):
325 | self.assert_fprettify_result([], instring[i], outstring[i])
326 |
327 | def test_new_intrinsics(self):
328 | """test new I/O intrinsics"""
329 | instring = ["REWIND(12)",
330 | "BACKSPACE(13)",
331 | "INQUIRE(14)"]
332 | outstring = ["REWIND (12)",
333 | "BACKSPACE (13)",
334 | "INQUIRE (14)"]
335 |
336 | for i in range(0, len(instring)):
337 | self.assert_fprettify_result([], instring[i], outstring[i])
338 |
339 | def test_associate(self):
340 | """test correct formatting of associate construct"""
341 | instring = ("associate(a=>b , c =>d ,e=> f )\n"
342 | "e=a+c\n"
343 | "end associate")
344 | outstring = ("associate (a => b, c => d, e => f)\n"
345 | " e = a + c\n"
346 | "end associate")
347 |
348 | self.assert_fprettify_result([], instring, outstring)
349 |
350 | def test_line_length(self):
351 | """test line length option"""
352 | instring = ["REAL(KIND=4) :: r,f ! some reals",
353 | "if( min == max.and.min .eq. thres )",
354 | "INQUIRE(14)"]
355 | instring_ = "if( min == max.and.min .eq. thres ) one_really_long_function_call_to_hit_the_line_limit(parameter1, parameter2,parameter3,parameter4,parameter5,err) ! this line would be too long"
356 | outstring = ["REAL(KIND=4) :: r, f ! some reals",
357 | "REAL(KIND=4) :: r,f ! some reals",
358 | "if (min == max .and. min .eq. thres)",
359 | "if( min == max.and.min .eq. thres )",
360 | "INQUIRE (14)",
361 | "INQUIRE (14)"]
362 | outstring_ = ["if( min == max.and.min .eq. thres ) one_really_long_function_call_to_hit_the_line_limit(parameter1, parameter2,parameter3,parameter4,parameter5,err) ! this line would be too long",
363 | "if (min == max .and. min .eq. thres) one_really_long_function_call_to_hit_the_line_limit(parameter1, parameter2, parameter3, parameter4, parameter5, err) ! this line would be too long"]
364 |
365 | # test shorter lines first, after all the actual length doesn't matter
366 | for i in range(0, len(instring)):
367 | self.assert_fprettify_result(['-S'], instring[i], outstring[2*i])
368 | self.assert_fprettify_result(['-S', '-l 20'], instring[i], outstring[2*i + 1])
369 | # now test a long line
370 | self.assert_fprettify_result(['-S'], instring_, outstring_[0])
371 | self.assert_fprettify_result(['-S', '-l 0'], instring_, outstring_[1])
372 |
373 | def test_relation_replacement(self):
374 | """test replacement of relational statements"""
375 | instring = ["if ( min < max .and. min .lt. thres)",
376 | "if (min > max .and. min .gt. thres )",
377 | "if ( min == max .and. min .eq. thres )",
378 | "if(min /= max .and. min .ne. thres)",
379 | "if(min >= max .and. min .ge. thres )",
380 | "if( min <= max .and. min .le. thres)",
381 | "'==== heading",
382 | "if (vtk%my_rank .eq. 0) write (vtk%filehandle_par, '(\"\",",
384 | "if (abc(1) .lt. -bca .or. &\n qwe .gt. ewq) then"]
385 | f_outstring = ["if (min .lt. max .and. min .lt. thres)",
386 | "if (min .gt. max .and. min .gt. thres)",
387 | "if (min .eq. max .and. min .eq. thres)",
388 | "if (min .ne. max .and. min .ne. thres)",
389 | "if (min .ge. max .and. min .ge. thres)",
390 | "if (min .le. max .and. min .le. thres)",
391 | "'==== heading",
392 | "if (vtk%my_rank .eq. 0) write (vtk%filehandle_par, '(\"\",",
394 | "if (abc(1) .lt. -bca .or. &\n qwe .gt. ewq) then"]
395 | c_outstring = ["if (min < max .and. min < thres)",
396 | "if (min > max .and. min > thres)",
397 | "if (min == max .and. min == thres)",
398 | "if (min /= max .and. min /= thres)",
399 | "if (min >= max .and. min >= thres)",
400 | "if (min <= max .and. min <= thres)",
401 | "'==== heading",
402 | "if (vtk%my_rank == 0) write (vtk%filehandle_par, '(\"\",",
404 | "if (abc(1) < -bca .or. &\n qwe > ewq) then"]
405 | for i in range(0, len(instring)):
406 | self.assert_fprettify_result(['--enable-replacements', '--c-relations'], instring[i], c_outstring[i])
407 | self.assert_fprettify_result(['--enable-replacements'], instring[i], f_outstring[i])
408 |
409 | def test_swap_case(self):
410 | """test replacement of keyword character case"""
411 | instring = (
412 | "MODULE exAmple",
413 | "INTEGER, PARAMETER :: SELECTED_REAL_KIND = 1*2",
414 | "INTEGER, PARAMETER :: dp1 = SELECTED_REAL_KIND ( 15 , 307)",
415 | 'CHARACTER(LEN=*), PARAMETER :: a = "INTEGER, PARAMETER" // "b"',
416 | "CHARACTER(LEN=*), PARAMETER :: a = 'INTEGER, PARAMETER' // 'b'",
417 | "INTEGER(kind=int64), PARAMETER :: l64 = 2_int64",
418 | "REAL(kind=real64), PARAMETER :: r64a = 2._real64",
419 | "REAL(kind=real64), PARAMETER :: r64b = 2.0_real64",
420 | "REAL(kind=real64), PARAMETER :: r64c = .0_real64",
421 | "REAL(kind=real64), PARAMETER :: r64a = 2.e3_real64",
422 | "REAL(kind=real64), PARAMETER :: r64b = 2.0e3_real64",
423 | "REAL(kind=real64), PARAMETER :: r64c = .0e3_real64",
424 | "REAL, PARAMETER :: r32 = 2.e3",
425 | "REAL, PARAMETER :: r32 = 2.0d3",
426 | "REAL, PARAMETER :: r32 = .2e3",
427 | "USE ISO_FORTRAN_ENV, ONLY: int64",
428 | "INTEGER, INTENT(IN) :: r, i, j, k",
429 | "IF (l.EQ.2) l=MAX (l64, 2_int64)",
430 | "PURE SUBROUTINE mypure()"
431 | )
432 | outstring = (
433 | "module exAmple",
434 | "integer, parameter :: SELECTED_REAL_KIND = 1*2",
435 | "integer, parameter :: dp1 = selected_real_kind(15, 307)",
436 | 'character(LEN=*), parameter :: a = "INTEGER, PARAMETER"//"b"',
437 | "character(LEN=*), parameter :: a = 'INTEGER, PARAMETER'//'b'",
438 | "integer(kind=INT64), parameter :: l64 = 2_INT64",
439 | "real(kind=REAL64), parameter :: r64a = 2._REAL64",
440 | "real(kind=REAL64), parameter :: r64b = 2.0_REAL64",
441 | "real(kind=REAL64), parameter :: r64c = .0_REAL64",
442 | "real(kind=REAL64), parameter :: r64a = 2.E3_REAL64",
443 | "real(kind=REAL64), parameter :: r64b = 2.0E3_REAL64",
444 | "real(kind=REAL64), parameter :: r64c = .0E3_REAL64",
445 | "real, parameter :: r32 = 2.E3",
446 | "real, parameter :: r32 = 2.0D3",
447 | "real, parameter :: r32 = .2E3",
448 | "use iso_fortran_env, only: INT64",
449 | "integer, intent(IN) :: r, i, j, k",
450 | "if (l .eq. 2) l = max(l64, 2_INT64)",
451 | "pure subroutine mypure()"
452 | )
453 | for i in range(len(instring)):
454 | self.assert_fprettify_result(['--case', '1', '1', '1', '2'],
455 | instring[i], outstring[i])
456 |
457 | def test_do(self):
458 | """test correct parsing of do statement"""
459 | instring = "do = 1\nb = 2"
460 |
461 | self.assert_fprettify_result([], instring, instring)
462 |
463 | def test_omp(self):
464 | """test formatting of omp directives"""
465 | instring = ("PROGRAM test_omp\n"
466 | " !$OMP PARALLEL DO\n"
467 | "b=4\n"
468 | "!$a=b\n"
469 | "!$ a=b\n"
470 | " !$ c=b\n"
471 | "!$acc parallel loop\n"
472 | "!$OMP END PARALLEL DO\n"
473 | "END PROGRAM")
474 | outstring = ("PROGRAM test_omp\n"
475 | "!$OMP PARALLEL DO\n"
476 | " b = 4\n"
477 | "!$a=b\n"
478 | "!$ a = b\n"
479 | "!$ c = b\n"
480 | "!$acc parallel loop\n"
481 | "!$OMP END PARALLEL DO\n"
482 | "END PROGRAM")
483 |
484 | self.assert_fprettify_result([], instring, outstring)
485 |
486 | def test_ford(self):
487 | """test formatting of ford comments"""
488 | instring = (" a = b\n"
489 | " !! ford docu\n"
490 | "b=c\n"
491 | " !! ford docu\n"
492 | "subroutine test(a,b,&\n"
493 | " !! ford docu\n"
494 | " c, d, e)"
495 | )
496 | outstring = (" a = b\n"
497 | " !! ford docu\n"
498 | " b = c\n"
499 | " !! ford docu\n"
500 | " subroutine test(a, b, &\n"
501 | " !! ford docu\n"
502 | " c, d, e)"
503 | )
504 |
505 | self.assert_fprettify_result([], instring, outstring)
506 |
507 | def test_plusminus(self):
508 | """test corner cases of +/-"""
509 | instring = "val_1d-1-1.0e-9-2.0d-08+.2e-1-val_2d-3.e-12+4"
510 | outstring = "val_1d - 1 - 1.0e-9 - 2.0d-08 + .2e-1 - val_2d - 3.e-12 + 4"
511 | self.assert_fprettify_result([], instring, outstring)
512 |
513 | def test_fypp(self):
514 | """test formatting of fypp statements"""
515 |
516 | instring = []
517 | outstring = []
518 |
519 | instring += [
520 | """
521 | #:if DEBUG> 0
522 | print *, "hola"
523 | if( .not. (${cond}$) ) then
524 | #:if ASSERT(cond)
525 | print *, "Assert failed!"
526 | #:endif
527 | error stop
528 | end if
529 | #:endif
530 | """
531 | ]
532 |
533 | outstring += [
534 | """
535 | #:if DEBUG> 0
536 | print *, "hola"
537 | if (.not. (${cond}$)) then
538 | #:if ASSERT(cond)
539 | print *, "Assert failed!"
540 | #:endif
541 | error stop
542 | end if
543 | #:endif
544 | """
545 | ]
546 |
547 | instring += [
548 | """
549 | if (.not. (${cond}$)) then
550 | #:for element in list
551 | print *, "Element is in list!"
552 | #:endfor
553 | error stop
554 | end if
555 | """
556 | ]
557 |
558 | outstring += [
559 | """
560 | if (.not. (${cond}$)) then
561 | #:for element in list
562 | print *, "Element is in list!"
563 | #:endfor
564 | error stop
565 | end if
566 | """
567 | ]
568 |
569 | instring += [
570 | """
571 | #:if aa > 1
572 | print *, "Number is more than 1"
573 | if (condition) then
574 | #:def something
575 | print *, "Added Definition!"
576 | #:enddef
577 | end if
578 | #:endif
579 | """
580 | ]
581 |
582 | outstring += [
583 | """
584 | #:if aa > 1
585 | print *, "Number is more than 1"
586 | if (condition) then
587 | #:def something
588 | print *, "Added Definition!"
589 | #:enddef
590 | end if
591 | #:endif
592 | """
593 | ]
594 |
595 | instring += [
596 | """
597 | #:def DEBUG_CODE( code)
598 | #:if DEBUG > 0
599 | $:code
600 | #:endif
601 | #:enddef DEBUG_CODE
602 | """
603 | ]
604 |
605 | outstring += [
606 | """
607 | #:def DEBUG_CODE( code)
608 | #:if DEBUG > 0
609 | $:code
610 | #:endif
611 | #:enddef DEBUG_CODE
612 | """
613 | ]
614 |
615 |
616 | instring += [
617 | """
618 | #:block DEBUG_CODE
619 | if (a 0
659 | print *, "hola"
660 | if (.not. (${cond}$)) then
661 | #:mute
662 | print *, "Muted"
663 | #:endmute
664 | error stop
665 | end if
666 | #:endif
667 | """
668 | ]
669 |
670 | outstring += [
671 | """
672 | #:if DEBUG > 0
673 | print *, "hola"
674 | if (.not. (${cond}$)) then
675 | #:mute
676 | print *, "Muted"
677 | #:endmute
678 | error stop
679 | end if
680 | #:endif
681 | """
682 | ]
683 |
684 | instring += [
685 | """
686 | program try
687 | #:def mydef
688 | a = &
689 | #:if dothat
690 | b + &
691 | #:else
692 | c + &
693 | #:endif
694 | d
695 | #:enddef
696 | end program
697 | """
698 | ]
699 |
700 | outstring += [
701 | """
702 | program try
703 | #:def mydef
704 | a = &
705 | #:if dothat
706 | b + &
707 | #:else
708 | c + &
709 | #:endif
710 | d
711 | #:enddef
712 | end program
713 | """
714 | ]
715 |
716 | instring += [
717 | """
718 | #:if worktype
719 | ${worktype}$, &
720 | #:else
721 | ${type}$, &
722 | #:endif
723 | DIMENSION(${arr_exp}$), &
724 | POINTER :: work
725 | """
726 | ]
727 |
728 | outstring += [
729 | """
730 | #:if worktype
731 | ${worktype}$, &
732 | #:else
733 | ${type}$, &
734 | #:endif
735 | DIMENSION(${arr_exp}$), &
736 | POINTER :: work
737 | """
738 | ]
739 |
740 |
741 |
742 | for instr, outstr in zip(instring, outstring):
743 | self.assert_fprettify_result([], instr, outstr)
744 |
745 | def test_mod(self):
746 | """test indentation of module / program"""
747 | instring_mod = "module my_module\nintrinsic none\ncontains\nfunction my_func()\nend\nend module"
748 | instring_prog = "program my_program\nintrinsic none\ncontains\nfunction my_func()\nend\nend program"
749 |
750 | outstring_mod = "module my_module\n intrinsic none\ncontains\n function my_func()\n end\nend module"
751 | outstring_mod_disable = "module my_module\nintrinsic none\ncontains\nfunction my_func()\nend\nend module"
752 |
753 | outstring_prog = "program my_program\n intrinsic none\ncontains\n function my_func()\n end\nend program"
754 | outstring_prog_disable = "program my_program\nintrinsic none\ncontains\nfunction my_func()\nend\nend program"
755 |
756 | self.assert_fprettify_result([], instring_mod, outstring_mod)
757 | self.assert_fprettify_result([], instring_prog, outstring_prog)
758 |
759 | self.assert_fprettify_result(['--disable-indent-mod'], instring_mod, outstring_mod_disable)
760 | self.assert_fprettify_result(['--disable-indent-mod'], instring_prog, outstring_prog_disable)
761 |
762 | def test_decl(self):
763 | """test formatting of declarations"""
764 | instring_1 = "integer :: a"
765 | instring_2 = "integer, dimension(:) :: a"
766 | outstring_1 = "integer :: a"
767 | outstring_2 = "integer, dimension(:) :: a"
768 | outstring_2_min = "integer, dimension(:)::a"
769 |
770 | self.assert_fprettify_result([], instring_1, instring_1)
771 | self.assert_fprettify_result([], instring_2, instring_2)
772 | self.assert_fprettify_result(['--enable-decl'], instring_1, outstring_1)
773 | self.assert_fprettify_result(['--enable-decl'], instring_2, outstring_2)
774 | self.assert_fprettify_result(['--enable-decl', '--whitespace-decl=0'], instring_2, outstring_2_min)
775 |
776 | def test_statement_label(self):
777 | instring = "1003 FORMAT(2(1x, i4), 5x, '-', 5x, '-', 3x, '-', 5x, '-', 5x, '-', 8x, '-', 3x, &\n 1p, 2(1x, d10.3))"
778 | outstring = "1003 FORMAT(2(1x, i4), 5x, '-', 5x, '-', 3x, '-', 5x, '-', 5x, '-', 8x, '-', 3x, &\n 1p, 2(1x, d10.3))"
779 | self.assert_fprettify_result([], instring, outstring)
780 |
781 | instring = "print *, 'hello'\n1003 FORMAT(2(1x, i4), 5x, '-', 5x, '-', 3x, '-', 5x, '-', 5x, '-', 8x, '-', 3x, &\n 1p, 2(1x, d10.3))"
782 | outstring = "print *, 'hello'\n1003 FORMAT(2(1x, i4), 5x, '-', 5x, '-', 3x, '-', 5x, '-', 5x, '-', 8x, '-', 3x, &\n 1p, 2(1x, d10.3))"
783 | self.assert_fprettify_result([], instring, outstring)
784 |
785 | def test_multiline_str(self):
786 |
787 | instring = []
788 | outstring = []
789 |
790 | instring += [
791 | '''
792 | CHARACTER(len=*), PARAMETER :: serialized_string = &
793 | "qtb_rng_gaussian 1 F T F 0.0000000000000000E+00&
794 | 12.0 12.0 12.0&
795 | 12.0 12.0 12.0&
796 | 12.0 12.0 12.0&
797 | 12.0 12.0 12.0&
798 | 12.0 12.0 12.0&
799 | 12.0 12.0 12.0"
800 | '''
801 | ]
802 |
803 | outstring += [
804 | '''
805 | CHARACTER(len=*), PARAMETER :: serialized_string = &
806 | "qtb_rng_gaussian 1 F T F 0.0000000000000000E+00&
807 | & 12.0 12.0 12.0&
808 | & 12.0 12.0 12.0&
809 | & 12.0 12.0 12.0&
810 | & 12.0 12.0 12.0&
811 | & 12.0 12.0 12.0&
812 | & 12.0 12.0 12.0"
813 | '''
814 | ]
815 |
816 | instring += [
817 | '''
818 | CHARACTER(len=*), PARAMETER :: serialized_string = &
819 | "qtb_rng_gaussian 1 F T F 0.0000000000000000E+00&
820 | & 12.0 12.0 12.0&
821 | & 12.0 12.0 12.0&
822 | & 12.0 12.0 12.0&
823 | & 12.0 12.0 12.0&
824 | & 12.0 12.0 12.0&
825 | & 12.0 12.0 12.0"
826 | '''
827 | ]
828 |
829 | outstring += [
830 | '''
831 | CHARACTER(len=*), PARAMETER :: serialized_string = &
832 | "qtb_rng_gaussian 1 F T F 0.0000000000000000E+00&
833 | & 12.0 12.0 12.0&
834 | & 12.0 12.0 12.0&
835 | & 12.0 12.0 12.0&
836 | & 12.0 12.0 12.0&
837 | & 12.0 12.0 12.0&
838 | & 12.0 12.0 12.0"
839 | '''
840 | ]
841 |
842 | for instr, outstr in zip(instring, outstring):
843 | self.assert_fprettify_result([], instr, outstr)
844 |
845 | def test_label(self):
846 | instring = \
847 | """
848 | MODULE cp_lbfgs
849 | CONTAINS
850 | 20000 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
851 | & 'it = iteration number', /, &
852 | & 'Machine precision =', 1p, d10.3)
853 | 2 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
854 | & 'it = iteration number', /, &
855 | & 'Machine precision =', 1p, d10.3)
856 | 20000 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
857 | 'it = iteration number', /, &
858 | 'Machine precision =', 1p, d10.3)
859 | 2 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
860 | 'it = iteration number', /, &
861 | 'Machine precision =', 1p, d10.3)
862 | END MODULE
863 | """
864 |
865 | outstring = \
866 | """
867 | MODULE cp_lbfgs
868 | CONTAINS
869 | 20000 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
870 | & 'it = iteration number', /, &
871 | & 'Machine precision =', 1p, d10.3)
872 | 2 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
873 | & 'it = iteration number', /, &
874 | & 'Machine precision =', 1p, d10.3)
875 | 20000 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
876 | 'it = iteration number', /, &
877 | 'Machine precision =', 1p, d10.3)
878 | 2 FORMAT('RUNNING THE L-BFGS-B CODE', /, /, &
879 | 'it = iteration number', /, &
880 | 'Machine precision =', 1p, d10.3)
881 | END MODULE
882 | """
883 |
884 | self.assert_fprettify_result([], instring, outstring)
885 |
886 |
887 |
888 | def addtestmethod(testcase, fpath, ffile):
889 | """add a test method for each example."""
890 |
891 | def testmethod(testcase):
892 | """this is the test method invoked for each example."""
893 |
894 | dirpath_before = joinpath(BEFORE_DIR, fpath)
895 | dirpath_after = joinpath(AFTER_DIR, fpath)
896 | if not os.path.exists(dirpath_after):
897 | os.makedirs(dirpath_after)
898 |
899 | example_before = joinpath(dirpath_before, ffile)
900 | example_after = joinpath(dirpath_after, ffile)
901 |
902 | if os.path.isfile(example_after):
903 | os.remove(example_after)
904 |
905 | def test_result(path, info):
906 | return [os.path.relpath(path, BEFORE_DIR), info]
907 |
908 | with io.open(example_before, 'r', encoding='utf-8') as infile:
909 |
910 | outstring = io.StringIO()
911 |
912 | try:
913 | fprettify.reformat_ffile(infile, outstring)
914 | m = hashlib.sha256()
915 | m.update(outstring.getvalue().encode('utf-8'))
916 |
917 | test_info = "checksum"
918 | test_content = test_result(example_before, m.hexdigest())
919 |
920 | with io.open(example_after, 'w', encoding='utf-8') as outfile:
921 | outfile.write(outstring.getvalue())
922 | FPrettifyTestCase.n_success += 1
923 | except FprettifyParseException as e:
924 | test_info = "parse error"
925 | fprettify.log_exception(e, test_info)
926 | test_content = test_result(example_before, test_info)
927 | FPrettifyTestCase.n_parsefail += 1
928 | except FprettifyInternalException as e:
929 | test_info = "internal error"
930 | fprettify.log_exception(e, test_info)
931 | test_content = test_result(example_before, test_info)
932 | FPrettifyTestCase.n_internalfail += 1
933 | except: # pragma: no cover
934 | FPrettifyTestCase.n_unexpectedfail += 1
935 | raise
936 |
937 | after_exists = os.path.isfile(example_after)
938 | if after_exists:
939 | with io.open(example_before, 'r', encoding='utf-8') as infile:
940 | before_content = infile.read()
941 | before_nosp = re.sub(
942 | r'\n{3,}', r'\n\n', before_content.lower().replace(' ', '').replace('\t', ''))
943 |
944 | with io.open(example_after, 'r', encoding='utf-8') as outfile:
945 | after_content = outfile.read()
946 | after_nosp = after_content.lower().replace(' ', '')
947 |
948 | testcase.assertMultiLineEqual(before_nosp, after_nosp)
949 |
950 | sep_str = ' : '
951 | with io.open(RESULT_FILE, 'r', encoding='utf-8') as infile:
952 | found = False
953 | for line in infile:
954 | line_content = line.strip().split(sep_str)
955 | if line_content[0] == test_content[0]:
956 | found = True
957 | eprint(test_info, end=" ")
958 | msg = '{} (old) != {} (new)'.format(
959 | line_content[1], test_content[1])
960 | if test_info == "checksum" and after_exists and after_content.count('\n') < 10000:
961 | # difflib can not handle large files
962 | result = list(difflib.unified_diff(before_content.splitlines(
963 | True), after_content.splitlines(True), fromfile=test_content[0], tofile=line_content[0]))
964 | msg += '\n' + ''.join(result)
965 | try:
966 | testcase.assertEqual(
967 | line_content[1], test_content[1], msg)
968 | except AssertionError: # pragma: no cover
969 | FPrettifyTestCase.write_result(
970 | FAILED_FILE, test_content, sep_str)
971 | raise
972 | break
973 |
974 | if not found: # pragma: no cover
975 | eprint(test_info + " new", end=" ")
976 | FPrettifyTestCase.write_result(RESULT_FILE, test_content, sep_str)
977 |
978 | # not sure why this even works, using "test something" (with a space) as function name...
979 | # however it gives optimal test output
980 | testmethod.__name__ = ("test " + joinpath(fpath, ffile))
981 |
982 | setattr(testcase, testmethod.__name__, testmethod)
983 |
984 | # make sure all directories exist
985 | if not os.path.exists(BEFORE_DIR): # pragma: no cover
986 | os.makedirs(BEFORE_DIR)
987 | if not os.path.exists(AFTER_DIR): # pragma: no cover
988 | os.makedirs(AFTER_DIR)
989 | if not os.path.exists(RESULT_DIR): # pragma: no cover
990 | os.makedirs(RESULT_DIR)
991 | if not os.path.exists(RESULT_FILE): # pragma: no cover
992 | io.open(RESULT_FILE, 'w', encoding='utf-8').close()
993 | if os.path.exists(FAILED_FILE): # pragma: no cover
994 | # erase failures from previous testers
995 | io.open(FAILED_FILE, 'w', encoding='utf-8').close()
996 |
997 | # this prepares FPrettifyTestCase class when module is loaded by unittest
998 | for dirpath, _, filenames in os.walk(BEFORE_DIR):
999 | for example in [f for f in filenames if any(f.endswith(_) for _ in fprettify.FORTRAN_EXTENSIONS)]:
1000 | rel_dirpath = os.path.relpath(dirpath, start=BEFORE_DIR)
1001 | addtestmethod(FPrettifyTestCase, rel_dirpath, example)
1002 |
--------------------------------------------------------------------------------
/fprettify/version.py:
--------------------------------------------------------------------------------
1 | try:
2 | from importlib.metadata import PackageNotFoundError, version
3 | except ModuleNotFoundError:
4 | from importlib_metadata import PackageNotFoundError, version
5 | try:
6 | __version__ = version(__package__)
7 | except PackageNotFoundError:
8 | from setuptools_scm import get_version
9 |
10 | __version__ = get_version(root="..", relative_to=__file__)
11 |
--------------------------------------------------------------------------------
/hooks.yml:
--------------------------------------------------------------------------------
1 | .pre-commit-hooks.yaml
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = [
3 | "setuptools >= 45",
4 | "wheel",
5 | "setuptools_scm[toml] >= 6.2",
6 | "setuptools_scm_git_archive",
7 | ]
8 | build-backend = "setuptools.build_meta"
9 |
10 | [tool.setuptools_scm]
11 | write_to = "fprettify/_version.py"
12 |
13 | [tool.isort]
14 | profile = "black"
15 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | setuptools
2 | configargparse
3 |
--------------------------------------------------------------------------------
/run_tests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | ###############################################################################
4 | # This file is part of fprettify.
5 | # Copyright (C) 2016-2019 Patrick Seewald, CP2K developers group
6 | #
7 | # fprettify is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # fprettify is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with fprettify. If not, see .
19 | ###############################################################################
20 |
21 | import unittest
22 | from fprettify.tests import FPrettifyTestCase, FAILED_FILE, RESULT_FILE
23 | import fileinput
24 | import io
25 | import os
26 | import sys
27 | import argparse
28 |
29 | if __name__ == '__main__':
30 | parser = argparse.ArgumentParser(
31 | description='Run tests', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
32 | parser.add_argument("-r", "--reset", action='store_true', default=False,
33 | help="Reset test results to new results of failed tests")
34 |
35 | args = parser.parse_args()
36 |
37 | suite = unittest.TestLoader().loadTestsFromTestCase(FPrettifyTestCase)
38 | unittest.TextTestRunner(verbosity=2).run(suite)
39 |
40 | if args.reset and os.path.isfile(FAILED_FILE):
41 | sep_str = ' : '
42 | with io.open(FAILED_FILE, 'r', encoding='utf-8') as infile:
43 | for failed_line in infile:
44 | failed_content = failed_line.strip().split(sep_str)
45 | for result_line in fileinput.input(RESULT_FILE, inplace=True):
46 | result_content = result_line.strip().split(sep_str)
47 | if result_content[0] == failed_content[0]:
48 | sys.stdout.write(failed_line)
49 | else:
50 | sys.stdout.write(result_line)
51 |
52 | os.remove(FAILED_FILE)
53 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = fprettify
3 | url = https://github.com/pseewald/fprettify
4 | author = Patrick Seewald
5 | author_email = patrick.seewald@gmail.com
6 | description = auto-formatter for modern fortran source code
7 | long_description = file: README.md
8 | long_description_content_type = text/markdown
9 | license = GPLv3
10 | classifiers =
11 | Development Status :: 5 - Production/Stable
12 | Intended Audience :: Developers
13 | Topic :: Software Development :: Quality Assurance
14 | License :: OSI Approved :: GNU General Public License v3 (GPLv3)
15 | Programming Language :: Python :: 3
16 | Programming Language :: Python :: 3.6
17 | Programming Language :: Python :: 3.7
18 | Programming Language :: Python :: 3.8
19 | Programming Language :: Python :: 3.9
20 | Environment :: Console
21 | Operating System :: OS Independent
22 | keywords =
23 | fortran
24 | formatter
25 | project_urls =
26 | Tracker = https://github.com/pseewald/fprettify/issues
27 | Source Code = https://github.com/pseewald/fprettify
28 |
29 | [options]
30 | packages = find:
31 | python_requires = >= 3.6
32 | install_requires =
33 | configargparse
34 | importlib-metadata; python_version < "3.8"
35 |
36 | [options.entry_points]
37 | console_scripts =
38 | fprettify = fprettify.__init__:run
39 |
40 | [options.extras_require]
41 | dev =
42 | black
43 | isort
44 | pre-commit
45 | coveralls
46 |
47 | [flake8]
48 | max-line-length = 88
49 | extend-ignore = E203, E722
50 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from setuptools import setup
3 |
4 | setup()
5 |
--------------------------------------------------------------------------------