Be more strict about synthetic name syntax

This commit is contained in:
disinvite 2023-12-01 19:58:40 -05:00
parent 806720f5c9
commit 9947231f6d
4 changed files with 18 additions and 12 deletions

View File

@ -18,9 +18,6 @@ class ParserError(Enum):
# to handle it # to handle it
BOGUS_MARKER = 104 BOGUS_MARKER = 104
# WARN: Under a synthetic marker we expected a comment but found a code line instead
SYNTHETIC_NOT_COMMENT = 110
# WARN: New function marker appeared while we were inside a function # WARN: New function marker appeared while we were inside a function
MISSED_END_OF_FUNCTION = 117 MISSED_END_OF_FUNCTION = 117
@ -31,3 +28,6 @@ class ParserError(Enum):
# with the preceding markers. # with the preceding markers.
# For example, a GLOBAL cannot follow FUNCTION/STUB # For example, a GLOBAL cannot follow FUNCTION/STUB
INCOMPATIBLE_MARKER = 201 INCOMPATIBLE_MARKER = 201
# ERROR: The line following a synthetic marker was not a comment
BAD_SYNTHETIC = 202

View File

@ -7,7 +7,7 @@
is_blank_or_comment, is_blank_or_comment,
match_marker, match_marker,
is_marker_exact, is_marker_exact,
get_template_function_name, get_synthetic_name,
remove_trailing_comment, remove_trailing_comment,
) )
from .node import ( from .node import (
@ -307,9 +307,13 @@ def read_line(self, line: str):
if self.state == ReaderState.IN_TEMPLATE: if self.state == ReaderState.IN_TEMPLATE:
# TEMPLATE functions are a special case. The signature is # TEMPLATE functions are a special case. The signature is
# given on the next line (in a // comment) # given on the next line (in a // comment)
self.function_sig = get_template_function_name(line) name = get_synthetic_name(line)
self._function_starts_here() if name is None:
self._function_done() self._syntax_error(ParserError.BAD_SYNTHETIC)
else:
self.function_sig = name
self._function_starts_here()
self._function_done()
elif self.state == ReaderState.WANT_SIG: elif self.state == ReaderState.WANT_SIG:
# Skip blank lines or comments that come after the offset # Skip blank lines or comments that come after the offset

View File

@ -23,15 +23,15 @@
trailingCommentRegex = re.compile(r"(\s*(?://|/\*).*)$") trailingCommentRegex = re.compile(r"(\s*(?://|/\*).*)$")
def get_template_function_name(line: str) -> str: def get_synthetic_name(line: str) -> str | None:
"""Parse function signature for special TEMPLATE functions""" """Synthetic names appear on a single line comment on the line after the marker.
If that's not what we have, return None"""
template_match = templateCommentRegex.match(line) template_match = templateCommentRegex.match(line)
# If we don't match, you get whatever is on the line as the signature
if template_match is not None: if template_match is not None:
return template_match.group(1) return template_match.group(1)
return line return None
def remove_trailing_comment(line: str) -> str: def remove_trailing_comment(line: str) -> str:

View File

@ -228,7 +228,6 @@ def test_synthetic_same_module(parser):
assert parser.functions[0].offset == 0x1234 assert parser.functions[0].offset == 0x1234
@pytest.mark.skip(reason="todo")
def test_synthetic_no_comment(parser): def test_synthetic_no_comment(parser):
"""Synthetic marker followed by a code line (i.e. non-comment)""" """Synthetic marker followed by a code line (i.e. non-comment)"""
parser.read_lines( parser.read_lines(
@ -238,6 +237,9 @@ def test_synthetic_no_comment(parser):
] ]
) )
assert len(parser.functions) == 0 assert len(parser.functions) == 0
assert len(parser.alerts) == 1
assert parser.alerts[0].code == ParserError.BAD_SYNTHETIC
assert parser.state == ReaderState.SEARCH
def test_single_line_function(parser): def test_single_line_function(parser):