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