1mod iterators;
7mod symbol_definition;
8mod symbol_inner;
9mod symbol_map;
10mod symbols;
11
12use indexmap::IndexSet;
13use microcad_lang_base::{RcMut, SrcRef, SrcReferrer, TreeDisplay, TreeState};
14
15pub use iterators::*;
16pub use symbol_definition::*;
17pub(crate) use symbol_map::*;
18pub(crate) use symbols::*;
19
20use symbol_inner::*;
21
22use crate::{builtin::*, lower::ir, resolve::*, value::*};
23
24#[derive(Clone)]
26pub struct Symbol {
27 visibility: std::cell::RefCell<ir::Visibility>,
28 src_ref: SrcRef,
29 inner: RcMut<SymbolInner>,
30}
31
32impl Symbol {
34 pub(crate) fn new(def: SymbolDef, parent: Option<Symbol>) -> Self {
39 Symbol {
40 visibility: std::cell::RefCell::new(def.visibility()),
41 inner: RcMut::new(SymbolInner {
42 def,
43 parent,
44 ..Default::default()
45 }),
46 ..Default::default()
47 }
48 }
49
50 pub(crate) fn new_with_visibility(
56 visibility: ir::Visibility,
57 def: SymbolDef,
58 parent: Option<Symbol>,
59 ) -> Self {
60 Symbol {
61 visibility: std::cell::RefCell::new(visibility),
62 inner: RcMut::new(SymbolInner {
63 def,
64 parent,
65 ..Default::default()
66 }),
67 ..Default::default()
68 }
69 }
70
71 pub(crate) fn new_builtin(builtin: impl Into<Builtin>) -> Symbol {
77 Symbol::new(SymbolDef::Builtin(builtin.into()), None)
78 }
79
80 pub fn new_builtin_fn(
82 name: &'static str,
83 parameters: impl Iterator<Item = (Identifier, ParameterValue)>,
84 f: &'static BuiltinFn,
85 doc: Option<&'static str>,
86 ) -> Symbol {
87 Self::new_builtin(BuiltinFunction {
88 id: Identifier::no_ref(name),
89 parameters: parameters.collect(),
90 f,
91 doc: doc.map(ir::DocBlock::new_builtin),
92 })
93 }
94
95 pub fn full_name(&self) -> ir::QualifiedName {
97 let id = self.id();
98 match &self.get_parent() {
99 Some(parent) => {
100 let mut name = parent.full_name();
101 name.push(id);
102 name
103 }
104
105 None => {
106 let src_ref = id.src_ref();
107 ir::QualifiedName::new(vec![id], src_ref)
108 }
109 }
110 }
111}
112
113impl Symbol {
114 pub(crate) fn unused_private(&self) -> Symbols {
118 let used_in_module = &mut IndexSet::new();
119 let mut symbols: Symbols = self
120 .riter()
121 .skip(1) .filter(|symbol| {
123 if let Some(in_module) = symbol.in_module()
124 && symbol.is_used()
125 {
126 used_in_module.insert(in_module);
127 }
128 symbol.is_unused_private()
129 })
130 .collect();
131
132 symbols.retain(|symbol| {
133 if let Some(in_module) = symbol.in_module() {
134 !used_in_module.contains(&in_module)
135 } else {
136 true
137 }
138 });
139 symbols.sort_by_key(|s| s.full_name());
140 symbols
141 }
142
143 pub(crate) fn lookup_within_name(
151 &self,
152 name: &ir::QualifiedName,
153 within: &ir::QualifiedName,
154 target: LookupTarget,
155 ) -> ResolveResult<Symbol> {
156 self.lookup_within(name, &self.search(within, false)?, target)
157 }
158}
159
160impl Symbol {
162 pub fn get_child(&self, id: &Identifier) -> Option<Symbol> {
166 self.inner.borrow().children.get(id).cloned()
167 }
168
169 pub(crate) fn add_symbol(&mut self, symbol: Symbol) -> ResolveResult<()> {
171 self.insert_symbol(symbol.id(), symbol.clone())
172 }
173
174 pub(super) fn insert_symbol(&mut self, id: Identifier, symbol: Symbol) -> ResolveResult<()> {
176 log::trace!("insert symbol: {id}");
177 if let Some(symbol) = self.inner.borrow_mut().children.insert(id, symbol.clone()) {
178 Err(ResolveError::SymbolAlreadyDefined(symbol.full_name()))
179 } else {
180 Ok(())
181 }
182 }
183
184 pub(crate) fn add_child(parent: &Symbol, child: Symbol) {
189 child.inner.borrow_mut().parent = Some(parent.clone());
190 let id = child.id();
191 parent.inner.borrow_mut().children.insert(id, child);
192 }
193
194 pub(super) fn set_children(&self, new_children: SymbolMap) {
198 assert!(self.inner.borrow().children.is_empty());
199 self.inner.borrow_mut().children = new_children;
200 }
201
202 pub(crate) fn try_children<E: std::error::Error>(
204 &self,
205 f: impl FnMut((&Identifier, &Symbol)) -> Result<(), E>,
206 ) -> Result<(), E> {
207 self.inner.borrow().children.iter().try_for_each(f)
208 }
209
210 pub(crate) fn try_children_sorted<E: std::error::Error>(
212 &self,
213 f: impl FnMut((&Identifier, &Symbol)) -> Result<(), E>,
214 ) -> Result<(), E> {
215 let mut children = self.inner.borrow().children.clone();
216 children.sort_by(|id1, _, id2, _| id1.cmp(id2));
217 children.iter().try_for_each(f)
218 }
219
220 pub fn with_children(&self, f: impl FnMut((&Identifier, &Symbol))) {
222 self.inner.borrow().children.iter().for_each(f)
223 }
224
225 fn public_children(&self, visibility: ir::Visibility, src_ref: SrcRef) -> SymbolMap {
227 let inner = self.inner.borrow();
228
229 inner
230 .children
231 .values()
232 .filter(|symbol| {
233 if symbol.is_public() {
234 true
235 } else {
236 log::trace!("Skipping private symbol:\n{symbol:?}");
237 false
238 }
239 })
240 .map(|symbol| symbol.clone_with(visibility.clone(), src_ref))
241 .map(|symbol| (symbol.id(), symbol))
242 .collect()
243 }
244
245 pub(crate) fn get_parent(&self) -> Option<Symbol> {
247 self.inner.borrow().parent.clone()
248 }
249
250 pub(super) fn set_parent(&mut self, parent: Symbol) {
252 self.inner.borrow_mut().parent = Some(parent);
253 }
254
255 pub fn iter(&self) -> Children {
257 Children::new(self.clone())
258 }
259
260 pub fn riter(&self) -> RecurseChildren {
262 RecurseChildren::new(self.clone())
263 }
264
265 pub fn kind_ref(&self) -> Option<SrcRef> {
267 self.inner.borrow().kind_ref()
268 }
269}
270
271impl Symbol {
273 pub fn visibility(&self) -> ir::Visibility {
275 self.visibility.borrow().clone()
276 }
277
278 pub fn is_public(&self) -> bool {
280 matches!(self.visibility(), ir::Visibility::Public)
281 }
282
283 pub(super) fn is_deleted(&self) -> bool {
284 matches!(self.visibility(), ir::Visibility::Deleted)
285 }
286
287 pub(super) fn delete(&self) {
288 self.visibility.replace(ir::Visibility::Deleted);
289 }
290
291 pub(crate) fn clone_with(&self, visibility: ir::Visibility, src_ref: SrcRef) -> Self {
293 Self {
294 visibility: std::cell::RefCell::new(visibility),
295 src_ref,
296 inner: self.inner.clone(),
297 }
298 }
299}
300
301impl Symbol {
303 pub fn id(&self) -> Identifier {
305 self.inner.borrow().def.id()
306 }
307
308 pub(super) fn can_const(&self) -> bool {
310 matches!(
311 self.inner.borrow().def,
312 SymbolDef::Module(..) | SymbolDef::SourceFile(..) | SymbolDef::Workbench(..)
313 )
314 }
315
316 pub(super) fn can_value(&self) -> bool {
318 matches!(
319 self.inner.borrow().def,
320 SymbolDef::Function(..) | SymbolDef::Workbench(..) | SymbolDef::SourceFile(..)
321 )
322 }
323
324 pub(super) fn can_prop(&self) -> bool {
326 matches!(self.inner.borrow().def, SymbolDef::Workbench(..))
327 }
328
329 fn is_root(&self) -> bool {
330 matches!(self.inner.borrow().def, SymbolDef::Root)
331 }
332
333 pub(crate) fn is_module(&self) -> bool {
334 matches!(
335 self.inner.borrow().def,
336 SymbolDef::SourceFile(..) | SymbolDef::Module(..)
337 )
338 }
339
340 pub(crate) fn is_workbench(&self) -> bool {
341 matches!(self.inner.borrow().def, SymbolDef::Workbench(..))
342 }
343
344 pub(crate) fn set_value(&self, new_value: Value) -> ResolveResult<()> {
346 let is_a_value = match &mut self.inner.borrow_mut().def {
347 SymbolDef::Value(.., value) => {
348 *value = new_value;
349 true
350 }
351 _ => false,
352 };
353 match is_a_value {
354 true => Ok(()),
355 false => Err(ResolveError::NotAValue(self.full_name())),
356 }
357 }
358
359 pub(super) fn source_path(&self) -> Option<std::path::PathBuf> {
361 if let SymbolDef::SourceFile(source_file) = &self.inner.borrow().def {
362 return source_file
363 .filename()
364 .parent()
365 .map(|path| path.to_path_buf());
366 }
367 self.get_parent().and_then(|parent| parent.source_path())
368 }
369
370 pub(super) fn is_resolvable(&self) -> bool {
371 matches!(
372 self.inner.borrow().def,
373 SymbolDef::SourceFile(..)
374 | SymbolDef::Module(..)
375 | SymbolDef::Function(..)
376 | SymbolDef::Workbench(..)
377 | SymbolDef::UseAll(..)
378 | SymbolDef::Alias(..)
379 ) && !self.is_deleted()
380 }
381
382 pub(super) fn is_link(&self) -> bool {
383 matches!(
384 self.inner.borrow().def,
385 SymbolDef::UseAll(..) | SymbolDef::Alias(..)
386 )
387 }
388
389 pub(super) fn is_alias(&self) -> bool {
390 matches!(self.inner.borrow().def, SymbolDef::Alias(..))
391 }
392
393 pub(super) fn has_links(&self) -> bool {
394 if self.is_link() {
395 true
396 } else {
397 self.inner
398 .borrow()
399 .children
400 .values()
401 .filter(|symbol| !symbol.is_deleted())
402 .any(|symbol| symbol.has_links())
403 }
404 }
405
406 pub fn with_def<T>(&self, mut f: impl FnMut(&SymbolDef) -> T) -> T {
408 f(&self.inner.borrow().def)
409 }
410
411 pub(crate) fn with_def_mut<T>(&self, mut f: impl FnMut(&mut SymbolDef) -> T) -> T {
413 f(&mut self.inner.borrow_mut().def)
414 }
415}
416
417impl Symbol {
419 pub(super) fn source_hash(&self) -> u64 {
420 self.inner.borrow().def.source_hash()
421 }
422
423 pub(crate) fn is_used(&self) -> bool {
424 self.inner.borrow().used.get().is_some()
425 }
426
427 pub(crate) fn set_used(&self) {
429 let _ = self.inner.borrow().used.set(());
430 }
431
432 pub(crate) fn is_unused_private(&self) -> bool {
433 !self.is_used() && !self.is_public() && !self.is_deleted()
434 }
435
436 pub(crate) fn in_module(&self) -> Option<ir::QualifiedName> {
437 if let ir::Visibility::PrivateUse(module) = self.visibility() {
438 Some(module.clone())
439 } else {
440 None
441 }
442 }
443
444 pub(super) fn resolve(&self, context: &mut ResolveContext) -> ResolveResult<SymbolMap> {
446 log::trace!("resolving: {self}");
447
448 let mut from_self = {
450 let inner = self.inner.borrow();
451 match &inner.def {
452 SymbolDef::Alias(visibility, id, name) => {
453 log::trace!("resolving use (as): {self} => {visibility}{id} ({name})");
454 let symbol = context
455 .root
456 .lookup_within_opt(name, &inner.parent, LookupTarget::Any)?
457 .clone_with(visibility.clone(), name.src_ref);
458 self.delete();
459 [(id.clone(), symbol)].into_iter().collect()
460 }
461 SymbolDef::UseAll(visibility, name) => {
462 let visibility = &if matches!(visibility, &ir::Visibility::Private) {
463 ir::Visibility::PrivateUse(name.clone())
464 } else {
465 visibility.clone()
466 };
467 log::trace!("resolving use all: {self} => {visibility}{name}");
468 let symbols = context
469 .root
470 .lookup_within_opt(name, &inner.parent, LookupTarget::Any)?
471 .public_children(visibility.clone(), name.src_ref);
472 if !symbols.is_empty() {
473 self.delete();
474 }
475 symbols
476 }
477 _ => SymbolMap::default(),
479 }
480 };
481
482 let resolved = from_self.resolve_all(context)?;
483 from_self.extend(resolved.iter().map(|(k, v)| (k.clone(), v.clone())));
484 let from_children = self.inner.borrow().children.resolve_all(context)?;
486 self.inner
487 .borrow_mut()
488 .children
489 .extend(from_children.iter().map(|(k, v)| (k.clone(), v.clone())));
490 Ok(from_self)
492 }
493
494 pub(crate) fn search(&self, name: &ir::QualifiedName, respect: bool) -> ResolveResult<Symbol> {
498 log::trace!("Searching {name} in {:?}", self.full_name());
499 if let Some(id) = name.first() {
500 if id.is_super() {
501 if let Some(parent) = self.get_parent() {
502 return parent.search(&name[1..].iter().cloned().collect(), respect);
503 }
504 }
505 }
506 self.search_inner(name, true, respect)
507 }
508
509 fn search_inner(
510 &self,
511 name: &ir::QualifiedName,
512 top_level: bool,
513 respect: bool,
514 ) -> ResolveResult<Symbol> {
515 use crate::lower::SingleIdentifier;
516
517 if let Some(first) = name.first() {
518 if let Some(child) = self.get_child(first) {
519 if respect && !top_level && !child.is_public() {
520 log::trace!("Symbol {:?} is private", child.full_name());
521 Err(ResolveError::SymbolIsPrivate(child.full_name().clone()))
522 } else if name.is_single_identifier() && !child.is_deleted() {
523 log::trace!("Found {name:?} in {:?}", self.full_name());
524 self.set_used();
525 Ok(child.clone())
526 } else {
527 let name = &name.remove_first();
528 child.search_inner(name, false, respect)
529 }
530 } else {
531 log::trace!("No child in {:?} while searching for {name:?}", self.id());
532 Err(ResolveError::SymbolNotFound(name.clone()))
533 }
534 } else {
535 log::warn!("Cannot search for an anonymous name");
536 Err(ResolveError::SymbolNotFound(name.clone()))
537 }
538 }
539
540 pub(super) fn print_symbol(
546 &self,
547 f: &mut impl std::fmt::Write,
548 id: Option<&ir::Identifier>,
549 state: TreeState,
550 children: bool,
551 ) -> std::fmt::Result {
552 let self_id = &self.id();
553 let id = id.unwrap_or(self_id);
554 let def = &self.inner.borrow().def;
555 let full_name = self.full_name();
556 let visibility = self.visibility();
557 let hash = self.source_hash();
558 let depth = state.depth;
559 if state.debug {
560 if self.is_used() {
561 write!(
562 f,
563 "{:depth$}{visibility:?}{id:?} {def:?} [{full_name:?}] #{hash:#x}",
564 "",
565 )?;
566 } else {
567 color_print::cwrite!(
568 f,
569 "{:depth$}<#606060>{visibility:?}{id:?} {def:?} [{full_name:?}] #{hash:#x}</>",
570 "",
571 )?;
572 }
573 } else {
574 write!(f, "{:depth$}{id} {def} [{full_name}]", "",)?;
575 }
576 if children {
577 writeln!(f)?;
578 if state.debug {
579 self.try_children(|(id, child)| {
580 child.print_symbol(f, Some(id), state.indented(), true)
581 })?;
582 } else {
583 self.try_children_sorted(|(id, child)| {
584 child.print_symbol(f, Some(id), state.indented(), true)
585 })?;
586 }
587 }
588 Ok(())
589 }
590
591 pub(super) fn set_src_ref(&mut self, src_ref: SrcRef) {
592 self.src_ref = src_ref;
593 }
594}
595
596impl SrcReferrer for Symbol {
597 fn src_ref(&self) -> SrcRef {
598 if self.src_ref.is_none() {
599 self.inner.borrow().src_ref()
600 } else {
601 self.src_ref
602 }
603 }
604}
605
606impl Default for Symbol {
607 fn default() -> Self {
608 Self {
609 src_ref: SrcRef::none(),
610 visibility: std::cell::RefCell::new(ir::Visibility::default()),
611 inner: RcMut::new(Default::default()),
612 }
613 }
614}
615
616impl PartialEq for Symbol {
617 fn eq(&self, other: &Self) -> bool {
618 self.inner.as_ptr() == other.inner.as_ptr()
620 }
621}
622
623impl std::fmt::Display for Symbol {
624 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
625 self.print_symbol(f, None, TreeState::new_display(), false)
626 }
627}
628
629impl std::fmt::Debug for Symbol {
630 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631 self.tree_print(f, TreeState::new_debug(0))
632 }
633}
634
635impl TreeDisplay for Symbol {
636 fn tree_print(&self, f: &mut std::fmt::Formatter, state: TreeState) -> std::fmt::Result {
637 if self.is_root() {
638 if state.debug {
639 self.try_children(|(_, symbol)| symbol.tree_print(f, state))
640 } else {
641 self.try_children_sorted(|(_, symbol)| symbol.tree_print(f, state))
642 }
643 } else {
644 self.print_symbol(f, Some(&self.id()), state, true)
645 }
646 }
647}
648
649impl Lookup for Symbol {
650 fn lookup(&self, name: &ir::QualifiedName, target: LookupTarget) -> ResolveResult<Symbol> {
652 log::trace!(
653 "{lookup} for global symbol '{name:?}'",
654 lookup = microcad_lang_base::mark!(LOOKUP)
655 );
656
657 let symbol = match self.search(name, true) {
658 Ok(symbol) => {
659 if target.matches(&symbol) {
660 symbol
661 } else {
662 log::trace!(
663 "{not_found} global symbol: {name:?}",
664 not_found = microcad_lang_base::mark!(NOT_FOUND),
665 );
666 return Err(ResolveError::WrongTarget);
667 }
668 }
669 Err(err) => {
670 log::trace!(
671 "{not_found} global symbol: {name:?}",
672 not_found = microcad_lang_base::mark!(NOT_FOUND),
673 );
674 return Err(err)?;
675 }
676 };
677 log::trace!(
678 "{found} global symbol: {symbol:?}",
679 found = microcad_lang_base::mark!(FOUND),
680 );
681 Ok(symbol)
682 }
683
684 fn ambiguity_error(ambiguous: ir::QualifiedName, others: ir::QualifiedNames) -> ResolveError {
685 ResolveError::AmbiguousSymbol(ambiguous, others)
686 }
687}