1use serde::Deserialize;
2use serde::Serialize;
3use strum::Display;
4
5use mago_span::HasSpan;
6use mago_span::Position;
7use mago_span::Span;
8
9use crate::ast::ast::identifier::Identifier;
10use crate::ast::ast::identifier::LocalIdentifier;
11use crate::ast::ast::keyword::Keyword;
12use crate::ast::ast::terminator::Terminator;
13use crate::ast::sequence::TokenSeparatedSequence;
14
15#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
16#[repr(C)]
17pub struct Use {
18 pub r#use: Keyword,
19 pub items: UseItems,
20 pub terminator: Terminator,
21}
22
23#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
24#[serde(tag = "type", content = "value")]
25#[repr(C, u8)]
26pub enum UseItems {
27 Sequence(UseItemSequence),
28 TypedSequence(TypedUseItemSequence),
29 TypedList(TypedUseItemList),
30 MixedList(MixedUseItemList),
31}
32
33#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
34#[serde(tag = "type", content = "value")]
35#[repr(C, u8)]
36pub enum UseType {
37 Function(Keyword),
38 Const(Keyword),
39}
40
41#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
42#[repr(C)]
43pub struct UseItemSequence {
44 pub start: Position,
45 pub items: TokenSeparatedSequence<UseItem>,
46}
47
48#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
49#[repr(C)]
50pub struct TypedUseItemSequence {
51 pub r#type: UseType,
52 pub items: TokenSeparatedSequence<UseItem>,
53}
54
55#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
56#[repr(C)]
57pub struct TypedUseItemList {
58 pub r#type: UseType,
59 pub namespace: Identifier,
60 pub namespace_separator: Span,
61 pub left_brace: Span,
62 pub items: TokenSeparatedSequence<UseItem>,
63 pub right_brace: Span,
64}
65
66#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
67#[repr(C)]
68pub struct MixedUseItemList {
69 pub namespace: Identifier,
70 pub namespace_separator: Span,
71 pub left_brace: Span,
72 pub items: TokenSeparatedSequence<MaybeTypedUseItem>,
73 pub right_brace: Span,
74}
75
76#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
77#[repr(C)]
78pub struct MaybeTypedUseItem {
79 pub r#type: Option<UseType>,
80 pub item: UseItem,
81}
82
83#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
84#[repr(C)]
85pub struct UseItem {
86 pub name: Identifier,
87 pub alias: Option<UseItemAlias>,
88}
89
90#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
91#[repr(C)]
92pub struct UseItemAlias {
93 pub r#as: Keyword,
94 pub identifier: LocalIdentifier,
95}
96
97impl UseType {
98 #[inline]
99 pub const fn is_function(&self) -> bool {
100 matches!(self, UseType::Function(_))
101 }
102
103 #[inline]
104 pub const fn is_const(&self) -> bool {
105 matches!(self, UseType::Const(_))
106 }
107}
108
109impl HasSpan for Use {
110 fn span(&self) -> Span {
111 self.r#use.span().join(self.terminator.span())
112 }
113}
114
115impl HasSpan for UseItems {
116 fn span(&self) -> Span {
117 match self {
118 UseItems::Sequence(items) => items.span(),
119 UseItems::TypedSequence(items) => items.span(),
120 UseItems::TypedList(items) => items.span(),
121 UseItems::MixedList(items) => items.span(),
122 }
123 }
124}
125
126impl HasSpan for UseType {
127 fn span(&self) -> Span {
128 match self {
129 UseType::Function(keyword) => keyword.span(),
130 UseType::Const(keyword) => keyword.span(),
131 }
132 }
133}
134
135impl HasSpan for UseItemSequence {
136 fn span(&self) -> Span {
137 self.items.span(self.start)
138 }
139}
140
141impl HasSpan for TypedUseItemSequence {
142 fn span(&self) -> Span {
143 self.r#type.span().join(self.items.span(self.r#type.span().end))
144 }
145}
146
147impl HasSpan for TypedUseItemList {
148 fn span(&self) -> Span {
149 self.r#type.span().join(self.right_brace)
150 }
151}
152
153impl HasSpan for MixedUseItemList {
154 fn span(&self) -> Span {
155 self.namespace.span().join(self.right_brace)
156 }
157}
158
159impl HasSpan for MaybeTypedUseItem {
160 fn span(&self) -> Span {
161 if let Some(r#type) = &self.r#type { r#type.span().join(self.item.span()) } else { self.item.span() }
162 }
163}
164
165impl HasSpan for UseItem {
166 fn span(&self) -> Span {
167 if let Some(alias) = &self.alias { self.name.span().join(alias.span()) } else { self.name.span() }
168 }
169}
170
171impl HasSpan for UseItemAlias {
172 fn span(&self) -> Span {
173 self.r#as.span().join(self.identifier.span())
174 }
175}