microcad_lang/syntax/identifier/
qualified_name.rs1use crate::{src_ref::*, syntax::*};
5use derive_more::{Deref, DerefMut};
6use miette::SourceSpan;
7
8#[derive(Default, Clone, PartialEq, Hash, Eq, Ord, PartialOrd, DerefMut, Deref)]
11pub struct QualifiedName(Refer<Vec<Identifier>>);
12
13impl QualifiedName {
14 pub fn as_identifier(&self) -> Option<&Identifier> {
16 self.0.first().filter(|_| self.0.len() == 1)
17 }
18}
19
20#[derive(Deref)]
22pub struct QualifiedNames(Vec<QualifiedName>);
23
24impl std::fmt::Display for QualifiedNames {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(
27 f,
28 "{}",
29 self.0
30 .iter()
31 .map(|name| name.to_string())
32 .collect::<Vec<_>>()
33 .join(", ")
34 )
35 }
36}
37
38impl std::fmt::Debug for QualifiedNames {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(
41 f,
42 "{}",
43 self.0
44 .iter()
45 .map(|name| format!("{:?}", name.to_string()))
46 .collect::<Vec<_>>()
47 .join(", ")
48 )
49 }
50}
51
52pub(crate) type QualifiedNameSet = indexmap::IndexSet<QualifiedName>;
53
54impl FromIterator<QualifiedName> for QualifiedNames {
55 fn from_iter<T: IntoIterator<Item = QualifiedName>>(iter: T) -> Self {
56 Self(iter.into_iter().collect())
57 }
58}
59
60impl QualifiedName {
61 pub fn new(ids: Vec<Identifier>, src_ref: SrcRef) -> Self {
66 Self(Refer::new(ids, src_ref))
67 }
68
69 pub fn from_id(id: Identifier) -> Self {
71 let src_ref = id.src_ref();
72 Self(Refer::new(vec![id], src_ref))
73 }
74
75 pub fn no_ref(ids: Vec<Identifier>) -> Self {
79 Self(Refer::none(ids))
80 }
81
82 pub fn is_qualified(&self) -> bool {
84 self.0.len() > 1
85 }
86
87 pub fn is_id(&self) -> bool {
89 self.0.len() == 1
90 }
91
92 pub fn is_within(&self, module: &QualifiedName) -> bool {
94 self.starts_with(module)
95 }
96
97 pub fn is_builtin(&self) -> bool {
99 if let Some(first) = self.first() {
100 first == "__builtin"
101 } else {
102 false
103 }
104 }
105
106 pub fn remove_first(&self) -> Self {
108 Self(Refer::new(self.0[1..].to_vec(), self.0.src_ref.clone()))
109 }
110
111 pub fn remove_last(self) -> Self {
113 Self(Refer::new(
114 self.0[..self.0.len() - 1].to_vec(),
115 self.0.src_ref.clone(),
116 ))
117 }
118
119 pub fn push(&mut self, id: Identifier) {
121 self.0.push(id)
122 }
123
124 pub fn split_first(&self) -> (Identifier, QualifiedName) {
126 match self.len() {
127 0 => todo!("return None or error?"),
128 1 => (self.0[0].clone(), Self::default()),
129 _ => (self.0[0].clone(), Self(Refer::none(self.0[1..].into()))),
130 }
131 }
132
133 pub fn basename(&self) -> Option<Self> {
135 let mut s = self.clone();
136 if s.len() >= 2 {
137 s.pop();
138 Some(s)
139 } else {
140 None
141 }
142 }
143
144 pub fn base(&self, relative: &Self) -> Self {
146 if self == relative {
147 QualifiedName::default()
148 } else {
149 assert!(!relative.is_empty());
150 assert!(self.len() > relative.len());
151 assert!(self.ends_with(relative));
152 let (base, _) = self.split_at(self.len() - relative.len());
153 base.iter().cloned().collect()
154 }
155 }
156
157 pub fn with_prefix(&self, prefix: &QualifiedName) -> Self {
159 let mut full_name = prefix.clone();
160 full_name.append(&mut self.clone());
161 full_name
162 }
163
164 pub fn with_suffix(&self, suffix: &Identifier) -> Self {
166 let mut name = self.clone();
167 name.push(suffix.clone());
168 name
169 }
170
171 pub(crate) fn count_super(&self) -> usize {
172 self.iter().take_while(|id| id.is_super()).count()
173 }
174
175 pub(crate) fn un_super(&self) -> Self {
176 self.iter().filter(|id| !id.is_super()).cloned().collect()
177 }
178}
179
180impl SingleIdentifier for QualifiedName {
181 fn single_identifier(&self) -> Option<&Identifier> {
182 if self.is_single_identifier() {
183 self.0.first()
184 } else {
185 None
186 }
187 }
188
189 fn is_single_identifier(&self) -> bool {
190 self.0.len() == 1
191 }
192}
193
194impl From<QualifiedName> for SourceSpan {
195 fn from(value: QualifiedName) -> Self {
196 value.src_ref().into()
197 }
198}
199
200#[test]
201fn test_base() {
202 let d: QualifiedName = "a::b::c::d".into();
203 assert_eq!(d.base(&"b::c::d".into()), "a".into());
204 assert_eq!(d.base(&"c::d".into()), "a::b".into());
205 assert_eq!(d.base(&"d".into()), "a::b::c".into());
206}
207
208#[test]
209#[should_panic]
210fn test_base_panic() {
211 let d: QualifiedName = "a::b::c::d".into();
212 assert_eq!(d.base(&"a::b::c::d".into()), "".into());
213}
214
215#[test]
216fn dissolve_super() {
217 let what: QualifiedName = "super::super::c::x".into();
218 assert_eq!(what.count_super(), 2);
219}
220
221impl std::fmt::Display for QualifiedName {
222 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
223 if self.is_empty() {
224 write!(f, crate::invalid_no_ansi!(NAME))
225 } else {
226 write!(
227 f,
228 "{}",
229 self.iter()
230 .map(|id| format!("{id}"))
231 .collect::<Vec<_>>()
232 .join("::")
233 )
234 }
235 }
236}
237
238impl std::fmt::Debug for QualifiedName {
239 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
240 if self.is_empty() {
241 write!(f, crate::invalid!(NAME))
242 } else {
243 write!(
244 f,
245 "{}",
246 self.iter()
247 .map(|id| format!("{id:?}"))
248 .collect::<Vec<_>>()
249 .join("::")
250 )
251 }
252 }
253}
254
255impl SrcReferrer for QualifiedName {
256 fn src_ref(&self) -> SrcRef {
257 self.0.src_ref()
258 }
259}
260
261impl From<Refer<Vec<Identifier>>> for QualifiedName {
262 fn from(value: Refer<Vec<Identifier>>) -> Self {
263 Self(value)
264 }
265}
266
267impl FromIterator<Identifier> for QualifiedName {
268 fn from_iter<T: IntoIterator<Item = Identifier>>(iter: T) -> Self {
269 Self(Refer::none(iter.into_iter().collect()))
270 }
271}
272
273impl From<&Identifier> for QualifiedName {
274 fn from(id: &Identifier) -> Self {
275 Self(Refer::none(vec![id.clone()]))
276 }
277}
278
279impl From<&std::path::Path> for QualifiedName {
280 fn from(path: &std::path::Path) -> Self {
281 let path = if path.file_stem() == Some(std::ffi::OsStr::new("mod")) {
283 path.parent().expect("mod file in root path is not allowed")
284 } else {
285 path
286 };
287
288 QualifiedName::no_ref(
289 path.iter()
290 .map(|id| {
291 Identifier(Refer {
292 value: id.to_string_lossy().into_owned().into(),
293 src_ref: SrcRef(None),
294 })
295 })
296 .collect(),
297 )
298 }
299}
300
301#[cfg(test)]
302impl From<&str> for QualifiedName {
303 fn from(value: &str) -> Self {
304 Self(Refer::none(
305 value.split("::").map(Identifier::from).collect(),
306 ))
307 }
308}
309
310#[cfg(not(test))]
311impl TryFrom<&str> for QualifiedName {
312 type Error = ();
313
314 fn try_from(value: &str) -> Result<Self, Self::Error> {
315 let mut name = Vec::new();
316 for id in value.split("::").map(Identifier::try_from) {
317 if id.is_err() {
318 return Err(());
319 }
320 name.push(id.expect("unexpected error"));
321 }
322
323 Ok(Self(Refer::none(name)))
324 }
325}
326
327impl From<Identifier> for QualifiedName {
328 fn from(id: Identifier) -> Self {
329 let src_ref = id.src_ref();
330 QualifiedName(Refer::new(vec![id], src_ref))
331 }
332}
333
334impl From<QualifiedName> for String {
335 fn from(value: QualifiedName) -> Self {
336 value
337 .iter()
338 .map(|id| format!("{id}"))
339 .collect::<Vec<_>>()
340 .join("::")
341 }
342}
343
344impl TreeDisplay for QualifiedName {
345 fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
346 writeln!(
347 f,
348 "{:depth$}QualifiedName: '{}'",
349 "",
350 self.iter()
351 .map(|id| format!("{id:?}"))
352 .collect::<Vec<_>>()
353 .join("::")
354 )
355 }
356}