diff --git a/tools/isledecomp/isledecomp/parser/error.py b/tools/isledecomp/isledecomp/parser/error.py index 8bda90da..dce99448 100644 --- a/tools/isledecomp/isledecomp/parser/error.py +++ b/tools/isledecomp/isledecomp/parser/error.py @@ -18,9 +18,6 @@ class ParserError(Enum): # to handle it 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 MISSED_END_OF_FUNCTION = 117 @@ -31,3 +28,6 @@ class ParserError(Enum): # with the preceding markers. # For example, a GLOBAL cannot follow FUNCTION/STUB INCOMPATIBLE_MARKER = 201 + + # ERROR: The line following a synthetic marker was not a comment + BAD_SYNTHETIC = 202 diff --git a/tools/isledecomp/isledecomp/parser/parser.py b/tools/isledecomp/isledecomp/parser/parser.py index cea4523c..24dc0b23 100644 --- a/tools/isledecomp/isledecomp/parser/parser.py +++ b/tools/isledecomp/isledecomp/parser/parser.py @@ -7,7 +7,7 @@ is_blank_or_comment, match_marker, is_marker_exact, - get_template_function_name, + get_synthetic_name, remove_trailing_comment, ) from .node import ( @@ -307,9 +307,13 @@ def read_line(self, line: str): if self.state == ReaderState.IN_TEMPLATE: # TEMPLATE functions are a special case. The signature is # given on the next line (in a // comment) - self.function_sig = get_template_function_name(line) - self._function_starts_here() - self._function_done() + name = get_synthetic_name(line) + if name is None: + self._syntax_error(ParserError.BAD_SYNTHETIC) + else: + self.function_sig = name + self._function_starts_here() + self._function_done() elif self.state == ReaderState.WANT_SIG: # Skip blank lines or comments that come after the offset diff --git a/tools/isledecomp/isledecomp/parser/util.py b/tools/isledecomp/isledecomp/parser/util.py index 38515cfa..e0b25d85 100644 --- a/tools/isledecomp/isledecomp/parser/util.py +++ b/tools/isledecomp/isledecomp/parser/util.py @@ -23,15 +23,15 @@ trailingCommentRegex = re.compile(r"(\s*(?://|/\*).*)$") -def get_template_function_name(line: str) -> str: - """Parse function signature for special TEMPLATE functions""" +def get_synthetic_name(line: str) -> str | None: + """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) - # If we don't match, you get whatever is on the line as the signature if template_match is not None: return template_match.group(1) - return line + return None def remove_trailing_comment(line: str) -> str: diff --git a/tools/isledecomp/tests/test_parser.py b/tools/isledecomp/tests/test_parser.py index ce8ad307..222a9ac1 100644 --- a/tools/isledecomp/tests/test_parser.py +++ b/tools/isledecomp/tests/test_parser.py @@ -228,7 +228,6 @@ def test_synthetic_same_module(parser): assert parser.functions[0].offset == 0x1234 -@pytest.mark.skip(reason="todo") def test_synthetic_no_comment(parser): """Synthetic marker followed by a code line (i.e. non-comment)""" parser.read_lines( @@ -238,6 +237,9 @@ def test_synthetic_no_comment(parser): ] ) 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):