microcad_lang/resolve/
lookup.rs1use crate::{resolve::*, syntax::*};
5
6#[derive(Clone, Copy)]
8pub enum LookupTarget {
9 Any,
11
12 AnyButMethod,
14
15 Method,
17 Function,
19 Module,
21 Value,
23 Link,
25}
26
27impl LookupTarget {
28 pub(crate) fn matches(&self, symbol: &Symbol) -> bool {
29 symbol.with_def(|def| -> bool {
30 match &def {
31 SymbolDef::SourceFile(..) | SymbolDef::Module(..) => {
32 matches!(self, Self::Any | Self::AnyButMethod | Self::Module)
33 }
34 SymbolDef::Workbench(wd) => match *wd.kind {
35 WorkbenchKind::Part | WorkbenchKind::Sketch => {
36 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
37 }
38 WorkbenchKind::Operation => matches!(self, Self::Any | Self::Method),
39 },
40 SymbolDef::Function(..) => {
41 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
42 }
43 SymbolDef::Builtin(b) => match &b.kind {
44 crate::builtin::BuiltinKind::Function => {
45 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
46 }
47 crate::builtin::BuiltinKind::Workbench(bwk) => match bwk {
48 crate::builtin::BuiltinWorkbenchKind::Primitive2D
49 | crate::builtin::BuiltinWorkbenchKind::Primitive3D => {
50 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
51 }
52 crate::builtin::BuiltinWorkbenchKind::Transform
53 | crate::builtin::BuiltinWorkbenchKind::Operation => {
54 matches!(self, Self::Any | Self::Method)
55 }
56 },
57 },
58 SymbolDef::Constant(..) | SymbolDef::Assignment(..) | SymbolDef::Argument(..) => {
59 matches!(self, Self::Any | Self::AnyButMethod | Self::Value)
60 }
61 SymbolDef::Alias(..) | SymbolDef::UseAll(..) => {
62 matches!(self, Self::Any | Self::AnyButMethod | Self::Link)
63 }
64 #[cfg(test)]
65 SymbolDef::Tester(..) => todo!(),
66 }
67 })
68 }
69}
70
71impl std::fmt::Display for LookupTarget {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 match self {
74 LookupTarget::Any => write!(f, "any symbol"),
75 LookupTarget::AnyButMethod => write!(f, "any symbol but a method"),
76 LookupTarget::Method => write!(f, "method"),
77 LookupTarget::Function => write!(f, "function"),
78 LookupTarget::Module => write!(f, "module"),
79 LookupTarget::Value => write!(f, "value"),
80 LookupTarget::Link => write!(f, "link"),
81 }
82 }
83}
84
85pub trait Lookup<E: std::error::Error = ResolveError> {
87 fn lookup(&self, name: &QualifiedName, target: LookupTarget) -> Result<Symbol, E>;
92
93 fn ambiguity_error(ambiguous: QualifiedName, others: QualifiedNames) -> E;
95
96 fn lookup_within(
105 &self,
106 name: &QualifiedName,
107 within: &Symbol,
108 target: LookupTarget,
109 ) -> Result<Symbol, E> {
110 log::trace!(
111 "{lookup} for symbol '{name:?}' within '{within}'",
112 within = within.full_name(),
113 lookup = crate::mark!(LOOKUP)
114 );
115 match (self.lookup(name, target), within.search(name, true)) {
116 (Ok(global), Ok(relative)) => {
118 match (global.is_alias(), relative.is_alias()) {
120 (true, false) => Ok(relative),
121 (false, true) => Ok(global),
122 (true, true) => unreachable!("found two aliases"),
123 (false, false) => {
124 if relative == global {
125 Ok(global)
126 } else {
127 Err(Self::ambiguity_error(
128 relative.full_name(),
129 [global.full_name()].into_iter().collect(),
130 ))
131 }
132 }
133 }
134 }
135 (Ok(symbol), Err(_)) | (Err(_), Ok(symbol)) => {
137 log::trace!(
138 "{found} symbol '{name:?}' within '{within}'",
139 within = within.full_name(),
140 found = crate::mark!(FOUND_INTERIM)
141 );
142 Ok(symbol)
143 }
144 (Err(err), Err(_)) => {
146 log::trace!(
147 "{not_found} symbol '{name:?}' within '{within}'",
148 within = within.full_name(),
149 not_found = crate::mark!(NOT_FOUND_INTERIM)
150 );
151 Err(err)
152 }
153 }
154 }
155
156 fn lookup_within_opt(
165 &self,
166 name: &QualifiedName,
167 within: &Option<Symbol>,
168 target: LookupTarget,
169 ) -> Result<Symbol, E> {
170 if let Some(within) = within {
171 self.lookup_within(name, within, target)
172 } else {
173 self.lookup(name, target)
174 }
175 }
176
177 fn deny_super(&self, name: &QualifiedName) -> ResolveResult<()> {
179 if name.count_super() > 0 {
180 log::trace!(
181 "{not_found} '{name:?}' is not canonical",
182 not_found = crate::mark!(NOT_FOUND_INTERIM),
183 );
184 return Err(ResolveError::SymbolNotFound(name.clone()));
185 }
186 Ok(())
187 }
188}