Skip to content

Commit dcea187

Browse files
authored
Merge pull request #198 from Pennycook/refactor/platform-class
Move `Platform` class into preprocessor.py
2 parents f8a1d06 + 5091f4b commit dcea187

File tree

5 files changed

+126
-136
lines changed

5 files changed

+126
-136
lines changed

codebasin/finder.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414

1515
from tqdm import tqdm
1616

17-
from codebasin import CodeBase, file_parser, platform, preprocessor
17+
from codebasin import CodeBase, file_parser, preprocessor
1818
from codebasin.language import FileLanguage
19-
from codebasin.platform import Platform
20-
from codebasin.preprocessor import CodeNode, Node, SourceTree, Visit
19+
from codebasin.preprocessor import CodeNode, Node, Platform, SourceTree, Visit
2120

2221
log = logging.getLogger(__name__)
2322

@@ -229,7 +228,7 @@ def _potential_file_generator(
229228
leave=False,
230229
disable=not show_progress,
231230
):
232-
file_platform = platform.Platform(p, rootdir)
231+
file_platform = Platform(p, rootdir)
233232

234233
for path in e["include_paths"]:
235234
file_platform.add_include_path(path)

codebasin/platform.py

Lines changed: 0 additions & 118 deletions
This file was deleted.

codebasin/preprocessor.py

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,6 +1646,114 @@ def replace(
16461646
return substituted_tokens
16471647

16481648

1649+
class Platform:
1650+
"""
1651+
Represents a platform, and everything associated with a platform.
1652+
Contains a list of definitions, and include paths.
1653+
"""
1654+
1655+
def __init__(self, name: str, _root_dir: str) -> None:
1656+
self._definitions: dict[str, Macro | MacroFunction] = {}
1657+
self._skip_includes: list[str] = []
1658+
self._include_paths: list[str] = []
1659+
self._root_dir = _root_dir
1660+
self.name = name
1661+
self.found_incl: dict[str, str | None] = {}
1662+
1663+
def add_include_path(self, path: str) -> None:
1664+
"""
1665+
Insert a new path into the list of include paths for this
1666+
platform.
1667+
"""
1668+
self._include_paths.append(path)
1669+
1670+
def undefine(self, identifier: str) -> None:
1671+
"""
1672+
Undefine a macro for this platform, if it's defined.
1673+
"""
1674+
if identifier in self._definitions:
1675+
del self._definitions[identifier]
1676+
1677+
def define(self, identifier: str, macro: Macro | MacroFunction) -> None:
1678+
"""
1679+
Define a new macro for this platform, only if it's not already
1680+
defined.
1681+
"""
1682+
if identifier not in self._definitions:
1683+
self._definitions[identifier] = macro
1684+
1685+
def add_include_to_skip(self, fn: str) -> None:
1686+
"""
1687+
Add an include file to the skip list for this platform. The file will
1688+
not be processed when encountered in the include directives.
1689+
"""
1690+
if fn not in self._skip_includes:
1691+
self._skip_includes.append(fn)
1692+
1693+
def process_include(self, fn: str) -> bool:
1694+
"""
1695+
Return a boolean stating if this include file should be
1696+
processed or skipped.
1697+
"""
1698+
return fn not in self._skip_includes
1699+
1700+
# FIXME: This should return a bool, but the usage relies on a str.
1701+
def is_defined(self, identifier: str) -> str:
1702+
"""
1703+
Return a string representing whether the macro named by 'identifier' is
1704+
defined.
1705+
"""
1706+
if identifier in self._definitions:
1707+
return "1"
1708+
return "0"
1709+
1710+
def get_macro(self, identifier: str) -> Macro | MacroFunction | None:
1711+
"""
1712+
Return either a macro definition (if it's defined), or None.
1713+
"""
1714+
if identifier in self._definitions:
1715+
return self._definitions[identifier]
1716+
return None
1717+
1718+
def find_include_file(
1719+
self,
1720+
filename: str,
1721+
this_path: str,
1722+
is_system_include: bool = False,
1723+
) -> str | None:
1724+
"""
1725+
Determine and return the full path to an include file, named
1726+
'filename' using the include paths for this platform.
1727+
1728+
System includes do not include the rootdir, while local includes
1729+
do.
1730+
"""
1731+
try:
1732+
return self.found_incl[filename]
1733+
except KeyError:
1734+
pass
1735+
1736+
include_file = None
1737+
1738+
local_paths = []
1739+
if not is_system_include:
1740+
local_paths += [this_path]
1741+
1742+
# Determine the path to the include file, if it exists
1743+
for path in local_paths + self._include_paths:
1744+
test_path = os.path.abspath(os.path.join(path, filename))
1745+
if os.path.isfile(test_path):
1746+
include_file = test_path
1747+
self.found_incl[filename] = include_file
1748+
return include_file
1749+
1750+
# TODO: Check this optimization is always valid.
1751+
if include_file is not None:
1752+
raise RuntimeError(f"Expected 'None', got '{filename}'")
1753+
self.found_incl[filename] = None
1754+
return None
1755+
1756+
16491757
class ExpanderHelper:
16501758
"""
16511759
Class to act as token stream for expansion stack.
@@ -1715,8 +1823,7 @@ class MacroExpander:
17151823
A specialized token parser for recognizing and expanding macros.
17161824
"""
17171825

1718-
# FIXME: Cannot define Platform type without circular import.
1719-
def __init__(self, platform: Any) -> None:
1826+
def __init__(self, platform: Platform) -> None:
17201827
self.platform = platform
17211828
self.parser_stack: list[ExpanderHelper] = []
17221829
self.no_expand: list[str] = []

tests/macro_expansion/test_macro_expansion.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import unittest
66
from pathlib import Path
77

8-
from codebasin import CodeBase, finder, platform, preprocessor
8+
from codebasin import CodeBase, finder, preprocessor
9+
from codebasin.preprocessor import Platform
910

1011

1112
class TestMacroExpansion(unittest.TestCase):
@@ -62,7 +63,7 @@ def test_cat(self):
6263
test_str = "CATTEST=first ## 2"
6364
macro = preprocessor.macro_from_definition_string(test_str)
6465
tokens = preprocessor.Lexer("CATTEST").tokenize()
65-
p = platform.Platform("Test", self.rootdir)
66+
p = Platform("Test", self.rootdir)
6667
p._definitions = {macro.name: macro}
6768
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
6869
expected_tokens = preprocessor.Lexer("first2").tokenize()
@@ -75,7 +76,7 @@ def test_stringify_quote(self):
7576
test_str = "STR(x)= #x"
7677
macro = preprocessor.macro_from_definition_string(test_str)
7778
tokens = preprocessor.Lexer('STR(foo("4 + 5"))').tokenize()
78-
p = platform.Platform("Test", self.rootdir)
79+
p = Platform("Test", self.rootdir)
7980
p._definitions = {macro.name: macro}
8081
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
8182
expected_tokens = preprocessor.Lexer('"foo(\\"4 + 5\\")"').tokenize()
@@ -89,7 +90,7 @@ def test_stringify_ws(self):
8990
macro = preprocessor.macro_from_definition_string(test_str)
9091
to_expand_str = r'STR(L + 2-2 "\" \n")'
9192
tokens = preprocessor.Lexer(to_expand_str).tokenize()
92-
p = platform.Platform("Test", self.rootdir)
93+
p = Platform("Test", self.rootdir)
9394
p._definitions = {macro.name: macro}
9495
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
9596
expected_str = r'TEST "L + 2-2 \"\\\" \\n\""'
@@ -103,7 +104,7 @@ def test_stringify_nested(self):
103104
mac_xstr = preprocessor.macro_from_definition_string("xstr(s)=str(s)")
104105
mac_str = preprocessor.macro_from_definition_string("str(s)=#s")
105106
mac_def = preprocessor.macro_from_definition_string("foo=4")
106-
p = platform.Platform("Test", self.rootdir)
107+
p = Platform("Test", self.rootdir)
107108
p._definitions = {x.name: x for x in [mac_xstr, mac_str, mac_def]}
108109

109110
tokens = preprocessor.Lexer("str(foo)").tokenize()
@@ -148,7 +149,7 @@ def test_variadic(self):
148149
tokens = preprocessor.Lexer(
149150
'eprintf("%d, %f, %e", a, b, c)',
150151
).tokenize()
151-
p = platform.Platform("Test", self.rootdir)
152+
p = Platform("Test", self.rootdir)
152153
p._definitions = {macro.name: macro}
153154
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
154155
self.assertTrue(len(expanded_tokens) == len(expected_expansion))
@@ -172,7 +173,7 @@ def test_self_reference_macros_1(self):
172173
def_string = "FOO=(4 + FOO)"
173174
macro = preprocessor.macro_from_definition_string(def_string)
174175
tokens = preprocessor.Lexer("FOO").tokenize()
175-
p = platform.Platform("Test", self.rootdir)
176+
p = Platform("Test", self.rootdir)
176177
p._definitions = {macro.name: macro}
177178
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
178179
self.assertTrue(len(expanded_tokens) == len(expected_expansion))
@@ -201,7 +202,7 @@ def test_self_reference_macros_2(self):
201202
def_string = "FOO=FOO"
202203
macro = preprocessor.macro_from_definition_string(def_string)
203204
tokens = preprocessor.Lexer("FOO").tokenize()
204-
p = platform.Platform("Test", self.rootdir)
205+
p = Platform("Test", self.rootdir)
205206
p._definitions = {macro.name: macro}
206207
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
207208
self.assertTrue(len(expanded_tokens) == len(expected_expansion))
@@ -226,7 +227,7 @@ def test_self_reference_macros_3(self):
226227
def_string = "foo(x)=bar x"
227228
macro = preprocessor.macro_from_definition_string(def_string)
228229
tokens = preprocessor.Lexer("foo(foo) (2)").tokenize()
229-
p = platform.Platform("Test", self.rootdir)
230+
p = Platform("Test", self.rootdir)
230231
p._definitions = {macro.name: macro}
231232
expanded_tokens = preprocessor.MacroExpander(p).expand(tokens)
232233
expected_tokens = preprocessor.Lexer("bar foo (2)").tokenize()
@@ -270,7 +271,7 @@ def test_indirect_self_reference_macros(self):
270271
x_tokens = preprocessor.Lexer("x").tokenize()
271272
y_tokens = preprocessor.Lexer("y").tokenize()
272273

273-
p = platform.Platform("Test", self.rootdir)
274+
p = Platform("Test", self.rootdir)
274275
p._definitions = {x_macro.name: x_macro, y_macro.name: y_macro}
275276

276277
x_expanded_tokens = preprocessor.MacroExpander(p).expand(x_tokens)

tests/operators/test_operators.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import unittest
66
from pathlib import Path
77

8-
from codebasin import CodeBase, finder, platform, preprocessor
8+
from codebasin import CodeBase, finder, preprocessor
9+
from codebasin.preprocessor import Platform
910

1011

1112
class TestOperators(unittest.TestCase):
@@ -52,7 +53,7 @@ def test_operators(self):
5253
def test_paths(self):
5354
input_str = r"FUNCTION(looks/2like/a/path/with_/bad%%identifiers)"
5455
tokens = preprocessor.Lexer(input_str).tokenize()
55-
p = platform.Platform("Test", self.rootdir)
56+
p = Platform("Test", self.rootdir)
5657
macro = preprocessor.macro_from_definition_string("FUNCTION(x)=#x")
5758
p._definitions = {macro.name: macro}
5859
_ = preprocessor.MacroExpander(p).expand(tokens)

0 commit comments

Comments
 (0)