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