zerodds_lang_rules/rule/python.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! The Python rule catalogue. Spec ยง2.
4//!
5//! The same constructs the Rust, C, C++ and Java catalogues cover,
6//! mapped onto Python's own tree. The rules are the same two shapes;
7//! what differs is the node each construct becomes, which is the
8//! difference a diff of two catalogues is supposed to show.
9//!
10//! Two rules are named for what Python actually does rather than for
11//! what the sibling catalogues do, because the target is not the same
12//! shape:
13//!
14//! - `enum-to-intenum` and `bitmask-to-intflag`. Java has no rule of
15//! that name because a Java `enum` constant's identity is its ordinal;
16//! Python's `enum.IntEnum` member *is* an `int`, so the enumerator
17//! names and the values live in one declaration.
18//! - `module-to-class`. Python's own unit of scope is the module, and
19//! one IDL file becomes one Python module, so a nested IDL module has
20//! to become something inside it. A class is the only construct Python
21//! has that nests and carries a name.
22
23use crate::rule::shape::{one_to_one, part_of};
24use seesaw_tgg::rules::format::RuleFile;
25
26/// The catalogue's own name, which a serialised rule file carries.
27const CATALOGUE_NAME: &str = "python";
28
29/// Every Python rule.
30#[must_use]
31pub fn catalogue() -> RuleFile {
32 RuleFile {
33 // The format version the engine expects; it reports a
34 // mismatch rather than reading an older file as if it were
35 // this one.
36 format: 3,
37 name: CATALOGUE_NAME.to_string(),
38 rules: vec![
39 one_to_one(
40 "struct-to-dataclass",
41 "Structure",
42 "PythonStruct",
43 "PythonStructCorr",
44 ),
45 part_of(
46 "member-to-field",
47 ("Member", "Structure", "PythonStructCorr"),
48 ("PythonField", "PythonStruct", "PythonFieldCorr"),
49 ),
50 one_to_one(
51 "enum-to-intenum",
52 "Enumeration",
53 "PythonEnum",
54 "PythonEnumCorr",
55 ),
56 part_of(
57 "enumerator-to-member",
58 ("Enumerator", "Enumeration", "PythonEnumCorr"),
59 ("PythonEnumerator", "PythonEnum", "PythonEnumeratorCorr"),
60 ),
61 one_to_one(
62 "alias-to-comment",
63 "Alias",
64 "PythonAlias",
65 "PythonAliasCorr",
66 ),
67 one_to_one(
68 "union-to-dataclass",
69 "Union",
70 "PythonUnion",
71 "PythonUnionCorr",
72 ),
73 part_of(
74 "case-to-field",
75 ("Case", "Union", "PythonUnionCorr"),
76 ("PythonCase", "PythonUnion", "PythonCaseCorr"),
77 ),
78 one_to_one(
79 "bitmask-to-intflag",
80 "Bitmask",
81 "PythonBitmask",
82 "PythonBitmaskCorr",
83 ),
84 part_of(
85 "bit-to-member",
86 ("BitValue", "Bitmask", "PythonBitmaskCorr"),
87 ("PythonBitConst", "PythonBitmask", "PythonBitCorr"),
88 ),
89 one_to_one(
90 "bitset-to-dataclass",
91 "Bitset",
92 "PythonBitset",
93 "PythonBitsetCorr",
94 ),
95 one_to_one(
96 "valuetype-to-dataclass",
97 "Valuetype",
98 "PythonValue",
99 "PythonValueCorr",
100 ),
101 one_to_one(
102 "module-to-class",
103 "Module",
104 "PythonModule",
105 "PythonModuleCorr",
106 ),
107 one_to_one("const-to-final", "Const", "PythonConst", "PythonConstCorr"),
108 one_to_one(
109 "exception-to-dataclass",
110 "Exception",
111 "PythonError",
112 "PythonErrorCorr",
113 ),
114 one_to_one(
115 "interface-to-protocol",
116 "Interface",
117 "PythonInterface",
118 "PythonInterfaceCorr",
119 ),
120 one_to_one(
121 "native-to-comment",
122 "Native",
123 "PythonNative",
124 "PythonNativeCorr",
125 ),
126 ],
127 }
128}