Skip to main content

microcad_lang/lower/ir/identifier/
qualified_name.rs

1// Copyright © 2024-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use derive_more::{Deref, DerefMut};
5
6use microcad_lang_base::{Identifier, Refer, SrcRef, SrcReferrer};
7use microcad_lang_proc_macros::SrcReferrer;
8use miette::SourceSpan;
9
10/// A *qualified name* consists of a list of *identifiers*, separated by `::`,
11/// e.g. `a::b::c`
12#[derive(
13    Default, Clone, Debug, PartialEq, Hash, Eq, Ord, PartialOrd, DerefMut, Deref, SrcReferrer,
14)]
15pub struct QualifiedName(Refer<Vec<Identifier>>);
16
17/// List of *qualified names* which can be displayed.
18#[derive(Debug, Deref)]
19pub struct QualifiedNames(Vec<QualifiedName>);
20
21impl std::fmt::Display for QualifiedNames {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(
24            f,
25            "{}",
26            self.0
27                .iter()
28                .map(|name| name.to_string())
29                .collect::<Vec<_>>()
30                .join(", ")
31        )
32    }
33}
34
35impl FromIterator<QualifiedName> for QualifiedNames {
36    fn from_iter<T: IntoIterator<Item = QualifiedName>>(iter: T) -> Self {
37        Self(iter.into_iter().collect())
38    }
39}
40
41impl QualifiedName {
42    /// Create [`QualifiedName`] from [`Identifier`]s.
43    ///
44    /// - `ids`: *Identifiers* that concatenate to the *qualified name*.
45    /// - `src_ref`: Reference for the whole name.
46    pub fn new(ids: Vec<Identifier>, src_ref: SrcRef) -> Self {
47        Self(Refer::new(ids, src_ref))
48    }
49
50    /// Returns true if self is a qualified name with multiple ids in it
51    pub fn is_qualified(&self) -> bool {
52        self.0.len() > 1
53    }
54
55    /// Tells if self is in a specified module
56    pub fn is_within(&self, module: &QualifiedName) -> bool {
57        self.starts_with(module)
58    }
59
60    /// remove the first name from path
61    pub fn remove_first(&self) -> Self {
62        Self(Refer::new(self.0[1..].to_vec(), self.0.src_ref.clone()))
63    }
64
65    /// remove the first name from path
66    pub fn remove_last(self) -> Self {
67        Self(Refer::new(
68            self.0[..self.0.len() - 1].to_vec(),
69            self.0.src_ref.clone(),
70        ))
71    }
72
73    /// Append identifier to name
74    pub fn push(&mut self, id: Identifier) {
75        self.0.push(id)
76    }
77
78    /// Split name into first id and the rest
79    pub fn split_first(&self) -> (Identifier, QualifiedName) {
80        match self.len() {
81            0 => todo!("return None or error?"),
82            1 => (self.0[0].clone(), Self::default()),
83            _ => (self.0[0].clone(), Self(Refer::none(self.0[1..].into()))),
84        }
85    }
86
87    /// Add given prefix to name
88    pub fn with_prefix(&self, prefix: &QualifiedName) -> Self {
89        let mut full_name = prefix.clone();
90        full_name.append(&mut self.clone());
91        full_name
92    }
93}
94
95impl crate::lower::SingleIdentifier for QualifiedName {
96    fn single_identifier(&self) -> Option<&Identifier> {
97        if self.is_single_identifier() {
98            self.0.first()
99        } else {
100            None
101        }
102    }
103
104    fn is_single_identifier(&self) -> bool {
105        self.0.len() == 1
106    }
107}
108
109impl From<QualifiedName> for SourceSpan {
110    fn from(value: QualifiedName) -> Self {
111        value.src_ref().into()
112    }
113}
114
115impl From<Identifier> for QualifiedName {
116    fn from(id: Identifier) -> Self {
117        let src_ref = id.src_ref();
118        Self(Refer::new(vec![id], src_ref))
119    }
120}
121
122impl std::fmt::Display for QualifiedName {
123    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
124        if self.is_empty() {
125            write!(f, "NO NAME")
126        } else {
127            write!(
128                f,
129                "{}",
130                self.iter()
131                    .map(|id| format!("{id}"))
132                    .collect::<Vec<_>>()
133                    .join("::")
134            )
135        }
136    }
137}
138
139impl From<Refer<Vec<Identifier>>> for QualifiedName {
140    fn from(value: Refer<Vec<Identifier>>) -> Self {
141        Self(value)
142    }
143}
144
145impl FromIterator<Identifier> for QualifiedName {
146    fn from_iter<T: IntoIterator<Item = Identifier>>(iter: T) -> Self {
147        Self(Refer::none(iter.into_iter().collect()))
148    }
149}
150
151impl From<&Identifier> for QualifiedName {
152    fn from(id: &Identifier) -> Self {
153        Self(Refer::none(vec![id.clone()]))
154    }
155}
156
157impl From<&str> for QualifiedName {
158    fn from(value: &str) -> Self {
159        Self(Refer::none(
160            value.split("::").map(Identifier::from).collect(),
161        ))
162    }
163}
164
165impl From<QualifiedName> for String {
166    fn from(value: QualifiedName) -> Self {
167        value
168            .iter()
169            .map(|id| format!("{id}"))
170            .collect::<Vec<_>>()
171            .join("::")
172    }
173}