From e79199da29c8fe9ffc9cf1b2f5bc15f996ef9154 Mon Sep 17 00:00:00 2001 From: Andrew Porter Date: Wed, 10 Jan 2024 20:50:53 +0000 Subject: [PATCH] #426 extend fix to F2008 and refactor Connect_Spec implementation --- src/fparser/two/Fortran2003.py | 86 +++++++++++-------- .../two/Fortran2008/connect_spec_r905.py | 66 +++----------- 2 files changed, 62 insertions(+), 90 deletions(-) diff --git a/src/fparser/two/Fortran2003.py b/src/fparser/two/Fortran2003.py index f87dda31..3e1b5e2c 100644 --- a/src/fparser/two/Fortran2003.py +++ b/src/fparser/two/Fortran2003.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Modified work Copyright (c) 2017-2023 Science and Technology +# Modified work Copyright (c) 2017-2024 Science and Technology # Facilities Council. # Original work Copyright (c) 1999-2008 Pearu Peterson @@ -8602,50 +8602,64 @@ class Connect_Spec(KeywordValueBase): "Scalar_Int_Variable", ] - @staticmethod - def match(string): - """ + @classmethod + def _keyword_value_list(cls): + """ + Defines the valid keywords and corresponding classes to match against. + This has to be a method rather than a class property as those classes + are generated after this class has been created. + + :returns: list of keyword, class pairs to match against. + :rtype: list[tuple[str, type]] + + """ + result = [ + ("ACCESS", Scalar_Default_Char_Expr), + ("ACTION", Scalar_Default_Char_Expr), + ("ASYNCHRONOUS", Scalar_Default_Char_Expr), + ("BLANK", Scalar_Default_Char_Expr), + ("DECIMAL", Scalar_Default_Char_Expr), + ("DELIM", Scalar_Default_Char_Expr), + ("ENCODING", Scalar_Default_Char_Expr), + ("FORM", Scalar_Default_Char_Expr), + ("PAD", Scalar_Default_Char_Expr), + ("POSITION", Scalar_Default_Char_Expr), + ("ROUND", Scalar_Default_Char_Expr), + ("SIGN", Scalar_Default_Char_Expr), + ("STATUS", Scalar_Default_Char_Expr), + ("ERR", Label), + ("FILE", File_Name_Expr), + ("IOSTAT", Scalar_Int_Variable), + ("IOMSG", Iomsg_Variable), + ("RECL", Scalar_Int_Expr), + ("UNIT", File_Unit_Number), + ] + if "open-convert" in EXTENSIONS(): + # The CONVERT keyword is a non-standard extension supported by + # many compilers. + result.append(("CONVERT", Scalar_Default_Char_Expr)) + return result + + @classmethod + def match(cls, string): + """Implements the matching for connect-spec. + + Note that this is implemented as a `classmethod` (not a + `staticmethod`), using attribute keywords from the list provided + as a class method. This allows expanding this list for + Fortran 2008 without having to reimplement the matching. + :param str string: Fortran code to check for a match :return: 2-tuple containing the keyword and value or None if the supplied string is not a match :rtype: 2-tuple containing keyword (e.g. "UNIT") and associated value + """ if "=" not in string: # The only argument which need not be named is the unit number return "UNIT", File_Unit_Number(string) # We have a keyword-value pair. Check whether it is valid... - keyword_list = [ - "ACCESS", - "ACTION", - "ASYNCHRONOUS", - "BLANK", - "DECIMAL", - "DELIM", - "ENCODING", - "FORM", - "PAD", - "POSITION", - "ROUND", - "SIGN", - "STATUS", - ] - if "open-convert" in EXTENSIONS(): - # The CONVERT keyword is a non-standard extension supported by - # many compilers. - keyword_list.append("CONVERT") - - for keyword, value in [ - ( - keyword_list, - Scalar_Default_Char_Expr, - ), - ("ERR", Label), - ("FILE", File_Name_Expr), - ("IOSTAT", Scalar_Int_Variable), - ("IOMSG", Iomsg_Variable), - ("RECL", Scalar_Int_Expr), - ("UNIT", File_Unit_Number), - ]: + for keyword, value in cls._keyword_value_list(): try: obj = KeywordValueBase.match(keyword, value, string, upper_lhs=True) except NoMatchError: diff --git a/src/fparser/two/Fortran2008/connect_spec_r905.py b/src/fparser/two/Fortran2008/connect_spec_r905.py index 0123be71..ae011cc4 100644 --- a/src/fparser/two/Fortran2008/connect_spec_r905.py +++ b/src/fparser/two/Fortran2008/connect_spec_r905.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2023, Science and Technology Facilities Council. +# Copyright (c) 2023-2024, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -48,7 +48,8 @@ class Connect_Spec(Connect_Spec_2003): """ - Fortran2008 rule R905. + Fortran2008 rule R905. Extends the Fortran2003 definition with support for + the NEWUNIT specifier. connect-spec is [ UNIT = ] file-unit-number or ACCESS = scalar-default-char-expr @@ -104,58 +105,15 @@ class Connect_Spec(Connect_Spec_2003): "Scalar_Int_Variable", ] - @staticmethod - def match(string): + @classmethod + def _keyword_value_list(cls): """ - :param str string: Fortran code to check for a match + Extends the list of keywords supported in Fortran2003 with NEWUNIT. - :returns: 2-tuple containing the keyword and value or None if the - supplied string is not a match - :rtype: Optional[Tuple[str, Any]] - """ - # Avoid circular dependencies by importing here. - # pylint: disable=import-outside-toplevel - from fparser.two.Fortran2008 import ( - Scalar_Default_Char_Expr, - Scalar_Int_Variable, - Scalar_Int_Expr, - ) + :returns: list of keyword, class pairs to match against. + :rtype: list[tuple[str, type]] - if "=" not in string: - # The only argument which need not be named is the unit number - return "UNIT", File_Unit_Number(string) - # We have a keyword-value pair. Check whether it is valid... - for keyword, value in [ - ( - [ - "ACCESS", - "ACTION", - "ASYNCHRONOUS", - "BLANK", - "DECIMAL", - "DELIM", - "ENCODING", - "FORM", - "PAD", - "POSITION", - "ROUND", - "SIGN", - "STATUS", - ], - Scalar_Default_Char_Expr, - ), - ("ERR", Label), - ("FILE", File_Name_Expr), - ("IOSTAT", Scalar_Int_Variable), - ("IOMSG", Iomsg_Variable), - ("RECL", Scalar_Int_Expr), - ("UNIT", File_Unit_Number), - ("NEWUNIT", File_Unit_Number), - ]: - try: - obj = KeywordValueBase.match(keyword, value, string, upper_lhs=True) - except NoMatchError: - obj = None - if obj is not None: - return obj - return None + """ + result = Connect_Spec_2003._keyword_value_list() + result.append(("NEWUNIT", File_Unit_Number)) + return result