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(Debug, 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 FromIterator<QualifiedName> for QualifiedNames {
31 fn from_iter<T: IntoIterator<Item = QualifiedName>>(iter: T) -> Self {
32 Self(iter.into_iter().collect())
33 }
34}
35
36impl QualifiedName {
37 pub fn new(ids: Vec<Identifier>, src_ref: SrcRef) -> Self {
42 Self(Refer::new(ids, src_ref))
43 }
44
45 pub fn from_id(id: Identifier) -> Self {
47 let src_ref = id.src_ref();
48 Self(Refer::new(vec![id], src_ref))
49 }
50
51 pub fn no_ref(ids: Vec<Identifier>) -> Self {
55 Self(Refer::none(ids))
56 }
57
58 pub fn single_identifier(&self) -> Option<&Identifier> {
60 if self.0.len() == 1 {
61 self.0.first()
62 } else {
63 None
64 }
65 }
66
67 pub fn is_qualified(&self) -> bool {
69 self.0.len() > 1
70 }
71
72 pub fn is_id(&self) -> bool {
74 self.0.len() == 1
75 }
76
77 pub fn is_within(&self, module: &QualifiedName) -> bool {
79 self.starts_with(module)
80 }
81
82 pub fn is_builtin(&self) -> bool {
84 if let Some(first) = self.first() {
85 first == "__builtin"
86 } else {
87 false
88 }
89 }
90
91 pub fn remove_first(&self) -> Self {
93 Self(Refer::new(self.0[1..].to_vec(), self.0.src_ref.clone()))
94 }
95
96 pub fn remove_last(self) -> Self {
98 Self(Refer::new(
99 self.0[..self.0.len() - 1].to_vec(),
100 self.0.src_ref.clone(),
101 ))
102 }
103
104 pub fn push(&mut self, id: Identifier) {
106 self.0.push(id)
107 }
108
109 pub fn split_first(&self) -> (Identifier, QualifiedName) {
111 match self.len() {
112 0 => todo!("return None or error?"),
113 1 => (self.0[0].clone(), Self::default()),
114 _ => (self.0[0].clone(), Self(Refer::none(self.0[1..].into()))),
115 }
116 }
117
118 pub fn basename(&self) -> Option<Self> {
120 let mut s = self.clone();
121 if s.len() >= 2 {
122 s.pop();
123 Some(s)
124 } else {
125 None
126 }
127 }
128
129 pub fn with_prefix(&self, prefix: &QualifiedName) -> Self {
131 let mut full_name = prefix.clone();
132 full_name.append(&mut self.clone());
133 full_name
134 }
135
136 pub fn with_suffix(&self, suffix: Identifier) -> Self {
138 let mut name = self.clone();
139 name.push(suffix.clone());
140 name
141 }
142
143 pub fn dissolve_super(&self, mut within: QualifiedName) -> (Self, Self) {
145 let what: QualifiedName = self
147 .iter()
148 .filter(|id| {
149 if id.is_super() {
150 within.pop();
151 false
152 } else {
153 true
154 }
155 })
156 .cloned()
157 .collect();
158
159 if what.iter().any(Identifier::is_super) {
161 todo!("error: super allowed only at begin of qualified name");
162 }
163 (what, within)
164 }
165}
166
167#[test]
168fn dissolve_super() {
169 let what: QualifiedName = "super::super::c::x".into();
170 let within: QualifiedName = "a::b::c::d".into();
171
172 let (what, within) = what.dissolve_super(within);
173 assert_eq!(what, "c::x".into());
174 assert_eq!(within, "a::b".into());
175}
176
177impl std::fmt::Display for QualifiedName {
178 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
179 if self.is_empty() {
180 write!(f, crate::invalid_no_ansi!(NAME))
181 } else {
182 write!(f, "{}", join_identifiers(&self.0, "::"))
183 }
184 }
185}
186
187impl std::fmt::Debug for QualifiedName {
188 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
189 if self.is_empty() {
190 write!(f, crate::invalid!(NAME))
191 } else {
192 write!(f, "{}", join_identifiers_debug(&self.0, "::"))
193 }
194 }
195}
196
197impl SrcReferrer for QualifiedName {
198 fn src_ref(&self) -> SrcRef {
199 self.0.src_ref()
200 }
201}
202
203impl From<Refer<Vec<Identifier>>> for QualifiedName {
204 fn from(value: Refer<Vec<Identifier>>) -> Self {
205 Self(value)
206 }
207}
208
209impl FromIterator<Identifier> for QualifiedName {
210 fn from_iter<T: IntoIterator<Item = Identifier>>(iter: T) -> Self {
211 Self(Refer::none(iter.into_iter().collect()))
212 }
213}
214
215impl From<&Identifier> for QualifiedName {
216 fn from(id: &Identifier) -> Self {
217 Self(Refer::none(vec![id.clone()]))
218 }
219}
220
221impl From<&std::path::Path> for QualifiedName {
222 fn from(path: &std::path::Path) -> Self {
223 let path = if path.file_stem() == Some(std::ffi::OsStr::new("mod")) {
225 path.parent().expect("mod file in root path is not allowed")
226 } else {
227 path
228 };
229
230 QualifiedName::no_ref(
231 path.iter()
232 .map(|id| {
233 Identifier(Refer {
234 value: id.to_string_lossy().into_owned().into(),
235 src_ref: SrcRef(None),
236 })
237 })
238 .collect(),
239 )
240 }
241}
242
243#[cfg(test)]
244impl From<&str> for QualifiedName {
245 fn from(value: &str) -> Self {
246 Self(Refer::none(
247 value.split("::").map(Identifier::from).collect(),
248 ))
249 }
250}
251
252#[cfg(not(test))]
253impl TryFrom<&str> for QualifiedName {
254 type Error = crate::parse::ParseError;
255
256 fn try_from(value: &str) -> Result<Self, Self::Error> {
257 let mut name = Vec::new();
258 for id in value.split("::").map(Identifier::try_from) {
259 if id.is_err() {
260 return Err(crate::parse::ParseError::InvalidQualifiedName(value.into()));
261 }
262 name.push(id.expect("unexpected error"));
263 }
264
265 Ok(Self(Refer::none(name)))
266 }
267}
268
269impl TryFrom<String> for QualifiedName {
270 type Error = crate::parse::ParseError;
271
272 fn try_from(value: String) -> Result<Self, Self::Error> {
273 let mut name = Vec::new();
274 for id in value.split("::").map(Identifier::try_from) {
275 if id.is_err() {
276 return Err(crate::parse::ParseError::InvalidQualifiedName(value));
277 }
278 name.push(id.expect("unexpected error"));
279 }
280
281 Ok(Self(Refer::none(name)))
282 }
283}
284
285impl From<Identifier> for QualifiedName {
286 fn from(id: Identifier) -> Self {
287 let src_ref = id.src_ref();
288 QualifiedName(Refer::new(vec![id], src_ref))
289 }
290}
291
292impl From<QualifiedName> for String {
293 fn from(value: QualifiedName) -> Self {
294 join_identifiers(&value.0, "::")
295 }
296}
297
298impl TreeDisplay for QualifiedName {
299 fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
300 writeln!(
301 f,
302 "{:depth$}QualifiedName: '{}'",
303 "",
304 join_identifiers_debug(&self.0, "::")
305 )
306 }
307}