microcad_lang/resolve/
symbol.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use crate::{builtin::*, rc::*, resolve::*, src_ref::*, syntax::*, value::*};
5use custom_debug::Debug;
6use derive_more::{Deref, DerefMut};
7
8/// Symbol content
9#[derive(Debug, Clone)]
10pub struct SymbolInner {
11    /// Symbol definition
12    pub def: SymbolDefinition,
13    /// Symbol's parent
14    #[debug(skip)]
15    pub parent: Option<Symbol>,
16    /// Symbol's children
17    pub children: SymbolMap,
18    /// Flag if this symbol was in use
19    pub used: bool,
20}
21
22impl Default for SymbolInner {
23    fn default() -> Self {
24        Self {
25            def: SymbolDefinition::SourceFile(SourceFile::default().into()),
26            parent: Default::default(),
27            children: Default::default(),
28            used: false,
29        }
30    }
31}
32
33/// Symbol
34///
35/// Every `Symbol` has a [`SymbolDefinition`], a *parent* and *children* stored within a `Rc<RefCell<`[`SymbolInner`]`>`.
36/// So `Symbol` is meant as a tree which is used by [`SymbolTable`] to store
37/// the resolved symbols by it's original structure in the source code and by it's *id*.
38///
39/// `Symbol` can be shared as mutable.
40#[derive(Debug, Clone, Deref, DerefMut)]
41pub struct Symbol {
42    visibility: Visibility,
43    #[deref]
44    #[deref_mut]
45    inner: RcMut<SymbolInner>,
46}
47
48/// List of qualified names which can pe displayed
49#[derive(Debug, Deref)]
50pub struct Symbols(Vec<Symbol>);
51
52impl Symbols {
53    /// Return all fully qualified names of all symbols.
54    pub fn full_names(&self) -> QualifiedNames {
55        self.iter().map(|symbol| symbol.full_name()).collect()
56    }
57}
58
59impl Default for Symbol {
60    fn default() -> Self {
61        Self {
62            visibility: Visibility::default(),
63            inner: RcMut::new(Default::default()),
64        }
65    }
66}
67
68impl PartialEq for Symbol {
69    fn eq(&self, other: &Self) -> bool {
70        // just compare the visibility and the pointers - not the content
71        self.visibility == other.visibility && self.inner.as_ptr() == other.inner.as_ptr()
72    }
73}
74
75impl From<Vec<Symbol>> for Symbols {
76    fn from(value: Vec<Symbol>) -> Self {
77        Self(value)
78    }
79}
80
81impl std::fmt::Display for Symbols {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(
84            f,
85            "{}",
86            self.0
87                .iter()
88                .map(|symbol| symbol.to_string())
89                .collect::<Vec<_>>()
90                .join("")
91        )
92    }
93}
94
95impl FromIterator<Symbol> for Symbols {
96    fn from_iter<T: IntoIterator<Item = Symbol>>(iter: T) -> Self {
97        Self(iter.into_iter().collect())
98    }
99}
100
101impl Symbol {
102    /// Create new symbol without children.
103    /// # Arguments
104    /// - `visibility`: Visibility of the symbol
105    /// - `def`: Symbol definition
106    /// - `parent`: Symbol's parent symbol or none for root
107    pub fn new(def: SymbolDefinition, parent: Option<Symbol>) -> Self {
108        Symbol {
109            visibility: def.visibility(),
110            inner: RcMut::new(SymbolInner {
111                def,
112                parent,
113                ..Default::default()
114            }),
115        }
116    }
117
118    /// Create a symbol node for a built-in.
119    /// # Arguments
120    /// - `id`: Name of the symbol
121    /// - `parameters`: Optional parameter list
122    /// - `f`: The builtin function
123    pub fn new_builtin(
124        id: Identifier,
125        parameters: Option<ParameterValueList>,
126        f: &'static BuiltinFn,
127    ) -> Symbol {
128        Symbol::new(
129            SymbolDefinition::Builtin(Rc::new(Builtin { id, parameters, f })),
130            None,
131        )
132    }
133
134    /// Create a new argument ([`SymbolDefinition::Argument`]).
135    pub fn new_call_argument(id: Identifier, value: Value) -> Symbol {
136        Symbol::new(SymbolDefinition::Argument(id, value), None)
137    }
138
139    /// Print out symbols from that point.
140    /// # Arguments
141    /// - `f`: Output formatter
142    /// - `id`: Overwrite symbol's internal `id` with this one if given (e.g. when using in a map).
143    /// - `depth`: Indention depth to use
144    pub fn print_symbol(
145        &self,
146        f: &mut impl std::fmt::Write,
147        id: Option<&Identifier>,
148        depth: usize,
149        children: bool,
150    ) -> std::fmt::Result {
151        let self_id = &self.id();
152        let id = id.unwrap_or(self_id);
153        if cfg!(feature = "ansi-color") && !self.borrow().used {
154            color_print::cwrite!(
155                f,
156                "{:depth$}<#606060>{visibility}{id:?} {def} [{full_name}]</>",
157                "",
158                visibility = self.visibility(),
159                def = self.inner.borrow().def,
160                full_name = self.full_name(),
161            )?;
162        } else {
163            write!(
164                f,
165                "{:depth$}{id:?} {} [{}]",
166                "",
167                self.inner.borrow().def,
168                self.full_name(),
169            )?;
170        }
171        if children {
172            writeln!(f)?;
173            let indent = 4;
174
175            self.borrow().children.iter().try_for_each(|(id, child)| {
176                child.print_symbol(f, Some(id), depth + indent, true)
177            })?;
178        }
179        Ok(())
180    }
181
182    /// Insert child and change parent of child to new parent.
183    /// # Arguments
184    /// - `parent`: New parent symbol (will be changed in child!).
185    /// - `child`: Child to insert
186    pub fn add_child(parent: &Symbol, child: Symbol) {
187        child.borrow_mut().parent = Some(parent.clone());
188        let id = child.id();
189        parent.borrow_mut().children.insert(id, child);
190    }
191
192    /// Move all children from another symbol into this one.
193    /// # Arguments
194    /// - `from`: Append this symbol's children
195    ///
196    /// Technically, nothing will be moved here because of the `Rc<RefCell<>>`,
197    /// but by resetting the parent of all moved  children, those will see
198    /// themselves as child of `self` (e.g when providing fully qualified name).
199    pub fn move_children(&self, from: &Symbol) {
200        // copy children
201        from.borrow().children.iter().for_each(|(id, child)| {
202            child.borrow_mut().parent = Some(self.clone());
203            self.borrow_mut().children.insert(id.clone(), child.clone());
204        });
205    }
206
207    /// Clone this symbol but give the clone another visibility.
208    pub fn clone_with_visibility(&self, visibility: Visibility) -> Self {
209        let mut cloned = self.clone();
210        cloned.visibility = visibility;
211        cloned
212    }
213
214    /// Return the internal *id* of this symbol.
215    pub fn id(&self) -> Identifier {
216        self.borrow().def.id()
217    }
218
219    /// Get any child with the given `id`.
220    /// # Arguments
221    /// - `id`: Anticipated *id* of the possible child.
222    pub fn get(&self, id: &Identifier) -> Option<Symbol> {
223        self.borrow().children.get(id).cloned()
224    }
225
226    /// True if symbol has any children
227    pub fn is_empty(&self) -> bool {
228        self.borrow().children.is_empty()
229    }
230
231    /// Return `true` if symbol's visibility is private
232    pub fn visibility(&self) -> Visibility {
233        self.visibility
234    }
235
236    /// Return `true` if symbol's visibility set to is public.
237    pub fn is_public(&self) -> bool {
238        matches!(self.visibility(), Visibility::Public)
239    }
240
241    /// Return `true` if symbol's visibility set to is non-public.
242    pub fn is_private(&self) -> bool {
243        !self.is_public()
244    }
245
246    /// Search down the symbol tree for a qualified name.
247    /// # Arguments
248    /// - `name`: Name to search for.
249    pub fn search(&self, name: &QualifiedName) -> Option<Symbol> {
250        log::trace!("Searching {name} in {:?}", self.full_name());
251        if let Some(first) = name.first() {
252            if let Some(child) = self.get(first) {
253                let name = &name.remove_first();
254                if name.is_empty() {
255                    log::trace!("Found {name:?} in {:?}", self.full_name());
256                    Some(child.clone())
257                } else {
258                    child.search(name)
259                }
260            } else {
261                log::trace!("No child in {:?} while searching for {name:?}", self.id());
262                None
263            }
264        } else {
265            log::warn!("Cannot search for an anonymous name");
266            None
267        }
268    }
269
270    /// check if a private symbol may be declared within this symbol
271    pub fn can_const(&self) -> bool {
272        matches!(
273            self.borrow().def,
274            SymbolDefinition::Module(..) | SymbolDefinition::SourceFile(..)
275        )
276    }
277
278    /// check if a value on the stack may be declared within this symbol
279    pub fn can_value(&self) -> bool {
280        matches!(
281            self.borrow().def,
282            SymbolDefinition::Function(..)
283                | SymbolDefinition::Workbench(..)
284                | SymbolDefinition::SourceFile(..)
285        )
286    }
287
288    /// check if a property may be declared within this symbol
289    pub fn can_prop(&self) -> bool {
290        matches!(self.borrow().def, SymbolDefinition::Workbench(..))
291    }
292
293    /// check if a public symbol may be declared within this symbol
294    pub fn can_pub(&self) -> bool {
295        self.can_const()
296    }
297
298    /// Overwrite any value in this symbol
299    pub fn set_value(&self, new_value: Value) -> ResolveResult<()> {
300        match &mut self.borrow_mut().def {
301            SymbolDefinition::Constant(_, _, value) => {
302                *value = new_value;
303                Ok(())
304            }
305            _ => Err(ResolveError::NotAValue(self.full_name())),
306        }
307    }
308
309    /// Get any value of this symbol
310    pub fn get_value(&self) -> ResolveResult<Value> {
311        match &self.borrow().def {
312            SymbolDefinition::Constant(_, _, value) => Ok(value.clone()),
313            _ => Err(ResolveError::NotAValue(self.full_name())),
314        }
315    }
316}
317
318impl FullyQualify for Symbol {
319    /// Get fully qualified name.
320    fn full_name(&self) -> QualifiedName {
321        let id = self.id();
322        match &self.borrow().parent {
323            Some(parent) => {
324                let mut name = parent.full_name();
325                name.push(id);
326                name
327            }
328
329            None => {
330                let src_ref = id.src_ref();
331                QualifiedName::new(vec![id], src_ref)
332            }
333        }
334    }
335}
336
337impl std::fmt::Display for Symbol {
338    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339        self.print_symbol(f, None, 0, false)
340    }
341}
342
343impl SrcReferrer for SymbolInner {
344    fn src_ref(&self) -> SrcRef {
345        match &self.def {
346            SymbolDefinition::SourceFile(source_file) => source_file.src_ref(),
347            SymbolDefinition::Module(module) => module.src_ref(),
348            SymbolDefinition::Workbench(workbench) => workbench.src_ref(),
349            SymbolDefinition::Function(function) => function.src_ref(),
350            SymbolDefinition::Builtin(_) => {
351                unreachable!("builtin has no source code reference")
352            }
353            SymbolDefinition::Constant(_, identifier, _)
354            | SymbolDefinition::Argument(identifier, _) => identifier.src_ref(),
355            SymbolDefinition::Alias(_, identifier, _) => identifier.src_ref(),
356            SymbolDefinition::UseAll(_, name) => name.src_ref(),
357            #[cfg(test)]
358            SymbolDefinition::Tester(id) => id.src_ref(),
359        }
360    }
361}