Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ae41c50
#390 Start to add support for linemarker.
hiker Apr 12, 2026
5e124e5
#390 Improve linermarker handling to support detection of invalid mar…
hiker Apr 13, 2026
7e482a2
#390 Simplified parameterization.
hiker Apr 16, 2026
88a74ee
#390 Fix incorrect linemarker specification in comment.
hiker Apr 16, 2026
8eb3954
#390 Remove need for using an additional regex to verify the linemark…
hiker Apr 16, 2026
fedc82c
#390 Updated manual.
hiker Apr 22, 2026
8480ccf
#390 Updated comments and added proper typing.
hiker Apr 22, 2026
b5e1f9f
#390 Added test that preprocessor directives are indeed properly pars…
hiker Apr 22, 2026
76441b6
#390 Moved location of preprocessor directive (which means it is now …
hiker Apr 22, 2026
099a818
#390 Fixed black.
hiker Apr 22, 2026
1634379
#390 Fix for github black, my black does not need that comma.
hiker Apr 22, 2026
27c7817
#390 Fix missing ',' which resulted in incorrectly concatenating stri…
hiker Apr 28, 2026
09099bf
Merge remote-tracking branch 'origin/master' into 390_ignore_linemarkers
hiker Apr 28, 2026
773ff8a
#390 Fixed previous fix - oops.
hiker Apr 28, 2026
c220665
Merge branch 'master' into 390_ignore_linemarkers
arporter Jun 4, 2026
f7172b3
#390 Covered missing line with test, fixed comments and coding style.
hiker Jun 9, 2026
50da372
#390 Undo my fix to limit line length to 80, since apparently black p…
hiker Jun 9, 2026
267eb90
#390 Undo yet another fix to limit line length to 80, since apparentl…
hiker Jun 9, 2026
ddb78ac
#390 update changelog
arporter Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/fparser/two/C99Preprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""C99 Preprocessor Syntax Rules."""
"""C99 Preprocessor Syntax Rules. It also supports linemarker statements
(which are technically not preprocessor directives, but are very close
Comment thread
arporter marked this conversation as resolved.
in their syntax, i.e. starting with `#`)

"""

# Author: Balthasar Reuter <balthasar.reuter@ecmwf.int>
# Based on previous work by Martin Schlipf (https://github.com/martin-schlipf)
Expand All @@ -57,6 +61,7 @@
"Cpp_Macro_Stmt",
"Cpp_Undef_Stmt",
"Cpp_Line_Stmt",
"Cpp_Linemarker_Stmt",
"Cpp_Error_Stmt",
"Cpp_Warning_Stmt",
"Cpp_Null_Stmt",
Expand Down Expand Up @@ -649,6 +654,55 @@ def tostr(self):
return "{0} {1}".format(*self.items)


class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker
"""
Linemarker
Comment thread
arporter marked this conversation as resolved.
Outdated

linemarker-stmt is # digit-sequence "s-char-sequence" [digit ...]
"""

subclass_names = []
use_names = ["Cpp_Pp_Tokens"]

# The match method will check that it is a valid linemarker, i.e.
# it has a line number, and file name in double quotes.
_pattern = pattern.Pattern("<linemarker>", r"^\s*#\s+\d+\s+\".*\".*$")

@staticmethod
def match(string):
"""Implements the matching for a linemarker.
The right hand side of the directive is not matched any further
Comment thread
arporter marked this conversation as resolved.
Outdated
but simply kept as a string.

:param str string: the string to match with as a line statement.

:return: a tuple of size 1 with the right hand side as a string, \
Comment thread
arporter marked this conversation as resolved.
Outdated
or `None` if there is no match.
:rtype: (`str`) or `NoneType`

"""
if not string:
return None
Comment thread
arporter marked this conversation as resolved.

return WORDClsBase.match(
Cpp_Linemarker_Stmt._pattern,
Cpp_Pp_Tokens,
string,
colons=False,
require_cls=False,
)

def tostr(self):
Comment thread
arporter marked this conversation as resolved.
Outdated
"""
Returns the line marker as string. Note that fparser accepts
spaces before the `#`, but it should remove the spaces, hence
we lstrip the result
:return: this linemarker as a string.
Comment thread
arporter marked this conversation as resolved.
:rtype: str
"""
return self.items[0].lstrip()


class Cpp_Error_Stmt(WORDClsBase): # 6.10.5 Error directive
"""
C99 6.10.5 Error directive
Expand Down
25 changes: 25 additions & 0 deletions src/fparser/two/tests/test_c99preprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
Cpp_Macro_Identifier_List,
Cpp_Undef_Stmt,
Cpp_Line_Stmt,
Cpp_Linemarker_Stmt,
Cpp_Error_Stmt,
Cpp_Warning_Stmt,
Cpp_Null_Stmt,
Expand Down Expand Up @@ -451,6 +452,30 @@ def test_incorrect_line_stmt(line):
assert "Cpp_Line_Stmt: '{0}'".format(line) in str(excinfo.value)


@pytest.mark.usefixtures("f2003_create")
@pytest.mark.parametrize(
"line, ref",
[
('# 123 "file"', '# 123 "file"'),
(' # 123 "file"', '# 123 "file"'),
('# 123 "file" 1 3', '# 123 "file" 1 3'),
],
)
def test_linemarker(line, ref):
"""Test that #line is recognized"""
result = Cpp_Linemarker_Stmt(line)
assert str(result) == ref


@pytest.mark.usefixtures("f2003_create")
@pytest.mark.parametrize("line", ["# abc", '# "bla"', "# 123 'wrong_quotes'"])
def test_incorrect_linemarker(line):
"""Test that incorrectly formed #line statements raise exception"""
with pytest.raises(NoMatchError) as excinfo:
_ = Cpp_Linemarker_Stmt(line)
assert "Cpp_Linemarker_Stmt: '{0}'".format(line) in str(excinfo.value)


@pytest.mark.usefixtures("f2003_create")
@pytest.mark.parametrize("line", ["#error MSG", " # error MSG "])
def test_error_statement_with_msg(line):
Expand Down
7 changes: 6 additions & 1 deletion src/fparser/two/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1819,7 +1819,12 @@ def match(keyword, cls, string, colons=False, require_cls=False):
if my_match is None:
return None
line = string[len(my_match.group()) :]
pattern_value = keyword.value
# If no constant return value is defined,
Comment thread
arporter marked this conversation as resolved.
Outdated
# return the matched string
if keyword.value:
pattern_value = keyword.value
else:
pattern_value = my_match.group()

if not line:
if require_cls:
Expand Down
Loading