Skip to content

390 ignore linemarkers#498

Merged
arporter merged 19 commits into
masterfrom
390_ignore_linemarkers
Jun 9, 2026
Merged

390 ignore linemarkers#498
arporter merged 19 commits into
masterfrom
390_ignore_linemarkers

Conversation

@hiker

@hiker hiker commented Apr 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes #390 by supporting linemarkers (# 123 "test.f90" - indicating line number and file).

I have used the existing preprocessor directive support, since linemarkers looks pretty much like a preprocessor directive (starting with #). But I was unable to get it to verify properly out of the box - I feel like the existing implementation assumes that the value is constant (e.g. #ifdef), while in the case of a linemarker we don't have this (since it would need the line number and filename to verify correctness, and I couldn't work out how to do this). While it worked this way, it was unable to detect invalid linemarkers (# abc "xx.f90" or # 123 'no_single_quote_allowed.f90'). So, instead I added a simple regex check at the beginning, and only if that passes, it will use the established path.

I am happy to reimplement (I know there is pattern_tools.digit_string and file_name ... I just couldn't figure out how to plug this all together.

@hiker

hiker commented Apr 13, 2026

Copy link
Copy Markdown
Collaborator Author

I could also not find an official syntax for a linemaker, but looked at https://git.cels.anl.gov/ksalapenades/llvm-project/-/blob/develop/clang/test/Preprocessor/line-directive.c (and did some compiler tests to verify what gets rejected)

@codecov

codecov Bot commented Apr 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.24%. Comparing base (73e31b5) to head (ddb78ac).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #498   +/-   ##
=======================================
  Coverage   92.23%   92.24%           
=======================================
  Files          88       88           
  Lines       13852    13866   +14     
=======================================
+ Hits        12776    12790   +14     
  Misses       1076     1076           

☔ 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.

@hiker

hiker commented Apr 13, 2026

Copy link
Copy Markdown
Collaborator Author

Checking the git log, it appears this code was contributed by @reuterbal - I wonder if you would have time to provide some feedback? Thanks!

@reuterbal reuterbal 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.

Happy to provide my 2ct here. I agree that linemarkers should be handled like preprocessor directives and the implementation itself looks good to me.

As for the need for the additional regex validation: I believe you only need to encode the full linemarker specification as a regex pattern to use in WORDClsBase.match - either manually or using the building blocks in pattern_tools - e.g., like here:

part_ref = name + ~((r"[(]" + name + r"[)]"))

Without testing it, I would expect this would maybe need to look like something like this:

_pattern = r"^\s*#\s+" +  digit_string + "\s+" + file_name

Comment thread src/fparser/two/tests/test_c99preprocessor.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py Outdated
@hiker

hiker commented Apr 16, 2026

Copy link
Copy Markdown
Collaborator Author

Hi Balthasar,

thanks a lot for the quick review, really appreciated.

Happy to provide my 2ct here. I agree that linemarkers should be handled like preprocessor directives and the implementation itself looks good to me.

I am glad that I made the right decision here :)

As for the need for the additional regex validation: I believe you only need to encode the full linemarker specification as a regex pattern to use in WORDClsBase.match - either manually or using the building blocks in pattern_tools - e.g., like here:

part_ref = name + ~((r"[(]" + name + r"[)]"))

Without testing it, I would expect this would maybe need to look like something like this:

_pattern = r"^\s*#\s+" +  digit_string + "\s+" + file_name

I tried that, and thanks a lot for the example. Looking at the +digit_string..., made me realise that Pattern overwrites __add_-, but that doesn't work here since the first expression is a string. But I could use digit_string.pattern etc. But then file_name.pattern started with ^, so I couldn't use this. And since digit_string.pattern was pretty long with no apparent advantage over \d+, I actually just removed it and used a simple regex instead.

But then I am stuck with my original problem: I am using:

    _pattern = pattern.Pattern("<linemarker>", r"^\s*#\s+\d+\s+\".*\"")

But if I do this, the matching in WORDClsBase uses _pattern.value ... which is None. _pattern.value is a string, so I can set it to # (which I did in the state that you reviewed it), but then I don't get the rest of the match: The match function basically does:

           my_match = keyword.match(string)
            if my_match is None:
                return None
            line = string[len(my_match.group()) :]
            pattern_value = keyword.value
...

Basically, the rest of the match is discarded (line number and filename) :(

I tried to fix that using:

           my_match = keyword.match(string)
            if my_match is None:
                return None
            line = string[len(my_match.group()) :]
            if keyword.value:
                pattern_value = keyword.value
            else:
                pattern_value = my_match.group()

So, I provide value=None for the linemarker class, and that then triggers returning the fully matched string, including line numbers and filename.

This passed nearly all tests, except it would not remove spaces between "#" and line number and line number and file name. Therefore, I adjusted one linemarker test (but the test still checks that leading spaces before the # are removed, which is consistent with other code in C99_preprocessor). Small changes to __str__ were required.

I am not sure if this is the right solution tbh :(

Maybe it should not be based on WORDClsBase, but instead use the full grammar? But that also feels like an total overkill.

@reuterbal , @arporter , @sergisiso - feedback appreciated! The modification of the match function seems to have no other side effect, all tests were passing. But I am not keen on changing something that might be quite fundamental ;)

@reuterbal reuterbal 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.

Nice work, the details of the keyword/value returns were lost on me and your proposal seems sensible to me.
Overall I think that's indeed much better now, no further comments!

@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.

Looks good to me Joerg, thanks. I could do with a bit of help understanding some of the changes - probably because I know pretty much nothing about the Pattern class.
I think it would also be good to test the new functionality in context - i.e. provide some Fortran containing some linemarkers and check that things work OK.

Comment thread src/fparser/two/C99Preprocessor.py
Comment thread src/fparser/two/C99Preprocessor.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py
Comment thread src/fparser/two/utils.py Outdated
@arporter arporter added ready for review reviewed with actions PR has been reviewed and is back with developer and removed under review ready for review labels Apr 17, 2026
@hiker

hiker commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator Author

I've resolved Balthasar's comments, and addressed all new issues. Back for next review.

@hiker hiker added ready for review and removed reviewed with actions PR has been reviewed and is back with developer labels Apr 22, 2026
@hiker hiker requested a review from arporter April 22, 2026 01:33
@hiker

hiker commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator Author

@arporter I just remembered that pylint flagged one issue, which looks wrong, but I just wanted to make sure it's not done on purpose before fixing. In test_c99preprocessor.py there is:

    [
...
        "#definex",
        "#define 2a" "#define fail(...,test) test",
        "#define",
        "#define fail(...,...)",
    ],
...
test_c99preprocessor.py:369:0: W1404: Implicit string concatenation found in list (implicit-str-concat)

Adding a , between the two strings works (as in: all tests are passing). It just looks wrong to me :)

The original (pre-black) line was:

@pytest.mark.parametrize('line', [
-    None, '', ' ', '#def', '#defnie', '#definex', '#define 2a'
-    '#define fail(...,test) test', '#define', '#define fail(...,...)'])

Which comes from d44ad584:

@@ -259,7 +259,7 @@ def test_macro_stmt_with_whitespace(line, ref):
 
 @pytest.mark.usefixtures("f2003_create")
 @pytest.mark.parametrize('line', [
-    None, '', ' ', '#def', '#defnie', '#definex',
+    None, '', ' ', '#def', '#defnie', '#definex', '#define 2a'
     '#define fail(...,test) test', '#define', '#define fail(...,...)'])
 def test_incorrect_macro_stmt(line):
     '''Test that incorrectly formed #define statements raise exception'''

Is it ok if I add the missing ,?

@reuterbal

Copy link
Copy Markdown

Nice catch, that was definitely a mistake when I expanded the test parameterisation. I'd say please add the missing ,.

@hiker

hiker commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the confirmation. Updated to current master, ready for review.

@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 Joerg, pretty much there now - just a couple of minor things to tidy up and then this can go on.

Comment thread src/fparser/two/C99Preprocessor.py Outdated
Comment thread src/fparser/two/utils.py Outdated
Comment thread src/fparser/two/C99Preprocessor.py
@arporter arporter added reviewed with actions PR has been reviewed and is back with developer and removed under review labels Jun 4, 2026
@hiker

hiker commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

All issues addressed, thanks! Ready for next review.

@hiker hiker requested a review from arporter June 9, 2026 08:40
@sergisiso

Copy link
Copy Markdown
Collaborator

Since this could be the last PR before a new release, I triggered the psyclone integration tests with this last fparser commit.

@arporter arporter added under review and removed reviewed with actions PR has been reviewed and is back with developer labels Jun 9, 2026

@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 Joerg. CodeCov is happy now and so am I :-)

@arporter arporter merged commit 65ea44f into master Jun 9, 2026
6 checks passed
@arporter arporter deleted the 390_ignore_linemarkers branch June 9, 2026 12:48
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.

Handle line markers

4 participants