microcad_lang/resolve/symbol/
mod.rs1mod symbol_definition;
5mod symbol_inner;
6mod symbol_map;
7mod symbols;
8
9pub use symbol_definition::*;
10pub(crate) use symbol_map::*;
11pub(crate) use symbols::*;
12
13use symbol_inner::*;
14
15use crate::{builtin::*, rc::*, resolve::*, src_ref::*, syntax::*, ty::*, value::*};
16
17#[derive(Clone)]
25pub struct Symbol {
26 visibility: std::cell::Cell<Visibility>,
27 inner: RcMut<SymbolInner>,
28}
29
30impl Symbol {
32 pub fn new(def: SymbolDefinition, parent: Option<Symbol>) -> Self {
38 Symbol {
39 visibility: std::cell::Cell::new(def.visibility()),
40 inner: RcMut::new(SymbolInner {
41 def,
42 parent,
43 ..Default::default()
44 }),
45 }
46 }
47
48 pub(super) fn new_with_visibility(
54 visibility: Visibility,
55 def: SymbolDefinition,
56 parent: Option<Symbol>,
57 ) -> Self {
58 Symbol {
59 visibility: std::cell::Cell::new(visibility),
60 inner: RcMut::new(SymbolInner {
61 def,
62 parent,
63 ..Default::default()
64 }),
65 }
66 }
67
68 pub fn new_builtin(
74 id: Identifier,
75 parameters: Option<ParameterValueList>,
76 f: &'static BuiltinFn,
77 ) -> Symbol {
78 Symbol::new(
79 SymbolDefinition::Builtin(Rc::new(Builtin { id, parameters, f })),
80 None,
81 )
82 }
83}
84
85impl Symbol {
87 fn get_child(&self, id: &Identifier) -> Option<Symbol> {
91 self.inner.borrow().children.get(id).cloned()
92 }
93
94 pub(crate) fn add_child(parent: &Symbol, child: Symbol) {
99 child.inner.borrow_mut().parent = Some(parent.clone());
100 let id = child.id();
101 parent.inner.borrow_mut().children.insert(id, child);
102 }
103
104 pub(crate) fn insert_child(&self, id: Identifier, new_child: Symbol) {
108 if self
109 .inner
110 .borrow_mut()
111 .children
112 .insert(id, new_child)
113 .is_some()
114 {
115 todo!("symbol already existing");
116 }
117 }
118
119 pub(super) fn set_children(&self, new_children: SymbolMap) {
123 assert!(self.inner.borrow().children.is_empty());
124 self.inner.borrow_mut().children = new_children;
125 }
126
127 pub(crate) fn with_children<E: std::error::Error>(
128 &self,
129 f: impl FnMut((&Identifier, &Symbol)) -> Result<(), E>,
130 ) -> Result<(), E> {
131 self.inner.borrow().children.iter().try_for_each(f)
132 }
133
134 fn public_children(&self, visibility: Visibility) -> SymbolMap {
136 let inner = self.inner.borrow();
137
138 inner
139 .children
140 .values()
141 .filter(|symbol| {
142 if symbol.is_public() {
143 true
144 } else {
145 log::trace!("Skipping private symbol:\n{symbol:?}");
146 false
147 }
148 })
149 .map(|symbol| symbol.clone_with_visibility(visibility))
150 .map(|symbol| (symbol.id(), symbol))
151 .collect()
152 }
153
154 pub(crate) fn is_empty(&self) -> bool {
156 self.inner.borrow().children.is_empty()
157 }
158
159 pub(crate) fn get_parent(&self) -> Option<Symbol> {
161 self.inner.borrow().parent.clone()
162 }
163
164 pub(super) fn set_parent(&mut self, parent: Symbol) {
166 self.inner.borrow_mut().parent = Some(parent);
167 }
168}
169
170impl Symbol {
172 fn visibility(&self) -> Visibility {
174 self.visibility.get()
175 }
176
177 pub(crate) fn set_visibility(&mut self, visibility: Visibility) {
179 self.visibility.set(visibility)
180 }
181
182 fn is_public(&self) -> bool {
184 matches!(self.visibility(), Visibility::Public)
185 }
186
187 pub(super) fn is_deleted(&self) -> bool {
188 self.visibility.get() == Visibility::Deleted
189 }
190
191 pub(crate) fn clone_with_visibility(&self, visibility: Visibility) -> Self {
193 let cloned = self.clone();
194 cloned.visibility.set(visibility);
195 cloned
196 }
197}
198
199impl Symbol {
201 pub(crate) fn id(&self) -> Identifier {
203 self.inner.borrow().def.id()
204 }
205
206 pub(super) fn can_const(&self) -> bool {
208 matches!(
209 self.inner.borrow().def,
210 SymbolDefinition::Module(..) | SymbolDefinition::SourceFile(..)
211 )
212 }
213
214 pub(super) fn can_value(&self) -> bool {
216 matches!(
217 self.inner.borrow().def,
218 SymbolDefinition::Function(..)
219 | SymbolDefinition::Workbench(..)
220 | SymbolDefinition::SourceFile(..)
221 )
222 }
223
224 pub(super) fn can_prop(&self) -> bool {
226 matches!(self.inner.borrow().def, SymbolDefinition::Workbench(..))
227 }
228
229 pub(crate) fn is_module(&self) -> bool {
230 matches!(
231 self.inner.borrow().def,
232 SymbolDefinition::SourceFile(..) | SymbolDefinition::Module(..)
233 )
234 }
235
236 pub(crate) fn is_workbench(&self) -> bool {
237 matches!(self.inner.borrow().def, SymbolDefinition::Workbench(..))
238 }
239
240 pub(crate) fn set_value(&self, new_value: Value) -> ResolveResult<()> {
242 let is_a_value = match &mut self.inner.borrow_mut().def {
243 SymbolDefinition::Constant(.., value) => {
244 *value = new_value;
245 true
246 }
247 _ => false,
248 };
249 match is_a_value {
250 true => Ok(()),
251 false => Err(ResolveError::NotAValue(self.full_name())),
252 }
253 }
254
255 pub(super) fn source_path(&self) -> Option<std::path::PathBuf> {
257 if let SymbolDefinition::SourceFile(source_file) = &self.inner.borrow().def {
258 return source_file
259 .filename()
260 .parent()
261 .map(|path| path.to_path_buf());
262 }
263 self.get_parent().and_then(|parent| parent.source_path())
264 }
265
266 pub(super) fn is_resolvable(&self) -> bool {
267 matches!(
268 self.inner.borrow().def,
269 SymbolDefinition::SourceFile(..)
270 | SymbolDefinition::Module(..)
271 | SymbolDefinition::UseAll(..)
272 | SymbolDefinition::Alias(..)
273 ) && !self.is_deleted()
274 }
275
276 pub(super) fn is_link(&self) -> bool {
277 matches!(
278 self.inner.borrow().def,
279 SymbolDefinition::UseAll(..) | SymbolDefinition::Alias(..)
280 )
281 }
282
283 pub(super) fn is_alias(&self) -> bool {
284 matches!(self.inner.borrow().def, SymbolDefinition::Alias(..))
285 }
286
287 pub(super) fn has_links(&self) -> bool {
288 if self.is_link() {
289 true
290 } else {
291 self.inner
292 .borrow()
293 .children
294 .values()
295 .filter(|symbol| !symbol.is_deleted())
296 .any(|symbol| symbol.has_links())
297 }
298 }
299
300 pub(crate) fn with_def<T>(&self, mut f: impl FnMut(&SymbolDefinition) -> T) -> T {
302 f(&self.inner.borrow().def)
303 }
304
305 pub(crate) fn with_def_mut<T>(&self, mut f: impl FnMut(&mut SymbolDefinition) -> T) -> T {
307 f(&mut self.inner.borrow_mut().def)
308 }
309}
310
311impl Symbol {
313 pub(super) fn set_check(&self) {
315 let _ = self.inner.borrow().checked.set(());
316 }
317
318 fn is_checked(&self) -> bool {
319 self.inner.borrow().checked.get().is_some()
320 }
321
322 pub(super) fn unchecked(&self, unchecked: &mut Symbols) {
323 let inner = self.inner.borrow();
324 if inner.checked.get().is_none() {
325 unchecked.push(self.clone())
326 }
327 inner
328 .children
329 .iter()
330 .for_each(|(_, child)| child.unchecked(unchecked));
331 }
332
333 pub(super) fn check(
335 &self,
336 context: &mut ResolveContext,
337 exclude_ids: &IdentifierSet,
338 ) -> ResolveResult<()> {
339 if !matches!(self.visibility.get(), Visibility::Deleted) {
340 let names = match &self.inner.borrow().def {
342 SymbolDefinition::SourceFile(sf) => sf.names(),
343 SymbolDefinition::Module(m) => m.names(),
344 SymbolDefinition::Workbench(wb) => wb.names(),
345 SymbolDefinition::Function(f) => f.names(),
346 SymbolDefinition::ConstExpression(.., ce) => ce.names(),
347 SymbolDefinition::Alias(..) | SymbolDefinition::UseAll(..) => {
348 log::error!("Resolve Context:\n{context:?}");
349 return Err(ResolveError::ResolveCheckFailed);
350 }
351 _ => Default::default(),
352 };
353
354 if !names.is_empty() {
355 log::debug!("checking symbols:\n{names:?}");
356 names
358 .iter()
359 .filter(|name| {
360 exclude_ids.contains(name.last().expect("symbol with empty name"))
361 })
362 .try_for_each(|name| match context.symbol_table.lookup(name) {
364 Ok(_) => Ok::<_, ResolveError>(()),
365 Err(err) => {
366 let module =
368 match context.symbol_table.search(&self.module_name(), false) {
369 Ok(module) => module,
370 Err(err) => {
371 context.error(&self.id(), err)?;
372 return Ok(());
373 }
374 };
375 if context.symbol_table.lookup_within(name, &module).is_err() {
377 context.error(name, err)?;
378 }
379 Ok(())
380 }
381 })?;
382 }
383
384 let children = self.inner.borrow().children.clone();
386 children
387 .values()
388 .try_for_each(|symbol| symbol.check(context, exclude_ids))
389 } else {
390 Ok(())
391 }
392 }
393
394 fn module_name(&self) -> QualifiedName {
395 match self.is_module() {
396 true => {
397 if let Some(parent) = &self.get_parent() {
398 parent.module_name().with_suffix(&self.id())
399 } else {
400 QualifiedName::from_id(self.id())
401 }
402 }
403 false => {
404 if let Some(parent) = &self.get_parent() {
405 parent.module_name()
406 } else {
407 unreachable!("root must be source file")
408 }
409 }
410 }
411 }
412
413 pub(crate) fn kind(&self) -> String {
414 self.inner.borrow().def.kind()
415 }
416}
417
418impl Symbol {
419 pub(crate) fn set_used(&self) {
421 let _ = self.inner.borrow().used.set(());
422 }
423
424 pub(super) fn unused(&self, unused: &mut Symbols) {
425 let inner = self.inner.borrow();
426 if inner.used.get().is_none() {
427 unused.push(self.clone())
428 }
429
430 inner
431 .children
432 .iter()
433 .for_each(|(_, child)| child.unused(unused));
434 }
435
436 pub(super) fn resolve(&self, context: &mut ResolveContext) -> ResolveResult<SymbolMap> {
438 log::trace!("resolving: {self}");
439
440 let mut from_self = {
442 let inner = self.inner.borrow();
443 match &inner.def {
444 SymbolDefinition::Alias(visibility, id, name) => {
445 log::trace!("resolving use (as): {self} => {visibility}{id} ({name})");
446 let symbol = context
447 .symbol_table
448 .lookup_within_opt(name, &inner.parent)?
449 .clone_with_visibility(*visibility);
450 self.visibility.set(Visibility::Deleted);
451 [(id.clone(), symbol)].into_iter().collect()
452 }
453 SymbolDefinition::UseAll(visibility, name) => {
454 log::trace!("resolving use all: {self} => {visibility}{name}");
455 let symbols = context
456 .symbol_table
457 .lookup_within_opt(name, &inner.parent)?
458 .public_children(*visibility);
459 if !symbols.is_empty() {
460 self.visibility.set(Visibility::Deleted);
461 }
462 symbols
463 }
464 _ => SymbolMap::default(),
466 }
467 };
468
469 let resolved = from_self.resolve_all(context)?;
470 from_self.extend(resolved.iter().map(|(k, v)| (k.clone(), v.clone())));
471 let from_children = self.inner.borrow().children.resolve_all(context)?;
473 self.inner
474 .borrow_mut()
475 .children
476 .extend(from_children.iter().map(|(k, v)| (k.clone(), v.clone())));
477 Ok(from_self)
479 }
480
481 pub(crate) fn is_target_mode(&self) -> bool {
485 self.with_def(|def| match def {
486 SymbolDefinition::Builtin(builtin) => {
487 if let Some(parameters) = &builtin.parameters {
488 parameters.values().any(|param| param.ty() == Type::Target)
489 } else {
490 false
491 }
492 }
493 _ => false,
494 })
495 }
496
497 pub(super) fn search_target_mode_ids(&self, ids: &mut IdentifierSet) -> ResolveResult<()> {
498 if self.is_target_mode() {
499 ids.insert(self.id());
500 }
501 self.with_children(|(_, child)| child.search_target_mode_ids(ids))
502 }
503
504 pub(crate) fn search(&self, name: &QualifiedName, respect: bool) -> ResolveResult<Symbol> {
508 log::trace!("Searching {name} in {:?}", self.full_name());
509 if let Some(id) = name.first() {
510 if id.is_super() {
511 if let Some(parent) = self.get_parent() {
512 return parent.search(&name[1..].iter().cloned().collect(), respect);
513 }
514 }
515 }
516 self.search_inner(name, true, respect)
517 }
518
519 fn search_inner(
520 &self,
521 name: &QualifiedName,
522 top_level: bool,
523 respect: bool,
524 ) -> ResolveResult<Symbol> {
525 if let Some(first) = name.first() {
526 if let Some(child) = self.get_child(first) {
527 if respect && !top_level && !child.is_public() {
528 log::trace!("Symbol {:?} is private", child.full_name());
529 Err(ResolveError::SymbolIsPrivate(child.full_name().clone()))
530 } else if name.is_single_identifier() && !child.is_deleted() {
531 log::trace!("Found {name:?} in {:?}", self.full_name());
532 Ok(child.clone())
533 } else {
534 let name = &name.remove_first();
535 child.search_inner(name, false, respect)
536 }
537 } else {
538 log::trace!("No child in {:?} while searching for {name:?}", self.id());
539 Err(ResolveError::SymbolNotFound(name.clone()))
540 }
541 } else {
542 log::warn!("Cannot search for an anonymous name");
543 Err(ResolveError::SymbolNotFound(name.clone()))
544 }
545 }
546
547 pub(super) fn print_symbol(
553 &self,
554 f: &mut impl std::fmt::Write,
555 id: Option<&Identifier>,
556 depth: usize,
557 debug: bool,
558 children: bool,
559 ) -> std::fmt::Result {
560 let self_id = &self.id();
561 let id = id.unwrap_or(self_id);
562 let def = &self.inner.borrow().def;
563 let full_name = self.full_name();
564 let visibility = self.visibility();
565 if debug && cfg!(feature = "ansi-color") && self.inner.borrow().used.get().is_none() {
566 let checked = if self.is_checked() { " ✓" } else { "" };
567 color_print::cwrite!(
568 f,
569 "{:depth$}<#606060>{visibility:?}{id:?} {def:?} [{full_name:?}]</>{checked}",
570 "",
571 )?;
572 } else {
573 write!(f, "{:depth$}{id} {def} [{full_name}]", "",)?;
574 }
575 if children {
576 writeln!(f)?;
577 let indent = 4;
578
579 self.with_children(|(id, child)| {
580 child.print_symbol(f, Some(id), depth + indent, debug, true)
581 })?;
582 }
583 Ok(())
584 }
585}
586
587impl FullyQualify for Symbol {
588 fn full_name(&self) -> QualifiedName {
590 let id = self.id();
591 match &self.get_parent() {
592 Some(parent) => {
593 let mut name = parent.full_name();
594 name.push(id);
595 name
596 }
597
598 None => {
599 let src_ref = id.src_ref();
600 QualifiedName::new(vec![id], src_ref)
601 }
602 }
603 }
604}
605
606impl Default for Symbol {
607 fn default() -> Self {
608 Self {
609 visibility: std::cell::Cell::new(Visibility::default()),
610 inner: RcMut::new(Default::default()),
611 }
612 }
613}
614
615impl PartialEq for Symbol {
616 fn eq(&self, other: &Self) -> bool {
617 self.inner.as_ptr() == other.inner.as_ptr()
619 }
620}
621
622impl std::fmt::Display for Symbol {
623 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
624 self.print_symbol(f, None, 0, false, false)
625 }
626}
627
628impl std::fmt::Debug for Symbol {
629 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
630 self.print_symbol(f, None, 0, true, false)
631 }
632}
633
634#[test]
635fn test_symbol_resolve() {
636 let root = SourceFile::load_from_str(
637 "root",
638 "
639 use my;
640 x = my::target;
641
642 use my::target;
643 x = target;
644 ",
645 )
646 .expect("parse error");
647
648 let my = SourceFile::load_from_str(
649 "my",
650 "
651 pub const target = 1;
652 ",
653 )
654 .expect("parse error");
655
656 let mut context =
657 ResolveContext::test_create(root, ResolveMode::Symbolized).expect("resolve error");
658 context.test_add_file(my);
659 log::trace!("{context:?}");
660 context.resolve().expect("resolve error");
661}