Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
60 changes: 59 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
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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oops, I missed that, thanks.

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,59 @@ def tostr(self):
return "{0} {1}".format(*self.items)


class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker
"""
Linemarker
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.

A bit more detail would be good here. i.e. explain what a Linemarker is.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done.


linemarker-stmt is # digit-sequence [ "s-char-sequence" ] [digit ...]
Comment thread
hiker marked this conversation as resolved.
Outdated
"""

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*#", value="#")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note that most Fortran compilers don't accept white space in front of the # for preprocessor directives. Are they more forgiving for line markers?
But since fparser allows for white space in front of directives, it's probably wise to allow them for marker as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I actually remember that I was wondering about the \s at the beginning (since I did some testing originally, and knew it's not accepted). But since all regex here started with #\s* .. I just followed the trend :) And I'll agree to leave it in for consistency (and because I am afraid of breaking something).


@staticmethod
def match(string):
"""Implements the matching for a linemarker.
The right hand side of the directive is not matched any further
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.

What does the "right hand side of the directive" mean?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I've reworded that.

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, \
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.

No line-continuation and please update to use type hints.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

or `None` if there is no match.
:rtype: (`str`) or `NoneType`

"""
if not string:
return None

# We can't fully rely on WORDClsBase, since it can't easily
# test if there is a line number following (it returns
# `value` for a match, but can't insert the matched line number
# in this value).
if not re.match(r"^\s*#\s+[0-9]+\s+\".*\"", string):
return

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

def tostr(self):
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.

typehints pls.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done.

"""
:return: this linemarker as a string.
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.

Blank line before :return: please.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oops.

:rtype: str
"""
return "{0} {1}".format(*self.items)


class Cpp_Error_Stmt(WORDClsBase): # 6.10.5 Error directive
"""
C99 6.10.5 Error directive
Expand Down
26 changes: 26 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,31 @@ 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"""
line, ref = line_ref
Comment thread
hiker marked this conversation as resolved.
Outdated
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
Loading