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