microcad_lang/resolve/
symbol_table.rs1use derive_more::{Deref, DerefMut};
5use indexmap::IndexSet;
6
7use crate::{resolve::*, syntax::*};
8
9#[derive(Default, Deref, DerefMut)]
11pub struct SymbolTable(SymbolMap);
12
13impl SymbolTable {
14 pub fn add_symbol(&mut self, symbol: Symbol) -> ResolveResult<()> {
16 self.insert_symbol(symbol.id(), symbol.clone())
17 }
18
19 pub fn insert_symbol(&mut self, id: Identifier, symbol: Symbol) -> ResolveResult<()> {
21 log::trace!("insert symbol: {id}");
22 if let Some(symbol) = self.insert(id, symbol.clone()) {
23 Err(ResolveError::SymbolAlreadyDefined(symbol.full_name()))
24 } else {
25 Ok(())
26 }
27 }
28
29 pub(super) fn symbols(&self) -> Symbols {
30 self.values().cloned().collect()
31 }
32
33 pub fn unchecked(&self) -> Symbols {
35 self.recursive_collect(|symbol| symbol.is_checked())
36 }
37
38 pub fn unused_private(&self) -> Symbols {
42 let used_in_module = &mut IndexSet::new();
43 let mut symbols = self.recursive_collect(|symbol| {
44 if let Some(in_module) = symbol.in_module()
45 && symbol.is_used()
46 {
47 used_in_module.insert(in_module);
48 }
49 symbol.is_unused_private()
50 });
51
52 symbols.retain(|symbol| {
53 if let Some(in_module) = symbol.in_module() {
54 !used_in_module.contains(&in_module)
55 } else {
56 true
57 }
58 });
59 symbols.sort_by_key(|s| s.full_name());
60 symbols
61 }
62
63 pub(super) fn search_target_mode_ids(&self) -> IdentifierSet {
65 self.recursive_collect(|symbol| symbol.is_target_mode())
66 .iter()
67 .map(|symbol| symbol.id())
68 .collect()
69 }
70
71 pub(super) fn recursive_collect<F>(&self, mut f: F) -> Symbols
72 where
73 F: FnMut(&Symbol) -> bool,
74 {
75 let mut result = vec![];
76 self.values().for_each(|symbol| {
77 symbol.recursive_collect(&mut f, &mut result);
78 });
79 result.into()
80 }
81
82 #[allow(dead_code)]
83 pub(super) fn recursive_for_each<F>(&self, f: F)
84 where
85 F: Fn(&Identifier, &Symbol),
86 {
87 self.iter().for_each(|(id, symbol)| {
88 symbol.recursive_for_each(id, &f);
89 });
90 }
91
92 pub(super) fn recursive_for_each_mut<F>(&mut self, f: F)
93 where
94 F: Fn(&Identifier, &mut Symbol),
95 {
96 self.iter_mut().for_each(|(id, symbol)| {
97 symbol.recursive_for_each_mut(id, &f);
98 });
99 }
100
101 pub(crate) fn lookup_within_name(
109 &self,
110 name: &QualifiedName,
111 within: &QualifiedName,
112 target: LookupTarget,
113 ) -> ResolveResult<Symbol> {
114 self.lookup_within(name, &self.search(within, false)?, target)
115 }
116}
117
118impl WriteToFile for SymbolTable {}
119
120impl Lookup for SymbolTable {
121 fn lookup(&self, name: &QualifiedName, target: LookupTarget) -> ResolveResult<Symbol> {
123 log::trace!(
124 "{lookup} for global symbol '{name:?}'",
125 lookup = crate::mark!(LOOKUP)
126 );
127 self.deny_super(name)?;
128
129 let symbol = match self.search(name, true) {
130 Ok(symbol) => {
131 if target.matches(&symbol) {
132 symbol
133 } else {
134 log::trace!(
135 "{not_found} global symbol: {name:?}",
136 not_found = crate::mark!(NOT_FOUND_INTERIM),
137 );
138 return Err(ResolveError::WrongTarget);
139 }
140 }
141 Err(err) => {
142 log::trace!(
143 "{not_found} global symbol: {name:?}",
144 not_found = crate::mark!(NOT_FOUND_INTERIM),
145 );
146 return Err(err)?;
147 }
148 };
149 symbol.set_check();
150 log::trace!(
151 "{found} global symbol: {symbol:?}",
152 found = crate::mark!(FOUND_INTERIM),
153 );
154 Ok(symbol)
155 }
156
157 fn ambiguity_error(ambiguous: QualifiedName, others: QualifiedNames) -> ResolveError {
158 ResolveError::AmbiguousSymbol(ambiguous, others)
159 }
160}
161
162impl std::fmt::Display for SymbolTable {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 writeln!(
165 f,
166 "{}",
167 self.iter()
168 .map(|(_, symbol)| symbol)
169 .filter(|symbol| !symbol.is_deleted())
170 .map(|symbol| symbol.full_name().to_string())
171 .collect::<Vec<_>>()
172 .join(", ")
173 )
174 }
175}
176
177impl std::fmt::Debug for SymbolTable {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 writeln!(f, "{:?}", self.0)
180 }
181}