Skip to content

Add 'format-missing-comma' extension (closes #484) - #526

Open
DisciplinedSoftware wants to merge 3 commits into
stfc:masterfrom
DisciplinedSoftware:484_format_missing_comma
Open

Add 'format-missing-comma' extension (closes #484)#526
DisciplinedSoftware wants to merge 3 commits into
stfc:masterfrom
DisciplinedSoftware:484_format_missing_comma

Conversation

@DisciplinedSoftware

Copy link
Copy Markdown

Closes #484.

Many compilers (gfortran, ifort, ifx) accept a missing comma between a character-string edit descriptor and a neighbouring format item:

100 format('a' 1x,'b')   ! literal then descriptor
200 format(15x'a')       ! descriptor then literal (the #484 example)
300 format('a' 'b')      ! adjacent literals

Following the convention described in the developer guide, this adds a format-missing-comma entry to the EXTENSIONS list in utils.py (enabled by default, like the other extensions) and implements the relaxation in Format_Item_C1002:

  • the existing match body becomes _standard_match (unchanged logic);
  • match now runs the standard pass first and only falls back to _extension_match when the standard pass finds no match and the extension is enabled — so standard-conforming code produces exactly the same tree as before (the standard pass can raise NoMatchError from an eagerly-taken branch, which previously aborted matching entirely; it is now treated as no-match so the fallback can run);
  • _extension_match splits the item at the boundary of the first character literal and matches both sides as Format_Items.

The full example from #484 parses with this change (verified verbatim). Also found independently while parsing MODFLOW-2005 (gwf2swr7.f, gwf2swi27.fpp, gwf2lak7.f, gwf2sfr7.f).

Two pre-existing negative tests in test_syntaxerror_c1002 asserted NoMatchError for exactly the constructs this extension legalizes (('hello' 2/), ('hello' 'hello')); they now assert the new behavior with the extension enabled and the old rejection with it disabled.

Note: re-generating a format specification from the parse tree re-introduces the omitted commas (consistent with how Format_Item_C1002 renders its item pairs); this is documented in the extension section of the docs.

  • pytest src/fparser passes (2950 passed, 24 xfailed, 1 pre-existing xpassed)
  • black clean
  • Extension documented in doc/source/fparser2.rst and the Format_Item_C1002 docstring
  • CHANGELOG.md updated (the PR-number placeholder will be filled in once this PR's number is known)

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings August 18, 2026 05:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new default-enabled parser extension, format-missing-comma, to accept missing commas between character-string edit descriptors and adjacent format items in FORMAT specifications (as supported by common compilers), addressing issue #484 and updating tests/docs accordingly.

Changes:

  • Add format-missing-comma to the default EXTENSIONS list.
  • Extend Format_Item_C1002 matching with an extension-aware fallback path to parse missing-comma constructs involving character literals.
  • Update/expand tests and user documentation (plus changelog) to reflect the new extension and its behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/fparser/two/utils.py Registers the new format-missing-comma extension as enabled by default.
src/fparser/two/Fortran2003.py Implements the extension logic in Format_Item_C1002 and adds helper for splitting character literals.
src/fparser/two/tests/fortran2003/test_format_specification_r1002.py Updates negative/positive expectations for C1002-related missing-comma cases with the extension enabled/disabled.
src/fparser/two/tests/fortran2003/test_format_item_c1002.py Adds direct tests covering the new missing-comma parsing behavior and disabled-extension behavior.
doc/source/fparser2.rst Documents the new extension and notes re-generation behavior (commas reintroduced).
CHANGELOG.md Records the new extension addition.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/fparser/two/Fortran2003.py Outdated
Comment on lines +10055 to +10058
if not string or string[0] not in "'\"":
return None
quote = string[0]
index = 1

@DisciplinedSoftware DisciplinedSoftware Aug 18, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional: a char-string-edit-desc may not have a kind parameter — F2008 (J3/10-007r1) 10.3.2, C1013 (R1021): "A kind parameter shall not be specified for the char-literal-constant"; likewise F2003 (WG5/N1601) 10.2.1, C1012 (R1019). Compilers enforce this (e.g. gfortran rejects FORMAT(4_'a')), so since this extension exists to mirror what compilers accept for missing commas, recognising kind-prefixed literals here would accept code that is invalid both per the standard and per the compilers. Happy to add kind-param handling if the maintainers prefer consistency with fparser's (lax) Char_Literal_Constant instead.

@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.28571% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.25%. Comparing base (cfdc2f7) to head (8d7c04a).

Files with missing lines Patch % Lines
src/fparser/two/Fortran2003.py 94.11% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master     #526   +/-   ##
=======================================
  Coverage   92.25%   92.25%           
=======================================
  Files          89       89           
  Lines       13891    13925   +34     
=======================================
+ Hits        12815    12847   +32     
- Misses       1076     1078    +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@arporter arporter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much @DisciplinedSoftware. I'm a bit concerned that this PR adds more character-string handling rather than re-using existing functionality. Given that this is always hard to get right, I'd be happier if the implementation could be refactored to avoid this.
We are also (slowly) in the process of modernising the docstrings so, for those that you've touched, I've asked that you remove the line-continuation characters and swap to using type hints.

ast = Format_Specification("('hello' 'hello')")
assert str(ast) == "('hello', 'hello')"
# ... and is invalid syntax without the extension.
with monkeypatch.context() as mpatch:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be simpler to do (thanks @hiker):

 monkeypatch.setattr(utils, "_EXTENSIONS", [])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully this won't cause any problems as we're only testing very specific snippets here.
Please could you also make this simplification in the other places where you use monkeypatch like this.

Comment thread src/fparser/two/Fortran2003.py Outdated

:param str string: the string to split.

:returns: a 2-tuple containing the character literal and the \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the line-continuation chars (trailing slashes) and move the type information into type hints instead.

Comment thread src/fparser/two/Fortran2003.py Outdated
index = 1
while index < len(string):
if string[index] == quote:
if index + 1 < len(string) and string[index + 1] == quote:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This character-string handling makes me uneasy - it's complicated and we must do it elsewhere so it shouldn't be repeated here. Can the existing comma handling in the match method be modified to allow for char literals?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the discussion about kind parameters above, that method also needs tightening up so that it rejects char strings with kind parameters. However, as that's not directly the subject of this PR you can leave it unless it fits naturally.

Comment thread CHANGELOG.md Outdated
24/08/2026 PR #523 for #522. Adds an extension to support the (Intel-specific)
'directory=' and 'dirspec=' arguments to the INQUIRY function.

18/08/2026 PR #526 for #484. Add the 'format-missing-comma' extension: accept a

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert the change to the CHANGELOG.md as that needs to happen last.

@arporter arporter added reviewed with actions PR has been reviewed and is back with developer and removed under review labels Aug 25, 2026
Pierre-Luc Gagné and others added 3 commits August 25, 2026 22:15
Many compilers (gfortran, ifort, ifx) accept a missing comma between
a character-string edit descriptor and a neighbouring format item,
e.g. FORMAT('a' 1x,'b'), FORMAT(15x'a') or FORMAT('a' 'b').

Following the extension convention, 'format-missing-comma' is added
to the EXTENSIONS list in utils.py and the relaxation is implemented
in Format_Item_C1002, whose match logic is split into the standard
C1002 pass and an extension fallback. Found while parsing MODFLOW-2005
(gwf2swr7.f, gwf2swi27.fpp, gwf2lak7.f, gwf2sfr7.f); also covers the
example in issue stfc#484.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
arporter (review on stfc#526): reimplementing quote/escape handling for
character literals is error-prone and duplicates logic that already
exists elsewhere in this file. _standard_match() already masks
literals via string_replace_map() before splitting on '/' and ':';
_extension_match() now uses the same masking to find literal
boundaries instead of the bespoke split_leading_char_literal()
helper, which is removed. Also modernises the docstrings touched by
this PR (type hints instead of line-continuation backslashes), per
the same review.
arporter/hiker (review on stfc#526): monkeypatch.setattr(utils,
"_EXTENSIONS", []) is simpler than filtering EXTENSIONS() by name,
and is safe here since these tests only exercise narrow snippets.
@DisciplinedSoftware

Copy link
Copy Markdown
Author

Thanks for the review, @arporter — I've pushed updates addressing all three points:

  • Character-string handling: _extension_match() no longer reimplements quote/escape parsing. It now reuses string_replace_map() — the same masking _standard_match() already uses for the / and : splits — to locate the character-literal boundary, and the bespoke split_leading_char_literal() helper is removed.
  • Docstrings: the docstrings touched by this PR (match(), _standard_match(), _extension_match()) now use type hints in the signature instead of \-continued :param str ...:/:rtype: blocks.
  • Tests: all three monkeypatch blocks added by this PR now use monkeypatch.setattr(utils, "_EXTENSIONS", []) as suggested.

I've also reverted the CHANGELOG.md entry from the branch entirely (not just the working tree) so it won't collide on a future rebase/merge — happy to add it back at the end per your note that it should happen last.

Left the kind-parameter tightening in _standard_match's comma handling out for now, per your comment that it's optional and doesn't directly relate to this PR.

Full test suite passes locally (2951 passed, 24 xfailed, 1 xpassed).

@arporter arporter added under review and removed reviewed with actions PR has been reviewed and is back with developer labels Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some commas in format specifiers are optional

3 participants