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