diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b7f83b3..151f365a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,11 @@ Modifications by (in alphabetical order): * P. Vitt, University of Siegen, Germany * A. Voysey, UK Met Office -15/05/2023 PR #415 for #165. Bug fix for spurious matching of 'NAMELIST' in - certain contexts. +16/05/2023 PR #414 for #412. Bug fix for disappearing line when parsing + include files. + +15/05/2023 PR #415 for #165. Bug fix for code aborting when trying to match + 'NAMELIST' in certain contexts. 15/05/2023 PR #408 for #403. Add support for the F2008 DO CONCURRENT. diff --git a/src/fparser/common/readfortran.py b/src/fparser/common/readfortran.py index 16480fd0..a5f886d4 100644 --- a/src/fparser/common/readfortran.py +++ b/src/fparser/common/readfortran.py @@ -745,8 +745,19 @@ def get_item(self, ignore_comments=None): return item def put_item(self, item): - """Insert item to FIFO item buffer.""" - self.fifo_item.insert(0, item) + """Insert item into FIFO buffer of 'innermost' reader object. + + :param item: the item to insert into the FIFO. + :type item: :py:class:`fparser.common.readfortran.Line` | \ + :py:class:`fparser.common.readfortran.MultiLine` | \ + :py:class:`fparser.common.readfortran.Comment` + """ + if self.reader: + # We are reading an INCLUDE file so put this item in the FIFO + # of the corresponding reader. + self.reader.put_item(item) + else: + self.fifo_item.insert(0, item) # Iterator methods: @@ -767,7 +778,7 @@ def next(self, ignore_comments=None): value. :returns: the next line item. This can be from a local fifo \ - buffer, from an include reader or from this reader. + buffer, from an include reader or from this reader. :rtype: py:class:`fparser.common.readfortran.Line` :raises StopIteration: if no more lines are found. @@ -780,7 +791,6 @@ def next(self, ignore_comments=None): if self.reader is not None: # inside INCLUDE statement try: - # Return a line from the include. return self.reader.next(ignore_comments) except StopIteration: # There is nothing left in the include diff --git a/src/fparser/common/tests/test_readfortran.py b/src/fparser/common/tests/test_readfortran.py index a3b7f5ab..05d48bb9 100644 --- a/src/fparser/common/tests/test_readfortran.py +++ b/src/fparser/common/tests/test_readfortran.py @@ -680,20 +680,46 @@ def test_put_item(ignore_comments): assert fifo_line == orig_line -def test_put_item_include(ignore_comments): +def test_put_item_include(ignore_comments, tmpdir): """Check that when a line that has been included via an include statement is consumed it can be pushed back so it can be consumed again. Test with and without ignoring comments. """ - reader = FortranStringReader(FORTRAN_CODE, ignore_comments=ignore_comments) + _ = tmpdir.chdir() + cwd = str(tmpdir) + include_code = """ + var1 = 1 + var2 = 2 + var3 = 3 +""" + with open(os.path.join(cwd, "my_include.h"), "w") as cfile: + cfile.write(include_code) + code = """ +program my_prog + integer :: var1, var2, var3 + include 'my_include.h' +end program my_prog +""" + reader = FortranStringReader(code, ignore_comments=ignore_comments) + lines = [] while True: - orig_line = reader.get_item() - if not orig_line: + lines.append(reader.get_item()) + # Try immediately putting the line back and then requesting it again. + # This checks that the correct FIFO buffer is being used. + reader.put_item(lines[-1]) + assert reader.get_item().line == lines[-1].line + if "var3 =" in lines[-1].line: + # Stop reading while we're still in the INCLUDE file so that we + # have a stack of readers when calling `put_item` below. break - reader.put_item(orig_line) - fifo_line = reader.get_item() - assert fifo_line == orig_line + # Put all the lines back in the same order that we saw them. + for line in reversed(lines): + reader.put_item(line) + # Check that the reader returns all those lines in the same order that + # we saw them originally. + for line in lines: + assert reader.get_item().line == line.line def test_multi_put_item(ignore_comments):