zerodds_ast/node/member.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Members and aggregate parts. Spec §3.3.
4
5use crate::facet::Facets;
6use crate::node::AnyId;
7use crate::node::constant::ConstExprNode;
8use crate::node::type_::TypeNode;
9use alloc::string::String;
10use alloc::vec::Vec;
11use zerodds_ast_core::{Id, NodeId, Ref};
12
13/// A field of an aggregate.
14///
15/// Covers struct members, valuetype state members, union case members
16/// and exception members. Spec §3.3.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct MemberNode {
19 /// Stable identity.
20 pub node_id: NodeId,
21 /// Simple name.
22 pub name: String,
23 /// Declared type.
24 pub type_: Ref<TypeNode>,
25 /// The aggregate this member belongs to.
26 pub parent: AnyId,
27 /// Per-source information, including the XTypes member id. Spec §4.
28 pub facets: Facets,
29}
30
31/// A union case label.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum CaseLabel {
34 /// `case <expr>:`
35 Value(Id<ConstExprNode>),
36 /// `default:`
37 Default,
38}
39
40impl CaseLabel {
41 /// Whether this is the `default:` label.
42 #[must_use]
43 pub const fn is_default(self) -> bool {
44 matches!(self, Self::Default)
45 }
46
47 /// The label expression, if this is not `default:`.
48 #[must_use]
49 pub const fn expr(self) -> Option<Id<ConstExprNode>> {
50 match self {
51 Self::Value(id) => Some(id),
52 Self::Default => None,
53 }
54 }
55}
56
57/// One `case` of a union, with its labels. Spec §3.3.
58///
59/// A case may carry several labels — `case 1: case 2: long x;` — so the
60/// labels are a list, not a single value.
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct CaseNode {
63 /// Stable identity.
64 pub node_id: NodeId,
65 /// Labels selecting this case, in declaration order.
66 pub labels: Vec<CaseLabel>,
67 /// The member this case declares.
68 pub member: Id<MemberNode>,
69 /// The union this case belongs to.
70 pub parent: Id<TypeNode>,
71 /// Per-source information. Spec §4.
72 pub facets: Facets,
73}
74
75/// One enumerator. Spec §3.3.
76///
77/// `value` is `None` for a positional enumerator and `Some` for an
78/// explicit `@value(n)`. The two encode differently, so collapsing the
79/// distinction is a wire bug — one that the emitters this rebuild
80/// replaces actually shipped.
81#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct EnumeratorNode {
83 /// Stable identity.
84 pub node_id: NodeId,
85 /// Simple name.
86 pub name: String,
87 /// Explicit `@value(n)`, if declared.
88 pub value: Option<Id<ConstExprNode>>,
89 /// The enumeration this enumerator belongs to.
90 pub parent: Id<TypeNode>,
91 /// Per-source information. Spec §4.
92 pub facets: Facets,
93}
94
95/// One bitmask bit. Spec §3.3.
96///
97/// `position` is `None` for a positional bit and `Some` for an explicit
98/// `@position(k)`, for the same reason as [`EnumeratorNode::value`].
99#[derive(Debug, Clone, PartialEq, Eq)]
100pub struct BitValueNode {
101 /// Stable identity.
102 pub node_id: NodeId,
103 /// Simple name.
104 pub name: String,
105 /// Explicit `@position(k)`, if declared.
106 pub position: Option<u16>,
107 /// The bitmask this bit belongs to.
108 pub parent: Id<TypeNode>,
109 /// Per-source information. Spec §4.
110 pub facets: Facets,
111}
112
113/// One bitset field. Spec §3.3.
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct BitfieldNode {
116 /// Stable identity.
117 pub node_id: NodeId,
118 /// Simple name. Anonymous padding fields have none.
119 pub name: Option<String>,
120 /// Width in bits.
121 pub bits: u16,
122 /// Explicit holder type, if declared.
123 pub holder_type: Option<Ref<TypeNode>>,
124 /// The bitset this field belongs to.
125 pub parent: Id<TypeNode>,
126 /// Per-source information. Spec §4.
127 pub facets: Facets,
128}
129
130impl BitfieldNode {
131 /// Whether this is an anonymous padding field.
132 #[must_use]
133 pub const fn is_padding(&self) -> bool {
134 self.name.is_none()
135 }
136}