Skip to content

Commit

Permalink
Merge pull request #406 from stfc/405_module_procedure_colons
Browse files Browse the repository at this point in the history
add f2008 R1206 procedure-stmt support (closes issue 405)
  • Loading branch information
arporter authored Apr 26, 2023
2 parents ab3ac61 + 4b9ec16 commit 0b58845
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Modifications by (in alphabetical order):
* P. Vitt, University of Siegen, Germany
* A. Voysey, UK Met Office

26/04/2023 PR #406 for #405. Add support for F2008 optional "::" in PROCEDURE
statement.

03/04/2023 PR #392 for #326. Add support for F2008 block and critical constructs.

30/03/2023 PR #396 for #395. Fix trailing whitespace bug in CallBase.
Expand Down
6 changes: 4 additions & 2 deletions doc/source/fparser2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ Fortran 2003. This is implemented in the Fortran2003.py `file`__ and
contains an entirely separate parser to fparser1 that includes rules
for Fortran 2003 syntax. Support for Fortran 2008 is being added in
the Fortran2008.py `file`__ which extends the Fortran2003 rules
appropriately. At this time fparser2 supports submodules, co-arrays,
the 'mold' argument to allocate and the 'contiguous' keyword in Fortran2008.
appropriately. At this time fparser2 supports the following
Fortran2008 features: submodules, co-arrays, the 'mold' argument to
allocate, the 'contiguous' keyword, the 'BLOCK' construct, the
'CRITICAL' construct and the optional '::' for a procedure statement.

__ https://github.com/stfc/fparser/blob/master/src/fparser/two/Fortran2003.py
__ https://github.com/stfc/fparser/blob/master/src/fparser/two/Fortran2008.py
Expand Down
51 changes: 50 additions & 1 deletion src/fparser/two/Fortran2008.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
Executable_Construct_C201 as Executable_Construct_C201_2003,
If_Stmt as If_Stmt_2003,
Open_Stmt as Open_Stmt_2003,
Procedure_Stmt as Procedure_Stmt_2003,
Program_Unit as Program_Unit_2003,
Type_Declaration_Stmt as Type_Declaration_Stmt_2003,
)
Expand Down Expand Up @@ -165,7 +166,7 @@ class Program_Unit(Program_Unit_2003): # R202
class Executable_Construct(Executable_Construct_2003): # R213
# pylint: disable=invalid-name
"""
Fortran 2003 rule R213.
Fortran 2008 rule R213.
.. code-block:: fortran
Expand Down Expand Up @@ -1578,6 +1579,54 @@ def match(string):
)


class Procedure_Stmt(Procedure_Stmt_2003): # R1206
"""
Fortran 2008 Rule 1206.
procedure-stmt is [ MODULE ] PROCEDURE [ :: ] procedure-name-list
"""

@staticmethod
def match(string):
""":param str string: Fortran code to check for a match
:returns: 3-tuple containing a boolean indicating whether the \
optional MODULE keyword is included, a boolean indicating \
whether the optional '::' is included and a Procedure_Name_List \
instance, or None if there is no match.
:rtype: Optional[Tuple[ \
bool, bool, \
:py:class:`fparser.two.Fortran2003.Procedure_Name_List`]]]
"""
line = string.lstrip()
optional_module = None
if line[:6].upper() == "MODULE":
line = line[6:].lstrip()
optional_module = "MODULE"
if line[:9].upper() != "PROCEDURE":
return None
line = line[9:].lstrip()
optional_colons = None
if line[:2] == "::":
line = line[2:].lstrip()
optional_colons = "::"
return (Procedure_Name_List(line), optional_module, optional_colons)

def tostr(self):
"""
:returns: the string representation of this node.
:rtype: str
"""
result = "PROCEDURE"
if self.items[1]:
result = f"MODULE {result}"
if self.items[2]:
result = f"{result} ::"
return f"{result} {self.items[0]}"


#
# GENERATE Scalar_, _List, _Name CLASSES
#
Expand Down
89 changes: 89 additions & 0 deletions src/fparser/two/tests/fortran2008/test_procedure_stmt_r1206.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright (c) 2023 Science and Technology Facilities Council

# All rights reserved.

# Modifications made as part of the fparser project are distributed
# under the following license:

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:

# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.

# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.

# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Test Fortran 2008 rule R1206
procedure-stmt is [ MODULE ] PROCEDURE [ :: ] procedure-name-list
"""

import pytest
from fparser.two.Fortran2008 import Procedure_Stmt
from fparser.two.utils import NoMatchError


def test_start_space():
"""Test that there is a match if the string contains white space at
the start and that the tostr() output is as expected.
"""
result = Procedure_Stmt(" procedure dummy")
assert isinstance(result, Procedure_Stmt)
assert str(result) == "PROCEDURE dummy"


def test_module():
"""Test that there is a match if the string contains the optional
MODULE keyword and that the tostr() output is as expected.
"""
result = Procedure_Stmt(" module procedure dummy")
assert isinstance(result, Procedure_Stmt)
assert str(result) == "MODULE PROCEDURE dummy"


def test_colons():
"""Test that there is a match if the string contains optional :: after
the procedure keyword and that the tostr() output is as expected.
"""
result = Procedure_Stmt(" module procedure :: dummy")
assert isinstance(result, Procedure_Stmt)
assert str(result) == "MODULE PROCEDURE :: dummy"


@pytest.mark.parametrize(
"string",
[
"procedur dummy",
"modul procedure dummy",
"procedure : dummy",
"procedure ",
"procedure :: ",
],
)
def test_invalid(string):
"""Test that there is no match for various invalid input strings."""
with pytest.raises(NoMatchError):
_ = Procedure_Stmt(string)
4 changes: 4 additions & 0 deletions src/fparser/two/tests/test_fortran2003.py
Original file line number Diff line number Diff line change
Expand Up @@ -2964,6 +2964,10 @@ def test_procedure_stmt(): # R1206
assert isinstance(obj, tcls), repr(obj)
assert str(obj) == "MODULE PROCEDURE a, b"

# '::' is only valid from F2008 onwards
with pytest.raises(NoMatchError):
_ = tcls("procedure :: a")


def test_generic_spec(): # R1207
tcls = Generic_Spec
Expand Down

0 comments on commit 0b58845

Please sign in to comment.