Skip to content

Commit a50f3f7

Browse files
committed
Swift: move toposort in schema.py
This makes the result of code generation independent of the order in which classes are defined in the schema, and makes additional topological sorting not required. Being independent from schema order will be important for reviewing the move to a pure python schema, as generated code will be left untouched.
1 parent b49487c commit a50f3f7

File tree

8 files changed

+4259
-4271
lines changed

8 files changed

+4259
-4271
lines changed

swift/codegen/generators/cppgen.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from typing import Dict
1717

1818
import inflection
19-
from toposort import toposort_flatten
2019

2120
from swift.codegen.lib import cpp, schema
2221

@@ -71,13 +70,9 @@ def _get_class(self, name: str) -> cpp.Class:
7170
)
7271

7372
def get_classes(self):
74-
grouped = {pathlib.Path(): {}}
73+
ret = {pathlib.Path(): []}
7574
for k, cls in self._classmap.items():
76-
grouped.setdefault(cls.dir, {}).update({k: cls})
77-
ret = {}
78-
for dir, map in grouped.items():
79-
inheritance_graph = {k: {b for b in cls.bases if b in map} for k, cls in map.items()}
80-
ret[dir] = [self._get_class(cls) for cls in toposort_flatten(inheritance_graph)]
75+
ret.setdefault(cls.dir, []).append(self._get_class(cls.name))
8176
return ret
8277

8378

swift/codegen/generators/qlgen.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import itertools
2929

3030
import inflection
31-
from toposort import toposort_flatten
3231

3332
from swift.codegen.lib import schema, ql
3433

@@ -263,9 +262,7 @@ def generate(opts, renderer):
263262

264263
imports = {}
265264

266-
inheritance_graph = {name: cls.bases for name, cls in data.classes.items()}
267-
toposorted_names = toposort_flatten(inheritance_graph)
268-
db_classes = [classes[name] for name in toposorted_names if not classes[name].ipa]
265+
db_classes = [cls for cls in classes.values() if not cls.ipa]
269266
renderer.render(ql.DbClasses(db_classes), out / "Raw.qll")
270267

271268
classes_by_dir_and_name = sorted(classes.values(), key=lambda cls: (cls.dir, cls.name))
@@ -286,8 +283,7 @@ def generate(opts, renderer):
286283
include_file = stub_out.with_suffix(".qll")
287284
renderer.render(ql.ImportList(list(imports.values())), include_file)
288285

289-
toposorted_classes = [classes[name] for name in toposorted_names]
290-
renderer.render(ql.GetParentImplementation(toposorted_classes), out / 'ParentChild.qll')
286+
renderer.render(ql.GetParentImplementation(list(classes.values())), out / 'ParentChild.qll')
291287

292288
for c in data.classes.values():
293289
if _should_skip_qltest(c, data.classes):

swift/codegen/lib/schema.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
from dataclasses import dataclass, field
66
from typing import List, Set, Union, Dict, ClassVar, Optional
7+
from toposort import toposort_flatten
78

89
import yaml
910

@@ -167,4 +168,17 @@ def load(path):
167168
cls.bases = [root_class_name]
168169
classes[root_class_name].derived.add(name)
169170

170-
return Schema(classes=classes, includes=set(data.get("_includes", [])))
171+
groups = {}
172+
173+
for name, cls in classes.items():
174+
groups.setdefault(cls.dir, []).append(name)
175+
176+
sorted_classes = {}
177+
178+
for dir in sorted(groups):
179+
group = groups[dir]
180+
inheritance = {name: classes[name].bases for name in group}
181+
for name in toposort_flatten(inheritance):
182+
sorted_classes[name] = classes[name]
183+
184+
return Schema(classes=sorted_classes, includes=set(data.get("_includes", [])))

swift/codegen/test/test_cppgen.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,6 @@ def test_two_class_hierarchy(generate):
5656
]
5757

5858

59-
def test_complex_hierarchy_topologically_ordered(generate):
60-
a = cpp.Class(name="A")
61-
b = cpp.Class(name="B")
62-
c = cpp.Class(name="C", bases=[a])
63-
d = cpp.Class(name="D", bases=[a])
64-
e = cpp.Class(name="E", bases=[b, c, d], final=True, trap_name="Es")
65-
f = cpp.Class(name="F", bases=[c], final=True, trap_name="Fs")
66-
assert generate([
67-
schema.Class(name="F", bases=["C"]),
68-
schema.Class(name="B", derived={"E"}),
69-
schema.Class(name="D", bases=["A"], derived={"E"}),
70-
schema.Class(name="C", bases=["A"], derived={"E", "F"}),
71-
schema.Class(name="E", bases=["B", "C", "D"]),
72-
schema.Class(name="A", derived={"C", "D"}),
73-
]) == [a, b, c, d, e, f]
74-
75-
7659
@pytest.mark.parametrize("type,expected", [
7760
("a", "a"),
7861
("string", "std::string"),
@@ -154,8 +137,8 @@ def test_classes_with_dirs(generate_grouped):
154137
assert generate_grouped([
155138
schema.Class(name="A"),
156139
schema.Class(name="B", dir=pathlib.Path("foo")),
157-
schema.Class(name="C", bases=["CBase"], dir=pathlib.Path("bar")),
158140
schema.Class(name="CBase", derived={"C"}, dir=pathlib.Path("bar")),
141+
schema.Class(name="C", bases=["CBase"], dir=pathlib.Path("bar")),
159142
schema.Class(name="D", dir=pathlib.Path("foo/bar/baz")),
160143
]) == {
161144
".": [cpp.Class(name="A", trap_name="As", final=True)],

swift/codegen/test/test_qlgen.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ def test_hierarchy_imports(generate_import_list):
177177

178178
def test_hierarchy_children(generate_children_implementations):
179179
assert generate_children_implementations([
180-
schema.Class("D", bases=["B", "C"]),
181-
schema.Class("C", bases=["A"], derived={"D"}),
182-
schema.Class("B", bases=["A"], derived={"D"}),
183180
schema.Class("A", derived={"B", "C"}),
181+
schema.Class("B", bases=["A"], derived={"D"}),
182+
schema.Class("C", bases=["A"], derived={"D"}),
183+
schema.Class("D", bases=["B", "C"]),
184184
]) == ql.GetParentImplementation(
185185
classes=[ql.Class(name="A"),
186186
ql.Class(name="B", bases=["A"], imports=[

0 commit comments

Comments
 (0)