Repository: stfc/fparser

Issue:
F2008's error-stop-stmt not supported
F2008 introduced `ERROR STOP [ stop-code ]` which fparser2 doesn't currently recognize. I'll file the corresponding PR in a few minutes.

Discussion:
reuterbal: Many thanks for looking through this so quickly! The functional test was indeed crucial, as the new class has of course not been picked up... Unfortunately, to make this work I had to duplicate quite a lot of boiler plate code from F2003 to carry over all constraints etc. to F2008 and make sure they are picked up in the right places higher-up in the matching hierarchy.

I have also added some more tests to cover this as good as I can but for the very high-level constructs I wasn't sure how much of this would bee needed on top. Feel free to suggest some more tests, of course.

Since If_Stmt hasn't had 100% coverage before, I took the liberty of back-porting the relevant tests there, too.
reuterbal: Thanks for your comments @arporter!

Please have a look at the parametrization of `If_Stmt.match` to make sure you are happy with my approach and the changes it implies (or suggest a better way, of course).

Regarding the application of constraints in subclasses: As mentioned in the comments, I just duplicated what is being done in Fortran2003.py -- and judging from the git blame, the relevant bits are fairly old. So, I don't know if the reason for this approach is still recorded somewhere?

If attempting to remove subclasses as much as possible to enforce these constraints, I would suggest doing this in both language versions to have the same behaviour everywhere. What are your thoughts on this?
arporter: Almost there now - thanks for adding all the extra tests. As I've said inline, I'm happy with the change you've made to the `match` method and have checked that the generated lists of subclasses are unchanged.

Please could you bring this branch up-to-date with master. (You may have noticed that we released 0.0.14 last week - this was primarily to satisfy deliverables in a related project.)

For the constraints-as-subclasses thing, I hadn't appreciated that that's what's done in Fortran2003. As you say, I see that they are the way Pearu originally implemented things so I suggest we leave it the way it is, at least for now. 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 644a5d4..26cb232 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,8 @@ Modifications by (in alphabetical order):
 * P. Vitt, University of Siegen, Germany
 * A. Voysey, UK Met Office
 
+21/03/2022 PR #315 for #314. Adds support for the F2008 Error_Stop_Stmt.
+
 ## Release 0.0.14 (16/03/2022) ##
 
 15/03/2022 PR #311 for #310. Allows symbol table scope to be None.
diff --git a/src/fparser/two/Fortran2003.py b/src/fparser/two/Fortran2003.py
index d0e1d53..5ebe5d9 100644
--- a/src/fparser/two/Fortran2003.py
+++ b/src/fparser/two/Fortran2003.py
@@ -5974,13 +5974,40 @@ class End_If_Stmt(EndStmtBase):  # R806
 
 class If_Stmt(StmtBase):  # R807
     """
-    <if-stmt> = IF ( <scalar-logical-expr> ) <action-stmt>
+    Fortran 2003 rule R807
+
+    if-stmt is IF ( scalar-logical-expr ) action-stmt
+
+    C802 (R807) The action-stmt in the if-stmt shall not be an if-stmt,
+    end-program-stmt, end-function-stmt, or end-subroutine-stmt.
+
     """
     subclass_names = []
     use_names = ['Scalar_Logical_Expr', 'Action_Stmt_C802']
+    action_stmt_cls = Action_Stmt_C802
 
-    @staticmethod
-    def match(string):
+    @classmethod
+    def match(cls, string):
+        '''Implements the matching for an if statement that controls a single
+        action statement
+
+        This is implemented as a class method to allow parameterizing the
+        type that is used to match the action-stmt. It is specified by the
+        attribute :py:attr:`action_stmt_cls`, which can be overwritten in
+        derived classes to specify an updated version, so done for example
+        in the Fortran 2008 version :py:class:`fparser.two.Fortran2008.If_Stmt`.
+
+        :param str string: Text that we are trying to match.
+
+        :returns: None if there is no match or, if there is a match, a \
+            2-tuple containing the logical expression as an object matched by \
+            :py:class:`fparser.two.Fortran2003.Scalar_Logical_Expr` and the \
+            action statement as an object matching ``cls.action_stmt_cls``. 
+        :rtype: (:py:class:`fparser.two.Fortran2003.Scalar_Logical_Expr`,
+            :py:class:`fparser.two.Fortran2003.Action_Stmt_C802`) \
+            or NoneType
+
+        '''
         if string[:2].upper() != 'IF':
             return
         line, repmap = string_replace_map(string)
@@ -5992,7 +6019,7 @@ class If_Stmt(StmtBase):  # R807
             return
         expr = repmap(line[1:i].strip())
         stmt = repmap(line[i+1:].lstrip())
-        return Scalar_Logical_Expr(expr), Action_Stmt_C802(stmt)
+        return Scalar_Logical_Expr(expr), cls.action_stmt_cls(stmt)
 
     def tostr(self):
         return 'IF (%s) %s' % self.items
diff --git a/src/fparser/two/Fortran2008.py b/src/fparser/two/Fortran2008.py
index e567194..4792876 100644
--- a/src/fparser/two/Fortran2008.py
+++ b/src/fparser/two/Fortran2008.py
@@ -1,4 +1,4 @@
-# Modified work Copyright (c) 2018-2020 Science and Technology
+# Modified work Copyright (c) 2018-2022 Science and Technology
 # Facilities Council
 # Original work Copyright (c) 1999-2008 Pearu Peterson
 
@@ -77,18 +77,26 @@ from fparser.common.splitline import string_replace_map
 from fparser.two import pattern_tools as pattern
 
 from fparser.two.utils import STRINGBase, BracketBase, WORDClsBase, \
-    SeparatorBase, Type_Declaration_StmtBase
+    SeparatorBase, Type_Declaration_StmtBase, StmtBase
 from fparser.two.Fortran2003 import (
     EndStmtBase, BlockBase, SequenceBase, Base, Specification_Part,
     Module_Subprogram_Part, Implicit_Part, Implicit_Part_Stmt,
     Declaration_Construct, Use_Stmt, Import_Stmt, Declaration_Type_Spec,
-    Entity_Decl_List, Component_Decl_List)
+    Entity_Decl_List, Component_Decl_List, Stop_Code)
 # Import of F2003 classes that are updated in this standard.
 from fparser.two.Fortran2003 import (
     Program_Unit as Program_Unit_2003, Attr_Spec as Attr_Spec_2003,
     Type_Declaration_Stmt as Type_Declaration_Stmt_2003,
     Component_Attr_Spec as Component_Attr_Spec_2003,
-    Data_Component_Def_Stmt as Data_Component_Def_Stmt_2003)
+    Data_Component_Def_Stmt as Data_Component_Def_Stmt_2003,
+    Action_Stmt as Action_Stmt_2003,
+    Action_Stmt_C201 as Action_Stmt_C201_2003,
+    Action_Stmt_C802 as Action_Stmt_C802_2003,
+    Action_Stmt_C824 as Action_Stmt_C824_2003,
+    If_Stmt as If_Stmt_2003,
+    Do_Term_Action_Stmt as Do_Term_Action_Stmt_2003,
+    Executable_Construct as Executable_Construct_2003,
+    Executable_Construct_C201 as Executable_Construct_C201_2003)
 
 
 class Program_Unit(Program_Unit_2003):  # R202
@@ -108,6 +116,146 @@ class Program_Unit(Program_Unit_2003):  # R202
     subclass_names.append("Submodule")
 
 
+
+class Executable_Construct(Executable_Construct_2003):  # R213
+    # pylint: disable=invalid-name
+    '''
+    Fortran 2003 rule R213
+    executable-construct is action-stmt
+                         or associate-construct
+                         or block-construct
+                         or case-construct
+                         or critical-construct
+                         or do-construct
+                         or forall-construct
+                         or if-construct
+                         or select-type-construct
+                         or where-construct
+
+    Associated constraints are:
+
+    "C201 (R208) An execution-part shall not contain an end-function-stmt,
+          end-mp-subprogram-stmt, end-program-stmt, or end-subroutine-stmt."
+
+    NB: The new block-construct and critical-construct are not yet implemented.
+    TODO: Implement missing F2008 executable-construct (#320)
+
+    '''
+    subclass_names = [
+        'Action_Stmt', 'Associate_Construct', 'Case_Construct',
+        'Do_Construct', 'Forall_Construct', 'If_Construct',
+        'Select_Type_Construct', 'Where_Construct']
+
+
+class Executable_Construct_C201(Executable_Construct_C201_2003):
+    '''
+    executable-construct-c201 is executable construct.
+    This applies C201.
+    '''
+    subclass_names = Executable_Construct.subclass_names[:]
+    subclass_names[subclass_names.index('Action_Stmt')] = 'Action_Stmt_C201'
+
+
+class Action_Stmt(Action_Stmt_2003):  # R214
+    '''
+    Fortran 2008 rule R214
+    action-stmt is allocate-stmt
+                    or assignment-stmt
+                    or backspace-stmt
+                    or call-stmt
+                    or close-stmt
+                    or continue-stmt
+                    or cycle-stmt
+                    or deallocate-stmt
+                    or end-function-stmt
+                    or end-mp-subprogram-stmt
+                    or end-program-stmt
+                    or end-subroutine-stmt
+                    or endfile-stmt
+                    or error-stop-stmt
+                    or exit-stmt
+                    or flush-stmt
+                    or forall-stmt
+                    or goto-stmt
+                    or if-stmt
+                    or inquire-stmt
+                    or lock-stmt
+                    or nullify-stmt
+                    or open-stmt
+                    or pointer-assignment-stmt
+                    or print-stmt
+                    or read-stmt
+                    or return-stmt
+                    or rewind-stmt
+                    or stop-stmt
+                    or sync-all-stmt
+                    or sync-images-stmt
+                    or sync-memory-stmt
+                    or unlock-stmt
+                    or wait-stmt
+                    or where-stmt
+                    or write-stmt
+                    or arithmetic-if-stmt
+                    or computed-goto-stmt
+
+    The implementation of this rule adds the relevant subclass names
+    for new statements added in Fortran 2008.
+
+    Associated constraints are:
+
+    "C201 (R208) An execution-part shall not contain an end-function-stmt,
+          end-mp-subprogram-stmt, end-program-stmt, or end-subroutine-stmt."
+
+    NB: The following statements are not yet implemented:
+    end-mp-subprogram-stmt, endfile-stmt, lock-stmt, sync-all-stmt,
+    sync-images-stmt, sync-memory-stmt, unlock-stmt.
+
+    '''
+    # Fortran 2008 adds a few additional action-stmt. We therefore
+    # extend the Fortran 2003 specification
+    subclass_names = Action_Stmt_2003.subclass_names[:]
+    subclass_names.append("Error_Stop_Stmt")
+
+
+class Action_Stmt_C201(Action_Stmt_C201_2003):
+    """
+    action-stmt-c201 is action-stmt
+    C201 is applied.
+    """
+    subclass_names = Action_Stmt.subclass_names[:]
+    subclass_names.remove('End_Function_Stmt')
+    subclass_names.remove('End_Subroutine_Stmt')
+
+
+class Action_Stmt_C816(Action_Stmt_C824_2003):
+    """
+    action-stmt-c816 is action-stmt
+    C816 is applied.
+    """
+    subclass_names = Action_Stmt.subclass_names[:]
+    subclass_names.remove('Arithmetic_If_Stmt')
+    subclass_names.remove('Continue_Stmt')
+    subclass_names.remove('Cycle_Stmt')
+    subclass_names.remove('End_Function_Stmt')
+    subclass_names.remove('End_Subroutine_Stmt')
+    subclass_names.remove('Error_Stop_Stmt')
+    subclass_names.remove('Exit_Stmt')
+    subclass_names.remove('Goto_Stmt')
+    subclass_names.remove('Return_Stmt')
+    subclass_names.remove('Stop_Stmt')
+
+
+class Action_Stmt_C828(Action_Stmt_C802_2003):
+    """
+    action-stmt-c828 is action-stmt
+    C828 is applied.
+    """
+    subclass_names = Action_Stmt.subclass_names[:]
+    subclass_names.remove('End_Function_Stmt')
+    subclass_names.remove('End_Subroutine_Stmt')
+    subclass_names.remove('If_Stmt')
+
+
 class Data_Component_Def_Stmt(Data_Component_Def_Stmt_2003):  # R436
     '''
     Fortran 2008 rule 436
@@ -526,6 +674,68 @@ class Upper_Cobound(Base):  # R513
     subclass_names = ['Specification_Expr']
 
 
+class Do_Term_Action_Stmt(Do_Term_Action_Stmt_2003):  # R826
+    """
+    Fortran 2008 rule R826
+    do-term-action-stmt is action-stmt
+
+    Associated constraints are:
+
+    "C816 (R826) A do-term-action-stmt shall not be an arithmetic-if-stmt,
+          continue-stmt, cycle-stmt, end-function-stmt, end-mp-subprogram-stmt,
+          end-program-stmt, end-subroutine-stmt, error-stop-stmt, exit-stmt,
+          goto-stmt, return-stmt, or stop-stmt."
+    """
+    subclass_names = ['Action_Stmt_C816']
+
+
+class If_Stmt(If_Stmt_2003):  # R837
+    '''
+    Fortran 2008 rule R837
+    if-stmt is IF ( scalar-logical-expr ) action-stmt
+
+    The implementation of this rule only replaces the :py:attr:`use_names` and
+    :py:attr:`action_stmt_class` attributes to use the Fortran 2008 variant
+    :py:class:`Action_Stmt_C828` instead of
+    :py:class:`fparser.two.Fortran2003.Action_Stmt_C802`.
+
+    Associated constraints are:
+
+    C828 (R837) The action-stmt in the if-stmt shall not be an end-function-stmt,
+          end-mp-subprogram-stmt, end-program-stmt, end-subroutine-stmt, or if-stmt.
+
+    '''
+    use_names = ['Scalar_Logical_Expr', 'Action_Stmt_C828']
+    action_stmt_cls = Action_Stmt_C828
+
+
+class Error_Stop_Stmt(StmtBase, WORDClsBase):  # R856
+    '''
+    Fortran 2008 rule R856
+    error-stop-stmt is ERROR STOP [ stop-code ]
+
+    '''
+    subclass_names = []
+    use_names = ['Stop_Code']
+
+    @staticmethod
+    def match(string):
+        '''Check whether the input matches the rule
+
+        :param str string: Text that we are trying to match.
+
+        :returns: None if there is no match or, if there is a match, a \
+            2-tuple containing a string matching 'ERROR STOP' and an \
+            instance of :py:class:`fparser.two.Fortran2003.Stop_Code` \
+            (or None if an instance of 'Stop_Code' is not required and \
+            not provided).
+        :rtype: (str, :py:class:`fparser.two.Fortran2003.Stop_Code` or None) \
+            or NoneType
+
+        '''
+        return WORDClsBase.match('ERROR STOP', Stop_Code, string)
+
+
 class Specification_Part_C1112(Specification_Part):  # C1112
     '''Fortran 2008 constraint C1112
     C1112 A submodule specification-part shall not contain a
@@ -860,11 +1070,10 @@ class %s_List(SequenceBase):
 class %s_Name(Base):
     subclass_names = [\'Name\']
 ''' % (n))
-# Currently there are no examples using scalar_* as a class name.
-#         elif n.startswith('Scalar_'):
-#             _names.append(n)
-#             n = n[7:]
-#             exec('''\
-# class Scalar_%s(Base):
-#     subclass_names = [\'%s\']
-# ''' % (n, n))
+        elif n.startswith('Scalar_'):
+            _names.append(n)
+            n = n[7:]
+            exec('''\
+class Scalar_%s(Base):
+    subclass_names = [\'%s\']
+''' % (n, n))
diff --git a/src/fparser/two/parser.py b/src/fparser/two/parser.py
index f6a6a00..e3afafd 100644
--- a/src/fparser/two/parser.py
+++ b/src/fparser/two/parser.py
@@ -223,7 +223,7 @@ class ParserFactory(object):
                     return []
                 # remove this code when all classes are implemented.
                 cls = base_classes[clsname]
-                if 'match' in cls.__dict__:
+                if hasattr(cls, 'match'):
                     return [clsname]
                 bits = []
                 for names in getattr(cls, 'subclass_names', []):


Test patch:
diff --git a/src/fparser/two/tests/fortran2003/test_if_stmt_r807.py b/src/fparser/two/tests/fortran2003/test_if_stmt_r807.py
new file mode 100644
index 0000000..017fb4b
--- /dev/null
+++ b/src/fparser/two/tests/fortran2003/test_if_stmt_r807.py
@@ -0,0 +1,92 @@
+# Copyright (c) 2022 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 2003 rule R807
+
+    if-stmt is IF ( scalar-logical-expr ) action-stmt
+'''
+
+import pytest
+from fparser.two.Fortran2003 import Stop_Stmt, If_Stmt, Assignment_Stmt
+from fparser.two.utils import walk, NoMatchError
+
+
+@pytest.mark.usefixtures("f2003_create")
+def test_simple_stop():
+    '''Test matching of a valid string.'''
+    result = If_Stmt('IF (5 > 3) STOP')
+    assert isinstance(result, If_Stmt)
+    assert walk(result, Stop_Stmt)
+
+
+@pytest.mark.usefixtures("f2003_create")
+def test_simple_assignment():
+    '''Test matching of a valid string.'''
+    result = If_Stmt('IF (A < B) A = B')
+    assert isinstance(result, If_Stmt)
+    assignments = walk(result, Assignment_Stmt)
+    assert len(assignments) == 1
+    assert str(assignments[0]) == 'A = B'
+
+
+@pytest.mark.usefixtures("f2003_create")
+def test_error1():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IFF (5 > 3) STOP')
+    assert "If_Stmt: 'IFF (5 > 3) STOP'" in str(excinfo.value)
+
+
+@pytest.mark.usefixtures("f2003_create")
+def test_error2():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IF 5 > 3 STOP')
+    assert "If_Stmt: 'IF 5 > 3 STOP'" in str(excinfo.value)
+
+
+@pytest.mark.usefixtures("f2003_create")
+def test_error3():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IF (5 > 3] STOP')
+    assert "If_Stmt: 'IF (5 > 3] STOP'" in str(excinfo.value)
+
+
+@pytest.mark.usefixtures("f2003_create")
+def test_error4():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IF (A = B) A = 0')
+    assert "If_Stmt: 'IF (A = B) A = 0'" in str(excinfo.value)
diff --git a/src/fparser/two/tests/fortran2008/test_action_stmt_r214.py b/src/fparser/two/tests/fortran2008/test_action_stmt_r214.py
new file mode 100644
index 0000000..845143d
--- /dev/null
+++ b/src/fparser/two/tests/fortran2008/test_action_stmt_r214.py
@@ -0,0 +1,163 @@
+# Copyright (c) 2022 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 R214
+
+    action-stmt is allocate-stmt
+                    or assignment-stmt
+                    or backspace-stmt
+                    or call-stmt
+                    or close-stmt
+                    or continue-stmt
+                    or cycle-stmt
+                    or deallocate-stmt
+                    or end-function-stmt
+                    or end-mp-subprogram-stmt
+                    or end-program-stmt
+                    or end-subroutine-stmt
+                    or endfile-stmt
+                    or error-stop-stmt
+                    or exit-stmt
+                    or flush-stmt
+                    or forall-stmt
+                    or goto-stmt
+                    or if-stmt
+                    or inquire-stmt
+                    or lock-stmt
+                    or nullify-stmt
+                    or open-stmt
+                    or pointer-assignment-stmt
+                    or print-stmt
+                    or read-stmt
+                    or return-stmt
+                    or rewind-stmt
+                    or stop-stmt
+                    or sync-all-stmt
+                    or sync-images-stmt
+                    or sync-memory-stmt
+                    or unlock-stmt
+                    or wait-stmt
+                    or where-stmt
+                    or write-stmt
+                    or arithmetic-if-stmt
+                    or computed-goto-stmt
+
+    Associated constraints are:
+
+    "C201 (R208) An execution-part shall not contain an end-function-stmt,
+          end-mp-subprogram-stmt, end-program-stmt, or end-subroutine-stmt."
+
+    TODO: Implement and test lock-stmt, sync-all-stmt, sync-images-stmt,
+          sync-memory-stmt, unlock-stmt (#321)
+'''
+
+import pytest
+from fparser.api import get_reader, walk
+from fparser.two.Fortran2003 import (
+    Allocate_Stmt, Arithmetic_If_Stmt, Backspace_Stmt, Call_Stmt, Close_Stmt,
+    Computed_Goto_Stmt, Continue_Stmt, Cycle_Stmt, Deallocate_Stmt,
+    End_Function_Stmt, End_Subroutine_Stmt, Endfile_Stmt, Exit_Stmt, Flush_Stmt,
+    Forall_Stmt, Goto_Stmt, If_Stmt, Inquire_Stmt, Nullify_Stmt, Open_Stmt,
+    Pointer_Assignment_Stmt, Print_Stmt, Read_Stmt, Return_Stmt, Rewind_Stmt,
+    Stop_Stmt, Wait_Stmt, Where_Stmt, Write_Stmt
+)
+from fparser.two.Fortran2008 import Action_Stmt, Error_Stop_Stmt
+from fparser.two.utils import NoMatchError
+
+
+@pytest.mark.usefixtures('f2008_create', 'fake_symbol_table')
+@pytest.mark.parametrize('string, cls', [
+    ('ALLOCATE(A(10))', Allocate_Stmt),
+    ('BACKSPACE 42', Backspace_Stmt),
+    ('CALL SOME_ROUTINE()', Call_Stmt),
+    ('CLOSE(23)', Close_Stmt),
+    ('CONTINUE', Continue_Stmt),
+    ('CYCLE', Cycle_Stmt),
+    ('DEALLOCATE(A)', Deallocate_Stmt),
+    ('END FUNCTION FUNC', End_Function_Stmt),
+    ('END SUBROUTINE MYSUB', End_Subroutine_Stmt),
+    ('ENDFILE 42', Endfile_Stmt),
+    ('EXIT', Exit_Stmt),
+    ('FLUSH 23', Flush_Stmt),
+    ('FORALL (I=1:N) A(I,I) = X(I)', Forall_Stmt),
+    ('GO TO 915', Goto_Stmt),
+    ('IF (A > B) A = B', If_Stmt),
+    ('INQUIRE (IOLENGTH=N) M', Inquire_Stmt),
+    ('NULLIFY(P)', Nullify_Stmt),
+    ("OPEN (10, FILE = 'employee.names', ACTION = 'READ', PAD = 'YES')", Open_Stmt),
+    ('P => NULL()', Pointer_Assignment_Stmt),
+    ("PRINT *, 'HELLO WORLD'", Print_Stmt),
+    ('READ (6, *) VAR', Read_Stmt),
+    ('RETURN', Return_Stmt),
+    ('REWIND 23', Rewind_Stmt),
+    ('STOP', Stop_Stmt),
+    ('WAIT(23)', Wait_Stmt),
+    ('WHERE (TEMP > 100.0) TEMP = TEMP - REDUCE_TEMP', Where_Stmt),
+    ('WRITE(10, *) A', Write_Stmt),
+    ('IF (A - B) 1, 2, 3', Arithmetic_If_Stmt),
+    ('GO TO (1, 2, 3) 2-1', Computed_Goto_Stmt)
+])
+def test_other(string, cls):
+    '''Test that previous subclasses are still matched correctly.'''
+    result = Action_Stmt(string)
+    assert isinstance(result, cls)
+
+
+def test_other_functional(f2008_parser):
+    '''Test previous subclasses are still matched correctly in a subroutine.'''
+    tree = f2008_parser(get_reader('''\
+subroutine my_abort
+stop
+end subroutine my_abort
+    '''))
+    assert walk(tree, Stop_Stmt)
+    assert 'STOP' in str(tree)
+
+
+@pytest.mark.usefixtures('f2008_create')
+@pytest.mark.parametrize('string, cls', [
+    ('ERROR STOP', Error_Stop_Stmt)
+])
+def test_new_f2008_stmt(string, cls):
+    '''Test that newly added F2008 subclasses are matched correctly.'''
+    result = Action_Stmt(string)
+    assert isinstance(result, cls)
+
+
+@pytest.mark.usefixtures('f2008_create')
+def test_error():
+    '''Test that invalid syntax raises an error.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = Action_Stmt('ERR STOP')
+    assert "Action_Stmt: 'ERR STOP'" in str(excinfo.value)
diff --git a/src/fparser/two/tests/fortran2008/test_error_stop_stmt_r856.py b/src/fparser/two/tests/fortran2008/test_error_stop_stmt_r856.py
new file mode 100644
index 0000000..179ba58
--- /dev/null
+++ b/src/fparser/two/tests/fortran2008/test_error_stop_stmt_r856.py
@@ -0,0 +1,91 @@
+# Copyright (c) 2022 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 R856
+
+    error-stop-stmt is ERROR STOP [ stop-code ]
+'''
+
+import pytest
+from fparser.two.utils import NoMatchError, walk
+from fparser.two.Fortran2008 import Error_Stop_Stmt
+from fparser.api import get_reader
+
+
+@pytest.mark.usefixtures("f2008_create")
+@pytest.mark.parametrize('string', ['ERROR STOP', 'error stop'])
+def test_simple(string):
+    '''Test that error-stop-stmt without stop-code matches.'''
+    result = Error_Stop_Stmt(string)
+    assert str(result) == 'ERROR STOP'
+
+
+@pytest.mark.usefixtures("f2008_create")
+@pytest.mark.parametrize('stop_code', ['1', 'A', 'err_code'])
+def test_stop_code(stop_code):
+    '''Test that error-stop-stmt with stop-code matches.'''
+    result = Error_Stop_Stmt('ERROR STOP {}'.format(stop_code))
+    assert str(result) == 'ERROR STOP {}'.format(stop_code)
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_error1():
+    '''Test error-stop-stmt is not matched for wrong syntax.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = Error_Stop_Stmt('ERROR () STOP')
+    assert "Error_Stop_Stmt: 'ERROR () STOP'" in str(excinfo.value)
+
+
+def test_functional1(f2008_parser):
+    '''Test error-stop-stmt is matched in a subroutine.'''
+    tree = f2008_parser(get_reader('''\
+subroutine my_abort
+error stop
+end subroutine my_abort
+    '''))
+    assert walk(tree, Error_Stop_Stmt)
+    assert 'ERROR STOP' in str(tree)
+
+
+def test_functional2(f2008_parser):
+    '''Test error-stop-stmt is matched in a if-stmt.'''
+    tree = f2008_parser(get_reader('''\
+subroutine my_abort(err_code)
+implicit none
+integer, intent(in) :: err_code
+if (err_code /= 0) error stop err_code
+end subroutine my_abort
+    '''))
+    assert walk(tree, Error_Stop_Stmt)
+    assert 'ERROR STOP err_code' in str(tree)
diff --git a/src/fparser/two/tests/fortran2008/test_if_stmt_r837.py b/src/fparser/two/tests/fortran2008/test_if_stmt_r837.py
new file mode 100644
index 0000000..5b0e47e
--- /dev/null
+++ b/src/fparser/two/tests/fortran2008/test_if_stmt_r837.py
@@ -0,0 +1,93 @@
+# Copyright (c) 2022 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 R837
+
+    if-stmt is IF ( scalar-logical-expr ) action-stmt
+'''
+
+import pytest
+from fparser.two.Fortran2003 import Stop_Stmt, Assignment_Stmt
+from fparser.two.Fortran2008 import If_Stmt
+from fparser.two.utils import walk, NoMatchError
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_simple_stop():
+    '''Test matching of a valid string.'''
+    result = If_Stmt('IF (5 > 3) STOP')
+    assert isinstance(result, If_Stmt)
+    assert walk(result, Stop_Stmt)
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_simple_assignment():
+    '''Test matching of a valid string.'''
+    result = If_Stmt('IF (A < B) A = B')
+    assert isinstance(result, If_Stmt)
+    assignments = walk(result, Assignment_Stmt)
+    assert len(assignments) == 1
+    assert str(assignments[0]) == 'A = B'
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_error1():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IFF (5 > 3) STOP')
+    assert "If_Stmt: 'IFF (5 > 3) STOP'" in str(excinfo.value)
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_error2():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IF 5 > 3 STOP')
+    assert "If_Stmt: 'IF 5 > 3 STOP'" in str(excinfo.value)
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_error3():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IF (5 > 3] STOP')
+    assert "If_Stmt: 'IF (5 > 3] STOP'" in str(excinfo.value)
+
+
+@pytest.mark.usefixtures("f2008_create")
+def test_error4():
+    '''Test invalid syntax doesn't match.'''
+    with pytest.raises(NoMatchError) as excinfo:
+        _ = If_Stmt('IF (A = B) A = 0')
+    assert "If_Stmt: 'IF (A = B) A = 0'" in str(excinfo.value)