parser: Identify namespaces (#499)

This commit is contained in:
MS
2024-01-28 09:25:45 -05:00
committed by GitHub
parent d9c4151bb8
commit 4137cd75e6
6 changed files with 280 additions and 7 deletions

View File

@@ -0,0 +1,73 @@
# nyuk nyuk nyuk
import pytest
from isledecomp.parser.parser import CurlyManager
from isledecomp.parser.util import sanitize_code_line
@pytest.fixture(name="curly")
def fixture_curly():
return CurlyManager()
def test_simple(curly):
curly.read_line("namespace Test {")
assert curly.get_prefix() == "Test"
curly.read_line("}")
assert curly.get_prefix() == ""
def test_oneliner(curly):
"""Should not go down into a scope for a class forward reference"""
curly.read_line("class LegoEntity;")
assert curly.get_prefix() == ""
# Now make sure that we still would not consider that class name
# even after reading the opening curly brace
curly.read_line("if (true) {")
assert curly.get_prefix() == ""
def test_ignore_comments(curly):
curly.read_line("namespace Test {")
curly.read_line("// }")
assert curly.get_prefix() == "Test"
@pytest.mark.xfail(reason="todo: need a real lexer")
def test_ignore_multiline_comments(curly):
curly.read_line("namespace Test {")
curly.read_line("/*")
curly.read_line("}")
curly.read_line("*/")
assert curly.get_prefix() == "Test"
curly.read_line("}")
assert curly.get_prefix() == ""
def test_nested(curly):
curly.read_line("namespace Test {")
curly.read_line("namespace Foo {")
assert curly.get_prefix() == "Test::Foo"
curly.read_line("}")
assert curly.get_prefix() == "Test"
sanitize_cases = [
("", ""),
(" ", ""),
("{", "{"),
("// comments {", ""),
("{ // why comment here", "{"),
("/* comments */ {", "{"),
('"curly in a string {"', '""'),
('if (!strcmp("hello { there }", g_test)) {', 'if (!strcmp("", g_test)) {'),
("'{'", "''"),
("weird_function('\"', hello, '\"')", "weird_function('', hello, '')"),
]
@pytest.mark.parametrize("start, end", sanitize_cases)
def test_sanitize(start: str, end: str):
"""Make sure that we can remove curly braces in places where they should
not be considered as part of the semantic structure of the file.
i.e. inside strings or chars, and inside comments"""
assert sanitize_code_line(start) == end

View File

@@ -48,6 +48,7 @@ vtable_cases = [
("??_7LegoCarBuildAnimPresenter@@6B@", "LegoCarBuildAnimPresenter"),
("??_7?$MxCollection@PAVLegoWorld@@@@6B@", "MxCollection<LegoWorld *>"),
("??_7?$MxPtrList@VLegoPathController@@@@6B@", "MxPtrList<LegoPathController>"),
("??_7Renderer@Tgl@@6B@", "Tgl::Renderer"),
]

View File

@@ -521,3 +521,111 @@ def test_string_ignore_g_prefix(parser):
)
assert len(parser.strings) == 1
assert len(parser.alerts) == 0
def test_class_variable(parser):
"""We should accurately name static variables that are class members."""
parser.read_lines(
[
"class Test {",
"protected:",
" // GLOBAL: TEST 0x1234",
" static int g_test;",
"};",
]
)
assert len(parser.variables) == 1
assert parser.variables[0].name == "Test::g_test"
def test_namespace_variable(parser):
"""We should identify a namespace surrounding any global variables"""
parser.read_lines(
[
"namespace Test {",
"// GLOBAL: TEST 0x1234",
"int g_test = 1234;",
"}",
"// GLOBAL: TEST 0x5555",
"int g_second = 2;",
]
)
assert len(parser.variables) == 2
assert parser.variables[0].name == "Test::g_test"
assert parser.variables[1].name == "g_second"
def test_namespace_vtable(parser):
parser.read_lines(
[
"namespace Tgl {",
"// VTABLE: TEST 0x1234",
"class Renderer {",
"};",
"}",
"// VTABLE: TEST 0x5555",
"class Hello { };",
]
)
assert len(parser.vtables) == 2
assert parser.vtables[0].name == "Tgl::Renderer"
assert parser.vtables[1].name == "Hello"
def test_global_prefix_namespace(parser):
"""Should correctly identify namespaces before checking for the g_ prefix"""
parser.read_lines(
[
"class Test {",
" // GLOBAL: TEST 0x1234",
" static int g_count = 0;",
" // GLOBAL: TEST 0x5555",
" static int count = 0;",
"};",
]
)
assert len(parser.variables) == 2
assert parser.variables[0].name == "Test::g_count"
assert parser.variables[1].name == "Test::count"
assert len(parser.alerts) == 1
assert parser.alerts[0].code == ParserError.GLOBAL_MISSING_PREFIX
def test_nested_namespace(parser):
parser.read_lines(
[
"namespace Tgl {",
"class Renderer {",
" // GLOBAL: TEST 0x1234",
" static int g_count = 0;",
"};",
"};",
]
)
assert len(parser.variables) == 1
assert parser.variables[0].name == "Tgl::Renderer::g_count"
def test_match_qualified_variable(parser):
"""If a variable belongs to a scope and we use a fully qualified reference
below a GLOBAL marker, make sure we capture the full name."""
parser.read_lines(
[
"// GLOBAL: TEST 0x1234",
"int MxTest::g_count = 0;",
]
)
assert len(parser.variables) == 1
assert parser.variables[0].name == "MxTest::g_count"
assert len(parser.alerts) == 0