Skip to main content

mago_syntax/ast/ast/
use.rs

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}