1mod iterators;
5mod symbol_definition;
6mod symbol_info;
7mod symbol_inner;
8mod symbol_map;
9mod symbols;
10
11use indexmap::IndexSet;
12pub use iterators::*;
13pub use symbol_definition::*;
14pub use symbol_info::*;
15pub(crate) use symbol_map::*;
16pub(crate) use symbols::*;
17
18use symbol_inner::*;
19
20use crate::{
21 builtin::*, rc::*, resolve::*, src_ref::*, syntax::*, tree_display::*, ty::*, value::*,
22};
23
24#[derive(Clone)]
26pub struct Symbol {
27 visibility: std::cell::RefCell<Visibility>,
28 src_ref: SrcRef,
29 inner: RcMut<SymbolInner>,
30}
31
32impl Symbol {
34 pub(crate) fn new(def: SymbolDef, parent: Option<Symbol>) -> Self {
40 Symbol {
41 visibility: std::cell::RefCell::new(def.visibility()),
42 inner: RcMut::new(SymbolInner {
43 def,
44 parent,
45 ..Default::default()
46 }),
47 ..Default::default()
48 }
49 }
50
51 pub(super) fn new_with_visibility(
57 visibility: Visibility,
58 def: SymbolDef,
59 parent: Option<Symbol>,
60 ) -> Self {
61 Symbol {
62 visibility: std::cell::RefCell::new(visibility),
63 inner: RcMut::new(SymbolInner {
64 def,
65 parent,
66 ..Default::default()
67 }),
68 ..Default::default()
69 }
70 }
71
72 pub(crate) fn new_builtin(builtin: Builtin) -> Symbol {
78 Symbol::new(SymbolDef::Builtin(Rc::new(builtin)), None)
79 }
80
81 pub fn new_builtin_fn(
83 name: &'static str,
84 parameters: impl Iterator<Item = (Identifier, ParameterValue)>,
85 f: &'static BuiltinFn,
86 doc: Option<&'static str>,
87 ) -> Symbol {
88 Self::new_builtin(Builtin {
89 id: Identifier::no_ref(name),
90 parameters: parameters.collect(),
91 kind: BuiltinKind::Function,
92 f,
93 doc: doc.map(DocBlock::new_builtin),
94 })
95 }
96
97 pub(super) fn replace(&mut self, replacement: Symbol) {
99 replacement
100 .inner
101 .borrow()
102 .children
103 .iter()
104 .for_each(|(_, child)| child.inner.borrow_mut().parent = Some(self.clone()));
105 self.inner.replace(replacement.inner.take());
106 }
107}
108
109impl Symbol {
110 pub(super) fn search_target_mode_ids(&self) -> IdentifierSet {
112 self.riter()
113 .filter(|symbol| symbol.is_target_mode())
114 .map(|symbol| symbol.id())
115 .collect()
116 }
117
118 pub(crate) fn unused_private(&self) -> Symbols {
122 let used_in_module = &mut IndexSet::new();
123 let mut symbols: Symbols = self
124 .riter()
125 .skip(1) .filter(|symbol| {
127 if let Some(in_module) = symbol.in_module()
128 && symbol.is_used()
129 {
130 used_in_module.insert(in_module);
131 }
132 symbol.is_unused_private()
133 })
134 .collect();
135
136 symbols.retain(|symbol| {
137 if let Some(in_module) = symbol.in_module() {
138 !used_in_module.contains(&in_module)
139 } else {
140 true
141 }
142 });
143 symbols.sort_by_key(|s| s.full_name());
144 symbols
145 }
146
147 pub(crate) fn lookup_within_name(
155 &self,
156 name: &QualifiedName,
157 within: &QualifiedName,
158 target: LookupTarget,
159 ) -> ResolveResult<Symbol> {
160 self.lookup_within(name, &self.search(within, false)?, target)
161 }
162}
163
164impl Symbol {
166 pub(super) fn get_child(&self, id: &Identifier) -> Option<Symbol> {
170 self.inner.borrow().children.get(id).cloned()
171 }
172
173 pub(crate) fn add_symbol(&mut self, symbol: Symbol) -> ResolveResult<()> {
175 self.insert_symbol(symbol.id(), symbol.clone())
176 }
177
178 pub(super) fn insert_symbol(&mut self, id: Identifier, symbol: Symbol) -> ResolveResult<()> {
180 log::trace!("insert symbol: {id}");
181 if let Some(symbol) = self.inner.borrow_mut().children.insert(id, symbol.clone()) {
182 Err(ResolveError::SymbolAlreadyDefined(symbol.full_name()))
183 } else {
184 Ok(())
185 }
186 }
187
188 pub(crate) fn add_child(parent: &Symbol, child: Symbol) {
193 child.inner.borrow_mut().parent = Some(parent.clone());
194 let id = child.id();
195 parent.inner.borrow_mut().children.insert(id, child);
196 }
197
198 pub(super) fn set_children(&self, new_children: SymbolMap) {
202 assert!(self.inner.borrow().children.is_empty());
203 self.inner.borrow_mut().children = new_children;
204 }
205
206 pub(crate) fn try_children<E: std::error::Error>(
208 &self,
209 f: impl FnMut((&Identifier, &Symbol)) -> Result<(), E>,
210 ) -> Result<(), E> {
211 self.inner.borrow().children.iter().try_for_each(f)
212 }
213
214 pub fn with_children(&self, f: impl FnMut((&Identifier, &Symbol))) {
216 self.inner.borrow().children.iter().for_each(f)
217 }
218
219 fn public_children(&self, visibility: Visibility, src_ref: SrcRef) -> SymbolMap {
221 let inner = self.inner.borrow();
222
223 inner
224 .children
225 .values()
226 .filter(|symbol| {
227 if symbol.is_public() {
228 true
229 } else {
230 log::trace!("Skipping private symbol:\n{symbol:?}");
231 false
232 }
233 })
234 .map(|symbol| symbol.clone_with(visibility.clone(), src_ref.clone()))
235 .map(|symbol| (symbol.id(), symbol))
236 .collect()
237 }
238
239 pub(crate) fn is_empty(&self) -> bool {
241 self.inner.borrow().children.is_empty()
242 }
243
244 pub(crate) fn get_parent(&self) -> Option<Symbol> {
246 self.inner.borrow().parent.clone()
247 }
248
249 pub(super) fn set_parent(&mut self, parent: Symbol) {
251 self.inner.borrow_mut().parent = Some(parent);
252 }
253
254 pub fn iter(&self) -> Children {
256 Children::new(self.clone())
257 }
258
259 pub fn riter(&self) -> RecurseChildren {
261 RecurseChildren::new(self.clone())
262 }
263}
264
265impl Symbol {
267 pub(super) fn visibility(&self) -> Visibility {
269 self.visibility.borrow().clone()
270 }
271
272 pub(super) fn is_public(&self) -> bool {
274 matches!(self.visibility(), Visibility::Public)
275 }
276
277 pub(super) fn is_deleted(&self) -> bool {
278 matches!(self.visibility(), Visibility::Deleted)
279 }
280
281 pub(super) fn delete(&self) {
282 self.visibility.replace(Visibility::Deleted);
283 }
284
285 pub(crate) fn clone_with(&self, visibility: Visibility, src_ref: SrcRef) -> Self {
287 Self {
288 visibility: std::cell::RefCell::new(visibility),
289 src_ref,
290 inner: self.inner.clone(),
291 }
292 }
293
294 pub(crate) fn reset_visibility(&self) {
295 self.visibility
296 .replace(self.with_def(|def| def.visibility()));
297 }
298}
299
300impl Symbol {
302 pub(crate) fn id(&self) -> Identifier {
304 self.inner.borrow().def.id()
305 }
306
307 pub(super) fn can_const(&self) -> bool {
309 matches!(
310 self.inner.borrow().def,
311 SymbolDef::Module(..) | SymbolDef::SourceFile(..) | SymbolDef::Workbench(..)
312 )
313 }
314
315 pub(super) fn can_value(&self) -> bool {
317 matches!(
318 self.inner.borrow().def,
319 SymbolDef::Function(..) | SymbolDef::Workbench(..) | SymbolDef::SourceFile(..)
320 )
321 }
322
323 pub(super) fn can_prop(&self) -> bool {
325 matches!(self.inner.borrow().def, SymbolDef::Workbench(..))
326 }
327
328 pub(super) fn can_public(&self) -> bool {
330 matches!(self.inner.borrow().def, SymbolDef::Module(..) | SymbolDef::SourceFile(..))
331 }
332
333 fn is_root(&self) -> bool {
334 matches!(self.inner.borrow().def, SymbolDef::Root)
335 }
336
337 pub(crate) fn is_source(&self) -> bool {
338 matches!(self.inner.borrow().def, SymbolDef::SourceFile(..))
339 }
340
341 pub(crate) fn is_module(&self) -> bool {
342 matches!(
343 self.inner.borrow().def,
344 SymbolDef::SourceFile(..) | SymbolDef::Module(..)
345 )
346 }
347
348 pub(crate) fn is_workbench(&self) -> bool {
349 matches!(self.inner.borrow().def, SymbolDef::Workbench(..))
350 }
351
352 pub(crate) fn set_value(&self, new_value: Value) -> ResolveResult<()> {
354 let is_a_value = match &mut self.inner.borrow_mut().def {
355 SymbolDef::Constant(.., value) => {
356 *value = new_value;
357 true
358 }
359 _ => false,
360 };
361 match is_a_value {
362 true => Ok(()),
363 false => Err(ResolveError::NotAValue(self.full_name())),
364 }
365 }
366
367 pub(super) fn source_path(&self) -> Option<std::path::PathBuf> {
369 if let SymbolDef::SourceFile(source_file) = &self.inner.borrow().def {
370 return source_file
371 .filename()
372 .parent()
373 .map(|path| path.to_path_buf());
374 }
375 self.get_parent().and_then(|parent| parent.source_path())
376 }
377
378 pub(super) fn is_resolvable(&self) -> bool {
379 matches!(
380 self.inner.borrow().def,
381 SymbolDef::SourceFile(..)
382 | SymbolDef::Module(..)
383 | SymbolDef::Workbench(..)
384 | SymbolDef::UseAll(..)
385 | SymbolDef::Alias(..)
386 ) && !self.is_deleted()
387 }
388
389 pub(super) fn is_link(&self) -> bool {
390 matches!(
391 self.inner.borrow().def,
392 SymbolDef::UseAll(..) | SymbolDef::Alias(..)
393 )
394 }
395
396 pub(super) fn is_alias(&self) -> bool {
397 matches!(self.inner.borrow().def, SymbolDef::Alias(..))
398 }
399
400 pub(super) fn get_link(&self) -> Option<QualifiedName> {
401 self.with_def(|def| match def {
402 SymbolDef::UseAll(_, name) | SymbolDef::Alias(.., name) => Some(name.clone()),
403 _ => None,
404 })
405 }
406
407 pub(super) fn has_links(&self) -> bool {
408 if self.is_link() {
409 true
410 } else {
411 self.inner
412 .borrow()
413 .children
414 .values()
415 .filter(|symbol| !symbol.is_deleted())
416 .any(|symbol| symbol.has_links())
417 }
418 }
419
420 pub(crate) fn with_def<T>(&self, mut f: impl FnMut(&SymbolDef) -> T) -> T {
422 f(&self.inner.borrow().def)
423 }
424
425 pub(crate) fn with_def_mut<T>(&self, mut f: impl FnMut(&mut SymbolDef) -> T) -> T {
427 f(&mut self.inner.borrow_mut().def)
428 }
429}
430
431impl Symbol {
433 pub(super) fn set_check(&self) {
435 let _ = self.inner.borrow().checked.set(());
436 }
437
438 pub(super) fn is_checked(&self) -> bool {
439 self.inner.borrow().checked.get().is_some()
440 }
441
442 pub(super) fn check(
444 &self,
445 context: &mut ResolveContext,
446 exclude_ids: &IdentifierSet,
447 ) -> ResolveResult<()> {
448 if !matches!(self.visibility.take(), Visibility::Deleted) {
449 let names = match &self.inner.borrow().def {
451 SymbolDef::SourceFile(sf) => sf.names(),
452 SymbolDef::Module(m) => m.names(),
453 SymbolDef::Workbench(wb) => wb.names(),
454 SymbolDef::Function(f) => f.names(),
455 SymbolDef::Assignment(a) => a.names(),
456 SymbolDef::Alias(_, _, name) | SymbolDef::UseAll(_, name) => {
457 log::error!("Resolve Context:\n{context:?}");
458 return Err(ResolveError::ResolveCheckFailed(name.src_ref()));
459 }
460 _ => Default::default(),
461 };
462
463 if !names.is_empty() {
464 log::debug!("checking symbols:\n{names:?}");
465 names
467 .iter()
468 .filter(|name| {
469 exclude_ids.contains(name.last().expect("symbol with empty name"))
470 })
471 .try_for_each(|name| {
473 match context.root.lookup(name, LookupTarget::Any) {
474 Ok(_) => Ok::<_, ResolveError>(()),
475 Err(err) => {
476 let module = match context.root.search(&self.module_name(), false) {
478 Ok(module) => module,
479 Err(err) => {
480 context.error(&self.id(), err)?;
481 return Ok(());
482 }
483 };
484 if context
486 .root
487 .lookup_within(name, &module, LookupTarget::Module)
488 .is_err()
489 {
490 context.error(name, err)?;
491 }
492 Ok(())
493 }
494 }
495 })?;
496 }
497
498 let children = self.inner.borrow().children.clone();
500 children
501 .values()
502 .try_for_each(|symbol| symbol.check(context, exclude_ids))
503 } else {
504 Ok(())
505 }
506 }
507
508 fn module_name(&self) -> QualifiedName {
509 match self.is_module() {
510 true => {
511 if let Some(parent) = &self.get_parent() {
512 parent.module_name().with_suffix(&self.id())
513 } else {
514 QualifiedName::from_id(self.id())
515 }
516 }
517 false => {
518 if let Some(parent) = &self.get_parent() {
519 parent.module_name()
520 } else {
521 unreachable!("root must be source file")
522 }
523 }
524 }
525 }
526
527 pub(crate) fn kind_str(&self) -> &'static str {
528 self.inner.borrow().def.kind_str()
529 }
530
531 pub(super) fn source_hash(&self) -> u64 {
532 self.inner.borrow().def.source_hash()
533 }
534}
535
536impl Symbol {
537 pub(crate) fn is_used(&self) -> bool {
538 self.inner.borrow().used.get().is_some()
539 }
540
541 pub(crate) fn set_used(&self) {
543 let _ = self.inner.borrow().used.set(());
544 }
545
546 pub(crate) fn is_unused_private(&self) -> bool {
547 !self.is_used() && !self.is_public() && !self.is_deleted()
548 }
549
550 pub(crate) fn in_module(&self) -> Option<QualifiedName> {
551 if let Visibility::PrivateUse(module) = self.visibility() {
552 Some(module.clone())
553 } else {
554 None
555 }
556 }
557
558 pub(super) fn resolve(&self, context: &mut ResolveContext) -> ResolveResult<SymbolMap> {
560 log::trace!("resolving: {self}");
561
562 let mut from_self = {
564 let inner = self.inner.borrow();
565 match &inner.def {
566 SymbolDef::Alias(visibility, id, name) => {
567 log::trace!("resolving use (as): {self} => {visibility}{id} ({name})");
568 let symbol = context
569 .root
570 .lookup_within_opt(name, &inner.parent, LookupTarget::Any)?
571 .clone_with(visibility.clone(), name.src_ref.clone());
572 self.delete();
573 [(id.clone(), symbol)].into_iter().collect()
574 }
575 SymbolDef::UseAll(visibility, name) => {
576 let visibility = &if matches!(visibility, &Visibility::Private) {
577 Visibility::PrivateUse(name.clone())
578 } else {
579 visibility.clone()
580 };
581 log::trace!("resolving use all: {self} => {visibility}{name}");
582 let symbols = context
583 .root
584 .lookup_within_opt(name, &inner.parent, LookupTarget::Any)?
585 .public_children(visibility.clone(), name.src_ref.clone());
586 if !symbols.is_empty() {
587 self.delete();
588 }
589 symbols
590 }
591 _ => SymbolMap::default(),
593 }
594 };
595
596 let resolved = from_self.resolve_all(context)?;
597 from_self.extend(resolved.iter().map(|(k, v)| (k.clone(), v.clone())));
598 let from_children = self.inner.borrow().children.resolve_all(context)?;
600 self.inner
601 .borrow_mut()
602 .children
603 .extend(from_children.iter().map(|(k, v)| (k.clone(), v.clone())));
604 Ok(from_self)
606 }
607
608 pub(crate) fn is_target_mode(&self) -> bool {
612 self.with_def(|def| match def {
613 SymbolDef::Builtin(builtin) => builtin
614 .parameters
615 .values()
616 .any(|param| param.ty() == Type::Target),
617 _ => false,
618 })
619 }
620
621 pub(crate) fn search(&self, name: &QualifiedName, respect: bool) -> ResolveResult<Symbol> {
625 log::trace!("Searching {name} in {:?}", self.full_name());
626 if let Some(id) = name.first() {
627 if id.is_super() {
628 if let Some(parent) = self.get_parent() {
629 return parent.search(&name[1..].iter().cloned().collect(), respect);
630 }
631 }
632 }
633 self.search_inner(name, true, respect)
634 }
635
636 fn search_inner(
637 &self,
638 name: &QualifiedName,
639 top_level: bool,
640 respect: bool,
641 ) -> ResolveResult<Symbol> {
642 if let Some(first) = name.first() {
643 if let Some(child) = self.get_child(first) {
644 if respect && !top_level && !child.is_public() {
645 log::trace!("Symbol {:?} is private", child.full_name());
646 Err(ResolveError::SymbolIsPrivate(child.full_name().clone()))
647 } else if name.is_single_identifier() && !child.is_deleted() {
648 log::trace!("Found {name:?} in {:?}", self.full_name());
649 self.set_used();
650 Ok(child.clone())
651 } else {
652 let name = &name.remove_first();
653 child.search_inner(name, false, respect)
654 }
655 } else {
656 log::trace!("No child in {:?} while searching for {name:?}", self.id());
657 Err(ResolveError::SymbolNotFound(name.clone()))
658 }
659 } else {
660 log::warn!("Cannot search for an anonymous name");
661 Err(ResolveError::SymbolNotFound(name.clone()))
662 }
663 }
664
665 pub(super) fn print_symbol(
671 &self,
672 f: &mut impl std::fmt::Write,
673 id: Option<&Identifier>,
674 state: TreeState,
675 children: bool,
676 ) -> std::fmt::Result {
677 let self_id = &self.id();
678 let id = id.unwrap_or(self_id);
679 let def = &self.inner.borrow().def;
680 let full_name = self.full_name();
681 let visibility = self.visibility();
682 let hash = self.source_hash();
683 let depth = state.depth;
684 if state.debug && cfg!(feature = "ansi-color") {
685 let checked = if self.is_checked() { " ✓" } else { "" };
686 if self.is_used() {
687 write!(
688 f,
689 "{:depth$}{visibility:?}{id:?} {def:?} [{full_name:?}] #{hash:#x}{checked}",
690 "",
691 )?;
692 } else {
693 color_print::cwrite!(
694 f,
695 "{:depth$}<#606060>{visibility:?}{id:?} {def:?} [{full_name:?}] #{hash:#x}</>{checked}",
696 "",
697 )?;
698 }
699 } else {
700 write!(f, "{:depth$}{id} {def} [{full_name}]", "",)?;
701 }
702 if children {
703 writeln!(f)?;
704 self.try_children(|(id, child)| {
705 child.print_symbol(f, Some(id), state.indented(), true)
706 })?;
707 }
708 Ok(())
709 }
710
711 pub(super) fn set_src_ref(&mut self, src_ref: SrcRef) {
712 self.src_ref = src_ref;
713 }
714}
715
716impl FullyQualify for Symbol {
717 fn full_name(&self) -> QualifiedName {
719 let id = self.id();
720 match &self.get_parent() {
721 Some(parent) => {
722 let mut name = parent.full_name();
723 name.push(id);
724 name
725 }
726
727 None => {
728 let src_ref = id.src_ref();
729 QualifiedName::new(vec![id], src_ref)
730 }
731 }
732 }
733}
734
735impl SrcReferrer for Symbol {
736 fn src_ref(&self) -> SrcRef {
737 if self.src_ref.is_none() {
738 self.inner.borrow().src_ref()
739 } else {
740 self.src_ref.clone()
741 }
742 }
743}
744
745impl Default for Symbol {
746 fn default() -> Self {
747 Self {
748 src_ref: SrcRef(None),
749 visibility: std::cell::RefCell::new(Visibility::default()),
750 inner: RcMut::new(Default::default()),
751 }
752 }
753}
754
755impl PartialEq for Symbol {
756 fn eq(&self, other: &Self) -> bool {
757 self.inner.as_ptr() == other.inner.as_ptr()
759 }
760}
761
762impl std::fmt::Display for Symbol {
763 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
764 self.print_symbol(f, None, TreeState::new_display(), false)
765 }
766}
767
768impl std::fmt::Debug for Symbol {
769 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
770 self.tree_print(f, TreeState::new_debug(0))
771 }
772}
773
774impl Info for Symbol {
775 fn info(&self) -> SymbolInfo {
776 self.with_def(|def| def.info())
777 }
778}
779
780impl TreeDisplay for Symbol {
781 fn tree_print(&self, f: &mut std::fmt::Formatter, state: TreeState) -> std::fmt::Result {
782 if self.is_root() {
783 self.try_children(|(_, symbol)| symbol.tree_print(f, TreeState::new_debug(1)))
784 } else {
785 self.print_symbol(f, Some(&self.id()), state, true)
786 }
787 }
788}
789
790#[test]
791fn test_symbol_resolve() {
792 let root = SourceFile::load_from_str(
793 Some("root"),
794 "",
795 "
796 use my;
797 x = my::target;
798
799 use my::target;
800 x = target;
801 ",
802 )
803 .expect("parse error");
804
805 let my = SourceFile::load_from_str(
806 Some("my"),
807 "",
808 "
809 pub const target = 1;
810 ",
811 )
812 .expect("parse error");
813
814 let mut context =
815 ResolveContext::test_create(root, ResolveMode::Symbolized).expect("resolve error");
816 context.test_add_file(my);
817 log::trace!("{context:?}");
818 context.resolve().expect("resolve error");
819}
820
821impl Lookup for Symbol {
822 fn lookup(&self, name: &QualifiedName, target: LookupTarget) -> ResolveResult<Symbol> {
824 log::trace!(
825 "{lookup} for global symbol '{name:?}'",
826 lookup = crate::mark!(LOOKUP)
827 );
828 self.deny_super(name)?;
829
830 let symbol = match self.search(name, true) {
831 Ok(symbol) => {
832 if target.matches(&symbol) {
833 symbol
834 } else {
835 log::trace!(
836 "{not_found} global symbol: {name:?}",
837 not_found = crate::mark!(NOT_FOUND),
838 );
839 return Err(ResolveError::WrongTarget);
840 }
841 }
842 Err(err) => {
843 log::trace!(
844 "{not_found} global symbol: {name:?}",
845 not_found = crate::mark!(NOT_FOUND),
846 );
847 return Err(err)?;
848 }
849 };
850 symbol.set_check();
851 log::trace!(
852 "{found} global symbol: {symbol:?}",
853 found = crate::mark!(FOUND),
854 );
855 Ok(symbol)
856 }
857
858 fn ambiguity_error(ambiguous: QualifiedName, others: QualifiedNames) -> ResolveError {
859 ResolveError::AmbiguousSymbol(ambiguous, others)
860 }
861}