1mod symbol_definition;
5mod symbol_info;
6mod symbol_inner;
7mod symbol_map;
8mod symbols;
9
10pub use symbol_definition::*;
11pub use symbol_info::*;
12pub(crate) use symbol_map::*;
13pub(crate) use symbols::*;
14
15use symbol_inner::*;
16
17use crate::{builtin::*, rc::*, resolve::*, src_ref::*, syntax::*, ty::*, value::*};
18
19#[derive(Clone)]
27pub struct Symbol {
28 visibility: std::cell::RefCell<Visibility>,
29 src_ref: SrcRef,
30 inner: RcMut<SymbolInner>,
31}
32
33impl Symbol {
35 pub fn new(def: SymbolDef, parent: Option<Symbol>) -> Self {
41 Symbol {
42 visibility: std::cell::RefCell::new(def.visibility()),
43 inner: RcMut::new(SymbolInner {
44 def,
45 parent,
46 ..Default::default()
47 }),
48 ..Default::default()
49 }
50 }
51
52 pub(super) fn new_with_visibility(
58 visibility: Visibility,
59 def: SymbolDef,
60 parent: Option<Symbol>,
61 ) -> Self {
62 Symbol {
63 visibility: std::cell::RefCell::new(visibility),
64 inner: RcMut::new(SymbolInner {
65 def,
66 parent,
67 ..Default::default()
68 }),
69 ..Default::default()
70 }
71 }
72
73 pub fn new_builtin(builtin: Builtin) -> Symbol {
79 Symbol::new(SymbolDef::Builtin(Rc::new(builtin)), None)
80 }
81
82 pub fn new_builtin_fn(
84 name: &'static str,
85 parameters: impl Iterator<Item = (Identifier, ParameterValue)>,
86 f: &'static BuiltinFn,
87 doc: Option<&'static str>,
88 ) -> Symbol {
89 Self::new_builtin(Builtin {
90 id: Identifier::no_ref(name),
91 parameters: parameters.collect(),
92 kind: BuiltinKind::Function,
93 f,
94 doc: doc.map(DocBlock::new_builtin),
95 })
96 }
97
98 pub fn replace(&mut self, replacement: Symbol) {
100 replacement
101 .inner
102 .borrow()
103 .children
104 .iter()
105 .for_each(|(_, child)| child.inner.borrow_mut().parent = Some(self.clone()));
106 self.inner.replace(replacement.inner.take());
107 }
108}
109
110impl Symbol {
112 fn get_child(&self, id: &Identifier) -> Option<Symbol> {
116 self.inner.borrow().children.get(id).cloned()
117 }
118
119 pub(crate) fn add_child(parent: &Symbol, child: Symbol) {
124 child.inner.borrow_mut().parent = Some(parent.clone());
125 let id = child.id();
126 parent.inner.borrow_mut().children.insert(id, child);
127 }
128
129 pub(super) fn set_children(&self, new_children: SymbolMap) {
133 assert!(self.inner.borrow().children.is_empty());
134 self.inner.borrow_mut().children = new_children;
135 }
136
137 pub fn try_children<E: std::error::Error>(
139 &self,
140 f: impl FnMut((&Identifier, &Symbol)) -> Result<(), E>,
141 ) -> Result<(), E> {
142 self.inner.borrow().children.iter().try_for_each(f)
143 }
144
145 pub fn with_children(&self, f: impl FnMut((&Identifier, &Symbol))) {
147 self.inner.borrow().children.iter().for_each(f)
148 }
149
150 fn public_children(&self, visibility: Visibility, src_ref: SrcRef) -> SymbolMap {
152 let inner = self.inner.borrow();
153
154 inner
155 .children
156 .values()
157 .filter(|symbol| {
158 if symbol.is_public() {
159 true
160 } else {
161 log::trace!("Skipping private symbol:\n{symbol:?}");
162 false
163 }
164 })
165 .map(|symbol| symbol.clone_with(visibility.clone(), src_ref.clone()))
166 .map(|symbol| (symbol.id(), symbol))
167 .collect()
168 }
169
170 pub(crate) fn is_empty(&self) -> bool {
172 self.inner.borrow().children.is_empty()
173 }
174
175 pub(crate) fn get_parent(&self) -> Option<Symbol> {
177 self.inner.borrow().parent.clone()
178 }
179
180 pub(super) fn set_parent(&mut self, parent: Symbol) {
182 self.inner.borrow_mut().parent = Some(parent);
183 }
184
185 pub(crate) fn recursive_collect<F>(&self, f: &mut F, result: &mut Vec<Symbol>)
186 where
187 F: FnMut(&Symbol) -> bool,
188 {
189 if f(self) {
190 result.push(self.clone());
191 }
192 self.inner
193 .borrow()
194 .children
195 .values()
196 .for_each(|symbol| symbol.recursive_collect(f, result));
197 }
198
199 #[allow(dead_code)]
200 pub(crate) fn recursive_for_each<F>(&self, id: &Identifier, f: &F)
201 where
202 F: Fn(&Identifier, &Symbol),
203 {
204 f(id, self);
205 self.inner
206 .borrow()
207 .children
208 .iter()
209 .for_each(|(id, symbol)| symbol.recursive_for_each(id, f));
210 }
211
212 pub(crate) fn recursive_for_each_mut<F>(&mut self, id: &Identifier, f: &F)
213 where
214 F: Fn(&Identifier, &mut Symbol),
215 {
216 f(id, self);
217 self.inner
218 .borrow_mut()
219 .children
220 .iter_mut()
221 .for_each(|(id, symbol)| symbol.recursive_for_each_mut(id, f));
222 }
223
224 pub(super) fn find_file(&self, hash: u64) -> Option<Symbol> {
225 if self.source_hash() == hash && self.is_source() {
226 Some(self.clone())
227 } else {
228 self.inner.borrow().children.find_file(hash)
229 }
230 }
231}
232
233impl Symbol {
235 pub(super) fn visibility(&self) -> Visibility {
237 self.visibility.borrow().clone()
238 }
239
240 pub(super) fn is_public(&self) -> bool {
242 matches!(self.visibility(), Visibility::Public)
243 }
244
245 pub(super) fn is_deleted(&self) -> bool {
246 matches!(self.visibility(), Visibility::Deleted)
247 }
248
249 pub(super) fn delete(&self) {
250 self.visibility.replace(Visibility::Deleted);
251 }
252
253 pub(crate) fn clone_with(&self, visibility: Visibility, src_ref: SrcRef) -> Self {
255 Self {
256 visibility: std::cell::RefCell::new(visibility),
257 src_ref,
258 inner: self.inner.clone(),
259 }
260 }
261
262 pub(crate) fn reset_visibility(&self) {
263 self.visibility
264 .replace(self.with_def(|def| def.visibility()));
265 }
266}
267
268impl Symbol {
270 pub(crate) fn id(&self) -> Identifier {
272 self.inner.borrow().def.id()
273 }
274
275 pub(super) fn can_const(&self) -> bool {
277 matches!(
278 self.inner.borrow().def,
279 SymbolDef::Module(..) | SymbolDef::SourceFile(..) | SymbolDef::Workbench(..)
280 )
281 }
282
283 pub(super) fn can_value(&self) -> bool {
285 matches!(
286 self.inner.borrow().def,
287 SymbolDef::Function(..) | SymbolDef::Workbench(..) | SymbolDef::SourceFile(..)
288 )
289 }
290
291 pub(super) fn can_prop(&self) -> bool {
293 matches!(self.inner.borrow().def, SymbolDef::Workbench(..))
294 }
295
296 pub(crate) fn is_source(&self) -> bool {
297 matches!(self.inner.borrow().def, SymbolDef::SourceFile(..))
298 }
299
300 pub(crate) fn is_module(&self) -> bool {
301 matches!(
302 self.inner.borrow().def,
303 SymbolDef::SourceFile(..) | SymbolDef::Module(..)
304 )
305 }
306
307 pub(crate) fn is_workbench(&self) -> bool {
308 matches!(self.inner.borrow().def, SymbolDef::Workbench(..))
309 }
310
311 pub(crate) fn set_value(&self, new_value: Value) -> ResolveResult<()> {
313 let is_a_value = match &mut self.inner.borrow_mut().def {
314 SymbolDef::Constant(.., value) => {
315 *value = new_value;
316 true
317 }
318 _ => false,
319 };
320 match is_a_value {
321 true => Ok(()),
322 false => Err(ResolveError::NotAValue(self.full_name())),
323 }
324 }
325
326 pub(super) fn source_path(&self) -> Option<std::path::PathBuf> {
328 if let SymbolDef::SourceFile(source_file) = &self.inner.borrow().def {
329 return source_file
330 .filename()
331 .parent()
332 .map(|path| path.to_path_buf());
333 }
334 self.get_parent().and_then(|parent| parent.source_path())
335 }
336
337 pub(super) fn is_resolvable(&self) -> bool {
338 matches!(
339 self.inner.borrow().def,
340 SymbolDef::SourceFile(..)
341 | SymbolDef::Module(..)
342 | SymbolDef::Workbench(..)
343 | SymbolDef::UseAll(..)
344 | SymbolDef::Alias(..)
345 ) && !self.is_deleted()
346 }
347
348 pub(super) fn is_link(&self) -> bool {
349 matches!(
350 self.inner.borrow().def,
351 SymbolDef::UseAll(..) | SymbolDef::Alias(..)
352 )
353 }
354
355 pub(super) fn is_alias(&self) -> bool {
356 matches!(self.inner.borrow().def, SymbolDef::Alias(..))
357 }
358
359 pub(super) fn get_link(&self) -> Option<QualifiedName> {
360 self.with_def(|def| match def {
361 SymbolDef::UseAll(_, name) | SymbolDef::Alias(.., name) => Some(name.clone()),
362 _ => None,
363 })
364 }
365
366 pub(super) fn has_links(&self) -> bool {
367 if self.is_link() {
368 true
369 } else {
370 self.inner
371 .borrow()
372 .children
373 .values()
374 .filter(|symbol| !symbol.is_deleted())
375 .any(|symbol| symbol.has_links())
376 }
377 }
378
379 pub(crate) fn with_def<T>(&self, mut f: impl FnMut(&SymbolDef) -> T) -> T {
381 f(&self.inner.borrow().def)
382 }
383
384 pub(crate) fn with_def_mut<T>(&self, mut f: impl FnMut(&mut SymbolDef) -> T) -> T {
386 f(&mut self.inner.borrow_mut().def)
387 }
388}
389
390impl Symbol {
392 pub(super) fn set_check(&self) {
394 let _ = self.inner.borrow().checked.set(());
395 }
396
397 pub(super) fn is_checked(&self) -> bool {
398 self.inner.borrow().checked.get().is_some()
399 }
400
401 pub(super) fn check(
403 &self,
404 context: &mut ResolveContext,
405 exclude_ids: &IdentifierSet,
406 ) -> ResolveResult<()> {
407 if !matches!(self.visibility.take(), Visibility::Deleted) {
408 let names = match &self.inner.borrow().def {
410 SymbolDef::SourceFile(sf) => sf.names(),
411 SymbolDef::Module(m) => m.names(),
412 SymbolDef::Workbench(wb) => wb.names(),
413 SymbolDef::Function(f) => f.names(),
414 SymbolDef::Assignment(a) => a.names(),
415 SymbolDef::Alias(..) | SymbolDef::UseAll(..) => {
416 log::error!("Resolve Context:\n{context:?}");
417 return Err(ResolveError::ResolveCheckFailed);
418 }
419 _ => Default::default(),
420 };
421
422 if !names.is_empty() {
423 log::debug!("checking symbols:\n{names:?}");
424 names
426 .iter()
427 .filter(|name| {
428 exclude_ids.contains(name.last().expect("symbol with empty name"))
429 })
430 .try_for_each(|name| {
432 match context.symbol_table.lookup(name, LookupTarget::Any) {
433 Ok(_) => Ok::<_, ResolveError>(()),
434 Err(err) => {
435 let module =
437 match context.symbol_table.search(&self.module_name(), false) {
438 Ok(module) => module,
439 Err(err) => {
440 context.error(&self.id(), err)?;
441 return Ok(());
442 }
443 };
444 if context
446 .symbol_table
447 .lookup_within(name, &module, LookupTarget::Module)
448 .is_err()
449 {
450 context.error(name, err)?;
451 }
452 Ok(())
453 }
454 }
455 })?;
456 }
457
458 let children = self.inner.borrow().children.clone();
460 children
461 .values()
462 .try_for_each(|symbol| symbol.check(context, exclude_ids))
463 } else {
464 Ok(())
465 }
466 }
467
468 fn module_name(&self) -> QualifiedName {
469 match self.is_module() {
470 true => {
471 if let Some(parent) = &self.get_parent() {
472 parent.module_name().with_suffix(&self.id())
473 } else {
474 QualifiedName::from_id(self.id())
475 }
476 }
477 false => {
478 if let Some(parent) = &self.get_parent() {
479 parent.module_name()
480 } else {
481 unreachable!("root must be source file")
482 }
483 }
484 }
485 }
486
487 pub(crate) fn kind_str(&self) -> String {
488 self.inner.borrow().def.kind_str()
489 }
490
491 pub(super) fn source_hash(&self) -> u64 {
492 self.inner.borrow().def.source_hash()
493 }
494}
495
496impl Symbol {
497 pub(crate) fn is_used(&self) -> bool {
498 self.inner.borrow().used.get().is_some()
499 }
500
501 pub(crate) fn set_used(&self) {
503 let _ = self.inner.borrow().used.set(());
504 }
505
506 pub(crate) fn is_unused_private(&self) -> bool {
507 !self.is_used() && !self.is_public() && !self.is_deleted()
508 }
509
510 pub(crate) fn in_module(&self) -> Option<QualifiedName> {
511 if let Visibility::PrivateUse(module) = self.visibility() {
512 Some(module.clone())
513 } else {
514 None
515 }
516 }
517
518 pub(super) fn resolve(&self, context: &mut ResolveContext) -> ResolveResult<SymbolMap> {
520 log::trace!("resolving: {self}");
521
522 let mut from_self = {
524 let inner = self.inner.borrow();
525 match &inner.def {
526 SymbolDef::Alias(visibility, id, name) => {
527 log::trace!("resolving use (as): {self} => {visibility}{id} ({name})");
528 let symbol = context
529 .symbol_table
530 .lookup_within_opt(name, &inner.parent, LookupTarget::Any)?
531 .clone_with(visibility.clone(), name.src_ref.clone());
532 self.delete();
533 [(id.clone(), symbol)].into_iter().collect()
534 }
535 SymbolDef::UseAll(visibility, name) => {
536 let visibility = &if matches!(visibility, &Visibility::Private) {
537 Visibility::PrivateUse(name.clone())
538 } else {
539 visibility.clone()
540 };
541 log::trace!("resolving use all: {self} => {visibility}{name}");
542 let symbols = context
543 .symbol_table
544 .lookup_within_opt(name, &inner.parent, LookupTarget::Any)?
545 .public_children(visibility.clone(), name.src_ref.clone());
546 if !symbols.is_empty() {
547 self.delete();
548 }
549 symbols
550 }
551 _ => SymbolMap::default(),
553 }
554 };
555
556 let resolved = from_self.resolve_all(context)?;
557 from_self.extend(resolved.iter().map(|(k, v)| (k.clone(), v.clone())));
558 let from_children = self.inner.borrow().children.resolve_all(context)?;
560 self.inner
561 .borrow_mut()
562 .children
563 .extend(from_children.iter().map(|(k, v)| (k.clone(), v.clone())));
564 Ok(from_self)
566 }
567
568 pub(crate) fn is_target_mode(&self) -> bool {
572 self.with_def(|def| match def {
573 SymbolDef::Builtin(builtin) => builtin
574 .parameters
575 .values()
576 .any(|param| param.ty() == Type::Target),
577 _ => false,
578 })
579 }
580
581 pub(crate) fn search(&self, name: &QualifiedName, respect: bool) -> ResolveResult<Symbol> {
585 log::trace!("Searching {name} in {:?}", self.full_name());
586 if let Some(id) = name.first() {
587 if id.is_super() {
588 if let Some(parent) = self.get_parent() {
589 return parent.search(&name[1..].iter().cloned().collect(), respect);
590 }
591 }
592 }
593 self.search_inner(name, true, respect)
594 }
595
596 fn search_inner(
597 &self,
598 name: &QualifiedName,
599 top_level: bool,
600 respect: bool,
601 ) -> ResolveResult<Symbol> {
602 if let Some(first) = name.first() {
603 if let Some(child) = self.get_child(first) {
604 if respect && !top_level && !child.is_public() {
605 log::trace!("Symbol {:?} is private", child.full_name());
606 Err(ResolveError::SymbolIsPrivate(child.full_name().clone()))
607 } else if name.is_single_identifier() && !child.is_deleted() {
608 log::trace!("Found {name:?} in {:?}", self.full_name());
609 self.set_used();
610 Ok(child.clone())
611 } else {
612 let name = &name.remove_first();
613 child.search_inner(name, false, respect)
614 }
615 } else {
616 log::trace!("No child in {:?} while searching for {name:?}", self.id());
617 Err(ResolveError::SymbolNotFound(name.clone()))
618 }
619 } else {
620 log::warn!("Cannot search for an anonymous name");
621 Err(ResolveError::SymbolNotFound(name.clone()))
622 }
623 }
624
625 pub(super) fn print_symbol(
631 &self,
632 f: &mut impl std::fmt::Write,
633 id: Option<&Identifier>,
634 depth: usize,
635 debug: bool,
636 children: bool,
637 ) -> std::fmt::Result {
638 let self_id = &self.id();
639 let id = id.unwrap_or(self_id);
640 let def = &self.inner.borrow().def;
641 let full_name = self.full_name();
642 let visibility = self.visibility();
643 let hash = self.source_hash();
644 if debug && cfg!(feature = "ansi-color") {
645 let checked = if self.is_checked() { " ✓" } else { "" };
646 if self.is_used() {
647 write!(
648 f,
649 "{:depth$}{visibility:?}{id:?} {def:?} [{full_name:?}] #{hash:#x}{checked}",
650 "",
651 )?;
652 } else {
653 color_print::cwrite!(
654 f,
655 "{:depth$}<#606060>{visibility:?}{id:?} {def:?} [{full_name:?}] #{hash:#x}</>{checked}",
656 "",
657 )?;
658 }
659 } else {
660 write!(f, "{:depth$}{id} {def} [{full_name}]", "",)?;
661 }
662 if children {
663 writeln!(f)?;
664 let indent = 4;
665
666 self.try_children(|(id, child)| {
667 child.print_symbol(f, Some(id), depth + indent, debug, true)
668 })?;
669 }
670 Ok(())
671 }
672
673 pub(super) fn set_src_ref(&mut self, src_ref: SrcRef) {
674 self.src_ref = src_ref;
675 }
676}
677
678impl FullyQualify for Symbol {
679 fn full_name(&self) -> QualifiedName {
681 let id = self.id();
682 match &self.get_parent() {
683 Some(parent) => {
684 let mut name = parent.full_name();
685 name.push(id);
686 name
687 }
688
689 None => {
690 let src_ref = id.src_ref();
691 QualifiedName::new(vec![id], src_ref)
692 }
693 }
694 }
695}
696
697impl SrcReferrer for Symbol {
698 fn src_ref(&self) -> SrcRef {
699 if self.src_ref.is_none() {
700 self.inner.borrow().src_ref()
701 } else {
702 self.src_ref.clone()
703 }
704 }
705}
706
707impl Default for Symbol {
708 fn default() -> Self {
709 Self {
710 src_ref: SrcRef(None),
711 visibility: std::cell::RefCell::new(Visibility::default()),
712 inner: RcMut::new(Default::default()),
713 }
714 }
715}
716
717impl PartialEq for Symbol {
718 fn eq(&self, other: &Self) -> bool {
719 self.inner.as_ptr() == other.inner.as_ptr()
721 }
722}
723
724impl std::fmt::Display for Symbol {
725 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
726 self.print_symbol(f, None, 0, false, false)
727 }
728}
729
730impl std::fmt::Debug for Symbol {
731 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
732 self.print_symbol(f, None, 0, true, false)
733 }
734}
735
736impl Info for Symbol {
737 fn info(&self) -> SymbolInfo {
738 self.with_def(|def| def.info())
739 }
740}
741
742#[test]
743fn test_symbol_resolve() {
744 let root = SourceFile::load_from_str(
745 Some("root"),
746 "",
747 "
748 use my;
749 x = my::target;
750
751 use my::target;
752 x = target;
753 ",
754 )
755 .expect("parse error");
756
757 let my = SourceFile::load_from_str(
758 Some("my"),
759 "",
760 "
761 pub const target = 1;
762 ",
763 )
764 .expect("parse error");
765
766 let mut context =
767 ResolveContext::test_create(root, ResolveMode::Symbolized).expect("resolve error");
768 context.test_add_file(my);
769 log::trace!("{context:?}");
770 context.resolve().expect("resolve error");
771}