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