Add 'format-missing-comma' extension (closes #484) - #526
Add 'format-missing-comma' extension (closes #484)#526DisciplinedSoftware wants to merge 3 commits into
Conversation
8ae7dad to
8baa74b
Compare
There was a problem hiding this comment.
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-commato the defaultEXTENSIONSlist. - Extend
Format_Item_C1002matching 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.
| if not string or string[0] not in "'\"": | ||
| return None | ||
| quote = string[0] | ||
| index = 1 |
There was a problem hiding this comment.
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.
8baa74b to
ef5b6a0
Compare
Codecov Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
arporter
left a comment
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
It would be simpler to do (thanks @hiker):
monkeypatch.setattr(utils, "_EXTENSIONS", [])
There was a problem hiding this comment.
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.
|
|
||
| :param str string: the string to split. | ||
|
|
||
| :returns: a 2-tuple containing the character literal and the \ |
There was a problem hiding this comment.
Please remove the line-continuation chars (trailing slashes) and move the type information into type hints instead.
| index = 1 | ||
| while index < len(string): | ||
| if string[index] == quote: | ||
| if index + 1 < len(string) and string[index + 1] == quote: |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
Please revert the change to the CHANGELOG.md as that needs to happen last.
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.
d6468cd to
8d7c04a
Compare
|
Thanks for the review, @arporter — I've pushed updates addressing all three points:
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 Full test suite passes locally (2951 passed, 24 xfailed, 1 xpassed). |
Closes #484.
Many compilers (gfortran, ifort, ifx) accept a missing comma between a character-string edit descriptor and a neighbouring format item:
Following the convention described in the developer guide, this adds a
format-missing-commaentry to theEXTENSIONSlist inutils.py(enabled by default, like the other extensions) and implements the relaxation inFormat_Item_C1002:matchbody becomes_standard_match(unchanged logic);matchnow runs the standard pass first and only falls back to_extension_matchwhen 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 raiseNoMatchErrorfrom an eagerly-taken branch, which previously aborted matching entirely; it is now treated as no-match so the fallback can run);_extension_matchsplits the item at the boundary of the first character literal and matches both sides asFormat_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_c1002assertedNoMatchErrorfor 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_C1002renders its item pairs); this is documented in the extension section of the docs.pytest src/fparserpasses (2950 passed, 24 xfailed, 1 pre-existing xpassed)blackcleandoc/source/fparser2.rstand theFormat_Item_C1002docstring🤖 Generated with Claude Code