stfc / fparser

This project maintains and develops a Fortran parser called fparser2 written purely in Python which supports Fortran 2003 and some Fortran 2008. A legacy parser fparser1 is also available but is not supported. The parsers were originally part of the f2py project by Pearu Peterson.
https://fparser.readthedocs.io
Other
61 stars 28 forks source link

[F2008] F2008 constructs/statements don't work in blocks #326

Closed ZedThree closed 1 year ago

ZedThree commented 2 years ago

While looking at implementing #320, I discovered that F2008-specific features don't work inside blocks. The following two tests demonstrate this for error stop:

def test_functional3(f2008_parser):
    '''Test error-stop-stmt is matched in a do loop.'''
    tree = f2008_parser(get_reader('''\
do
error stop
end do
    '''))
    assert walk(tree, Error_Stop_Stmt)
    assert 'ERROR STOP' in str(tree)

def test_functional4(f2008_parser):
    '''Test error-stop-stmt is matched in an if block.'''
    tree = f2008_parser(get_reader('''\
if (.true.) then
error stop
end if
    '''))
    assert walk(tree, Error_Stop_Stmt)
    assert 'ERROR STOP' in str(tree)

Both raising:

E           fparser.two.utils.FortranSyntaxError: at line 2
E           >>>error stop

src/fparser/two/Fortran2003.py:241: FortranSyntaxError

I think this is because the modified F2003 classes (for example, Action_Stmt here) don't get their subclasses updated. Here's some output from putting a breakpoint() just before https://github.com/stfc/fparser/blob/58f903d011642ea76738074203257d6cda225f75/src/fparser/two/parser.py#L161

(Pdb) p "Error_Stop_Stmt" in dict(f2008_cls_members)["Action_Stmt"].subclass_names
True
(Pdb) p "Error_Stop_Stmt" in dict(f2008_cls_members)["Action_Stmt"].subclasses
False
ZedThree commented 2 years ago

I think this is related to #297. Adding the tests in my first comment and running them like:

pytest src/fparser/two/tests/fortran2008/test_error_stop_stmt_r856.py::test_functional3

works but

pytest -k test_functional3

fails. This is because the first only finds that one test and runs it, while the second finds all tests and only runs the selected one.

To demonstrate, try the following test:

def test_error_stmt_exists(f2008_create):
    assert "Error_Stop_Stmt" in [x.__name__ for x in Base.subclasses["Execution_Part_Construct"]]

and see the difference between

# Passes
pytest src/fparser/two/tests/fortran2008/test_error_stop_stmt_r856.py::test_error_stmt_exists
# Fails
pytest -k test_error_stmt_exists

I suspect the solution requires #191 in order to remove all the global state as creating a parser modifies the class objects themselves, as opposed to instances of them.

sergisiso commented 1 year ago

@ZedThree We merged the block and critical construct support PR. Can this be closed now?

ZedThree commented 1 year ago

Yes, looks like this works now