Skip to content

Commit faf1eee

Browse files
author
Paolo Tranquilli
committed
Rust: introduce typed labels
1 parent 0b850a2 commit faf1eee

File tree

18 files changed

+5175
-1219
lines changed

18 files changed

+5175
-1219
lines changed

misc/codegen/generators/rustgen.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def _get_type(t: str) -> str:
2020
case "int":
2121
return "usize"
2222
case _ if t[0].isupper():
23-
return "trap::Label"
23+
return f"{t}TrapLabel"
2424
case "boolean":
2525
assert False, "boolean unsupported"
2626
case _:
@@ -57,6 +57,15 @@ def _get_properties(
5757
yield cls, p
5858

5959

60+
def _get_ancestors(
61+
cls: schema.Class, lookup: dict[str, schema.Class]
62+
) -> typing.Iterable[schema.Class]:
63+
for b in cls.bases:
64+
base = lookup[b]
65+
yield base
66+
yield from _get_ancestors(base, lookup)
67+
68+
6069
class Processor:
6170
def __init__(self, data: schema.Schema):
6271
self._classmap = data.classes
@@ -69,14 +78,15 @@ def _get_class(self, name: str) -> rust.Class:
6978
_get_field(c, p)
7079
for c, p in _get_properties(cls, self._classmap)
7180
if "rust_skip" not in p.pragmas and not p.synth
72-
],
81+
] if not cls.derived else [],
82+
ancestors=sorted(set(a.name for a in _get_ancestors(cls, self._classmap))),
7383
table_name=inflection.tableize(cls.name),
7484
)
7585

7686
def get_classes(self):
7787
ret = {"": []}
7888
for k, cls in self._classmap.items():
79-
if not cls.synth and not cls.derived:
89+
if not cls.synth:
8090
ret.setdefault(cls.group, []).append(self._get_class(cls.name))
8191
return ret
8292

misc/codegen/lib/rust.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,9 @@ def is_label(self):
110110
@dataclasses.dataclass
111111
class Class:
112112
name: str
113-
table_name: str
113+
table_name: str | None = None
114114
fields: list[Field] = dataclasses.field(default_factory=list)
115+
ancestors: list[str] = dataclasses.field(default_factory=list)
115116

116117
@property
117118
def single_field_entries(self):

misc/codegen/templates/rust_classes.mustache

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,104 @@
22

33
#![cfg_attr(any(), rustfmt::skip)]
44

5-
use crate::trap::{TrapId, TrapEntry};
6-
use codeql_extractor::trap;
5+
use crate::trap;
76
{{#classes}}
87

8+
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
9+
pub struct {{name}}TrapLabel(trap::UntypedLabel);
10+
11+
impl From<trap::UntypedLabel> for {{name}}TrapLabel {
12+
fn from(value: trap::UntypedLabel) -> Self {
13+
Self(value)
14+
}
15+
}
16+
17+
impl From<{{name}}TrapLabel> for trap::TrapId<{{name}}> {
18+
fn from(value: {{name}}TrapLabel) -> Self {
19+
Self::Label(value)
20+
}
21+
}
22+
23+
impl trap::Label for {{name}}TrapLabel {
24+
fn as_untyped(&self) -> trap::UntypedLabel {
25+
self.0
26+
}
27+
}
28+
29+
impl From<{{name}}TrapLabel> for trap::Arg {
30+
fn from(value: {{name}}TrapLabel) -> Self {
31+
value.0.into()
32+
}
33+
}
34+
35+
{{#table_name}}
936
#[derive(Debug)]
1037
pub struct {{name}} {
11-
pub id: TrapId,
38+
pub id: trap::TrapId<{{name}}>,
1239
{{#fields}}
1340
pub {{field_name}}: {{type}},
1441
{{/fields}}
1542
}
1643

17-
impl TrapEntry for {{name}} {
18-
fn extract_id(&mut self) -> TrapId {
19-
std::mem::replace(&mut self.id, TrapId::Star)
44+
impl trap::TrapEntry for {{name}} {
45+
fn class_name() -> &'static str { "{{name}}" }
46+
47+
fn extract_id(&mut self) -> trap::TrapId<Self> {
48+
std::mem::replace(&mut self.id, trap::TrapId::Star)
2049
}
2150
22-
fn emit(self, id: trap::Label, out: &mut trap::Writer) {
51+
fn emit(self, id: Self::Label, out: &mut trap::Writer) {
2352
{{#single_field_entries}}
24-
out.add_tuple("{{table_name}}", vec![trap::Arg::Label(id){{#fields}}, self.{{field_name}}.into(){{/fields}}]);
53+
out.add_tuple("{{table_name}}", vec![id.into(){{#fields}}, self.{{field_name}}.into(){{/fields}}]);
2554
{{/single_field_entries}}
2655
{{#fields}}
2756
{{#is_predicate}}
2857
if self.{{field_name}} {
29-
out.add_tuple("{{table_name}}", vec![trap::Arg::Label(id)]);
58+
out.add_tuple("{{table_name}}", vec![id.into()]);
3059
}
3160
{{/is_predicate}}
3261
{{#is_optional}}
3362
{{^is_repeated}}
3463
if let Some(v) = self.{{field_name}} {
35-
out.add_tuple("{{table_name}}", vec![trap::Arg::Label(id), v.into()]);
64+
out.add_tuple("{{table_name}}", vec![id.into(), v.into()]);
3665
}
3766
{{/is_repeated}}
3867
{{/is_optional}}
3968
{{#is_repeated}}
4069
for (i, v) in self.{{field_name}}.into_iter().enumerate() {
4170
{{^is_optional}}
42-
out.add_tuple("{{table_name}}", vec![trap::Arg::Label(id){{^is_unordered}}, i.into(){{/is_unordered}}, v.into()]);
71+
out.add_tuple("{{table_name}}", vec![id.into(){{^is_unordered}}, i.into(){{/is_unordered}}, v.into()]);
4372
{{/is_optional}}
4473
{{#is_optional}}
4574
if let Some(v) = v {
46-
out.add_tuple("{{table_name}}", vec![trap::Arg::Label(id){{^is_unordered}}, i.into(){{/is_unordered}}, v.into()]);
75+
out.add_tuple("{{table_name}}", vec![id.into(){{^is_unordered}}, i.into(){{/is_unordered}}, v.into()]);
4776
}
4877
{{/is_optional}}
4978
}
5079
{{/is_repeated}}
5180
{{/fields}}
5281
}
5382
}
83+
{{/table_name}}
84+
{{^table_name}}
85+
{{! virtual class, make it unbuildable }}
86+
pub struct {{name}} {
87+
unused: ()
88+
}
89+
{{/table_name}}
90+
91+
impl trap::TrapClass for {{name}} {
92+
type Label = {{name}}TrapLabel;
93+
}
94+
{{/classes}}
95+
96+
// Conversions
97+
{{#classes}}
98+
{{#ancestors}}
99+
impl From<{{name}}TrapLabel> for {{.}}TrapLabel {
100+
fn from(value: {{name}}TrapLabel) -> Self {
101+
value.0.into()
102+
}
103+
}
104+
{{/ancestors}}
54105
{{/classes}}

rust/extractor/src/generated/.generated.list

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)