Swift: move hierarchy IPA logic to schema.py

This commit is contained in:
Paolo Tranquilli
2022-11-16 11:14:17 +01:00
parent c70f3d35d0
commit 88a0c4053b
4 changed files with 68 additions and 70 deletions

View File

@@ -80,16 +80,10 @@ class Processor:
trap_name=trap_name,
)
@functools.lru_cache(maxsize=None)
def _is_ipa(self, name: str) -> bool:
cls = self._classmap[name]
return cls.ipa is not None or (
cls.derived and all(self._is_ipa(d) for d in cls.derived))
def get_classes(self):
ret = {'': []}
for k, cls in self._classmap.items():
if not self._is_ipa(k):
if not cls.ipa:
ret.setdefault(cls.group, []).append(self._get_class(cls.name))
return ret

View File

@@ -247,6 +247,32 @@ def _toposort_classes_by_group(classes: typing.Dict[str, Class]) -> typing.Dict[
return ret
def _fill_ipa_information(classes: typing.Dict[str, Class]):
if not classes:
return
is_ipa: typing.Dict[str, bool] = {}
def fill_is_ipa(name: str):
if name not in is_ipa:
cls = classes[name]
for d in cls.derived:
fill_is_ipa(d)
if cls.ipa is not None:
is_ipa[name] = True
elif not cls.derived:
is_ipa[name] = False
else:
is_ipa[name] = all(is_ipa[d] for d in cls.derived)
root = next(iter(classes))
fill_is_ipa(root)
for name, cls in classes.items():
if cls.ipa is None and is_ipa[name]:
cls.ipa = IpaInfo()
def load(m: types.ModuleType) -> Schema:
includes = set()
classes = {}
@@ -274,6 +300,8 @@ def load(m: types.ModuleType) -> Schema:
null = name
cls.is_null_class = True
_fill_ipa_information(classes)
return Schema(includes=includes, classes=_toposort_classes_by_group(classes), null=null)

View File

@@ -182,6 +182,10 @@ def test_cpp_skip_pragma(generate):
def test_ipa_classes_ignored(generate):
assert generate([
schema.Class(
name="W",
ipa=schema.IpaInfo(),
),
schema.Class(
name="X",
ipa=schema.IpaInfo(from_class="A"),
@@ -198,66 +202,5 @@ def test_ipa_classes_ignored(generate):
]
def test_ipa_hierarchy_ignored(generate):
assert generate([
schema.Class(
name="Root",
derived={"Base", "Z"},
),
schema.Class(
name="Base",
bases=["Root"],
derived={"X", "Y"}
),
schema.Class(
name="X",
bases=["Base"],
ipa=schema.IpaInfo(from_class="A"),
),
schema.Class(
name="Y",
bases=["Base"],
ipa=schema.IpaInfo(on_arguments={"a": "A", "b": "int"}),
),
schema.Class(
name="Z",
ipa=schema.IpaInfo(from_class="A"),
),
]) == []
def test_ipa_hierarchy_not_ignored_with_non_ipa_descendant(generate):
root = cpp.Class(name="Root")
base = cpp.Class(name="Base", bases=[root])
assert generate([
schema.Class(
name="Root",
derived={"Base", "Z"},
),
schema.Class(
name="Base",
bases=["Root"],
derived={"X", "Y"}
),
schema.Class(
name="X",
bases=["Base"],
),
schema.Class(
name="Y",
bases=["Base"],
ipa=schema.IpaInfo(on_arguments={"a": "A", "b": "int"}),
),
schema.Class(
name="Z",
ipa=schema.IpaInfo(from_class="A"),
),
]) == [
root,
base,
cpp.Class(name="X", bases=[base], final=True, trap_name="Xes"),
]
if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:]))

View File

@@ -340,7 +340,7 @@ def test_ipa_from_class():
pass
assert data.classes == {
'A': schema.Class('A', derived={'B'}),
'A': schema.Class('A', derived={'B'}, ipa=schema.IpaInfo()),
'B': schema.Class('B', bases=['A'], ipa=schema.IpaInfo(from_class="A")),
}
@@ -381,7 +381,7 @@ def test_ipa_class_on():
pass
assert data.classes == {
'A': schema.Class('A', derived={'B'}),
'A': schema.Class('A', derived={'B'}, ipa=schema.IpaInfo()),
'B': schema.Class('B', bases=['A'], ipa=schema.IpaInfo(on_arguments={'a': 'A', 'i': 'int'})),
}
@@ -414,6 +414,39 @@ def test_ipa_class_on_dangling():
pass
def test_ipa_class_hierarchy():
@schema.load
class data:
class Root:
pass
class Base(Root):
pass
class Intermediate(Base):
pass
@defs.synth.on_arguments(a=Base, i=defs.int)
class A(Intermediate):
pass
@defs.synth.from_class(Base)
class B(Base):
pass
class C(Root):
pass
assert data.classes == {
'Root': schema.Class('Root', derived={'Base', 'C'}),
'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, ipa=schema.IpaInfo()),
'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, ipa=schema.IpaInfo()),
'A': schema.Class('A', bases=['Intermediate'], ipa=schema.IpaInfo(on_arguments={'a': 'Base', 'i': 'int'})),
'B': schema.Class('B', bases=['Base'], ipa=schema.IpaInfo(from_class='Base')),
'C': schema.Class('C', bases=['Root']),
}
def test_class_docstring():
@schema.load
class data: