Skip to main content

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}