Skip to content

Commit 15aa0bb

Browse files
authored
Merge pull request #19866 from github/redsun82/codegen-new-parent-child
Codegen: improve implementation of generated parent/child relationship
2 parents 97412f4 + 9cf037f commit 15aa0bb

File tree

18 files changed

+1883
-5013
lines changed

18 files changed

+1883
-5013
lines changed

misc/codegen/generators/qlgen.py

Lines changed: 191 additions & 173 deletions
Large diffs are not rendered by default.

misc/codegen/generators/rusttestgen.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,12 @@ def generate(opts, renderer):
5959
registry=opts.ql_test_output / ".generated_tests.list",
6060
force=opts.force,
6161
) as renderer:
62+
63+
resolver = qlgen.Resolver(schema.classes)
6264
for cls in schema.classes.values():
6365
if cls.imported:
6466
continue
65-
if (
66-
qlgen.should_skip_qltest(cls, schema.classes)
67-
or "rust_skip_doc_test" in cls.pragmas
68-
):
67+
if resolver.should_skip_qltest(cls) or "rust_skip_doc_test" in cls.pragmas:
6968
continue
7069
code = _get_code(cls.doc)
7170
for p in schema.iter_properties(cls.name):

misc/codegen/lib/ql.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class Property:
3737
is_optional: bool = False
3838
is_predicate: bool = False
3939
is_unordered: bool = False
40-
prev_child: Optional[str] = None
4140
qltest_skip: bool = False
4241
description: List[str] = field(default_factory=list)
4342
doc: Optional[str] = None
@@ -48,6 +47,7 @@ class Property:
4847
type_is_self: bool = False
4948
internal: bool = False
5049
cfg: bool = False
50+
is_child: bool = False
5151

5252
def __post_init__(self):
5353
if self.tableparams:
@@ -76,10 +76,6 @@ def is_repeated(self):
7676
def is_single(self):
7777
return not (self.is_optional or self.is_repeated or self.is_predicate)
7878

79-
@property
80-
def is_child(self):
81-
return self.prev_child is not None
82-
8379
@property
8480
def is_indexed(self) -> bool:
8581
return self.is_repeated and not self.is_unordered
@@ -89,6 +85,12 @@ def type_alias(self) -> Optional[str]:
8985
return self.type + "Alias" if self.type_is_self else self.type
9086

9187

88+
@dataclass
89+
class Child:
90+
property: Property
91+
prev: str = ""
92+
93+
9294
@dataclass
9395
class Base:
9496
base: str
@@ -107,6 +109,7 @@ class Class:
107109
bases_impl: List[Base] = field(default_factory=list)
108110
final: bool = False
109111
properties: List[Property] = field(default_factory=list)
112+
all_children: List[Child] = field(default_factory=list)
110113
dir: pathlib.Path = pathlib.Path()
111114
imports: List[str] = field(default_factory=list)
112115
import_prefix: Optional[str] = None
@@ -148,7 +151,7 @@ def db_id(self) -> str:
148151

149152
@property
150153
def has_children(self) -> bool:
151-
return any(p.is_child for p in self.properties)
154+
return bool(self.all_children)
152155

153156
@property
154157
def last_base(self) -> str:

misc/codegen/templates/ql_parent.mustache

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,51 +9,39 @@ import {{.}}
99

1010
private module Impl {
1111
{{#classes}}
12-
private Element getImmediateChildOf{{name}}({{name}} e, int index, string partialPredicateCall) {
13-
{{! avoid unused argument warnings on root element, assuming the root element has no children }}
14-
{{#root}}none(){{/root}}
15-
{{^root}}
16-
{{! b is the base offset 0, for ease of generation }}
17-
{{! b<base> is constructed to be strictly greater than the indexes required for children coming from <base> }}
18-
{{! n is the base offset for direct children, equal to the last base offset from above }}
19-
{{! n<child> is constructed to be strictly greater than the indexes for <child> children }}
20-
exists(int b{{#bases}}, int b{{.}}{{/bases}}, int n{{#properties}}{{#is_child}}, int n{{singular}}{{/is_child}}{{/properties}} |
21-
b = 0
22-
{{#bases}}
23-
and
24-
b{{.}} = b{{prev}} + 1 + max(int i | i = -1 or exists(getImmediateChildOf{{.}}(e, i, _)) | i)
25-
{{/bases}}
26-
and
27-
n = b{{last_base}}
28-
{{#properties}}
29-
{{#is_child}}
30-
{{! n<child> is defined on top of the previous definition }}
31-
{{! for single and optional properties it adds 1 (regardless of whether the optional property exists) }}
32-
{{! for repeated it adds 1 + the maximum index (which works for repeated optional as well) }}
33-
and
34-
n{{singular}} = n{{prev_child}} + 1{{#is_repeated}}+ max(int i | i = -1 or exists(e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}(i)) | i){{/is_repeated}}
35-
{{/is_child}}
36-
{{/properties}} and (
37-
none()
38-
{{#bases}}
39-
or
40-
result = getImmediateChildOf{{.}}(e, index - b{{prev}}, partialPredicateCall)
41-
{{/bases}}
42-
{{#properties}}
43-
{{#is_child}}
44-
or
45-
{{#is_repeated}}
46-
result = e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}(index - n{{prev_child}}) and partialPredicateCall = "{{singular}}(" + (index - n{{prev_child}}).toString() + ")"
47-
{{/is_repeated}}
48-
{{^is_repeated}}
49-
index = n{{prev_child}} and result = e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}() and partialPredicateCall = "{{singular}}()"
50-
{{/is_repeated}}
51-
{{/is_child}}
52-
{{/properties}}
53-
))
54-
{{/root}}
55-
}
56-
12+
{{#final}}
13+
private Element getImmediateChildOf{{name}}({{name}} e, int index, string partialPredicateCall) {
14+
{{^has_children}}none(){{/has_children}}
15+
{{#has_children}}
16+
{{! n is the base offset 0, for ease of generation }}
17+
{{! n<child> is constructed to be strictly greater than the indexes for <child> children }}
18+
exists(int n{{#all_children}}, int n{{property.singular}}{{/all_children}} |
19+
n = 0
20+
{{#all_children}}
21+
{{#property}}
22+
{{! n<child> is defined on top of the previous definition }}
23+
{{! for single and optional properties it adds 1 (regardless of whether the optional property exists) }}
24+
{{! for repeated it adds 1 + the maximum index (which works for repeated optional as well) }}
25+
and
26+
n{{singular}} = n{{prev}} + 1{{#is_repeated}}+ max(int i | i = -1 or exists(e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}(i)) | i){{/is_repeated}}
27+
{{/property}}
28+
{{/all_children}} and (
29+
none()
30+
{{#all_children}}
31+
{{#property}}
32+
or
33+
{{#is_repeated}}
34+
result = e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}(index - n{{prev}}) and partialPredicateCall = "{{singular}}(" + (index - n{{prev}}).toString() + ")"
35+
{{/is_repeated}}
36+
{{^is_repeated}}
37+
index = n{{prev}} and result = e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}() and partialPredicateCall = "{{singular}}()"
38+
{{/is_repeated}}
39+
{{/property}}
40+
{{/all_children}}
41+
))
42+
{{/has_children}}
43+
}
44+
{{/final}}
5745
{{/classes}}
5846
cached
5947
Element getImmediateChild(Element e, int index, string partialAccessor) {

misc/codegen/test/test_ql.py

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -133,34 +133,18 @@ def test_non_root_class():
133133
assert not cls.root
134134

135135

136-
@pytest.mark.parametrize(
137-
"prev_child,is_child", [(None, False), ("", True), ("x", True)]
138-
)
139-
def test_is_child(prev_child, is_child):
140-
p = ql.Property("Foo", "int", prev_child=prev_child)
141-
assert p.is_child is is_child
142-
143-
144-
def test_empty_class_no_children():
145-
cls = ql.Class("Class", properties=[])
146-
assert cls.has_children is False
147-
148-
149136
def test_class_no_children():
150137
cls = ql.Class(
151-
"Class", properties=[ql.Property("Foo", "int"), ql.Property("Bar", "string")]
138+
"Class",
139+
all_children=[],
152140
)
153141
assert cls.has_children is False
154142

155143

156144
def test_class_with_children():
157145
cls = ql.Class(
158146
"Class",
159-
properties=[
160-
ql.Property("Foo", "int"),
161-
ql.Property("Child", "x", prev_child=""),
162-
ql.Property("Bar", "string"),
163-
],
147+
all_children=[ql.Child(ql.Property("Foo", "int"))],
164148
)
165149
assert cls.has_children is True
166150

0 commit comments

Comments
 (0)