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::Root => unreachable!("<ROOT> cannot be matched"),
32 SymbolDef::SourceFile(..) | SymbolDef::Module(..) => {
33 matches!(self, Self::Any | Self::AnyButMethod | Self::Module)
34 }
35 SymbolDef::Workbench(wd) => match *wd.kind {
36 WorkbenchKind::Part | WorkbenchKind::Sketch => {
37 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
38 }
39 WorkbenchKind::Operation => matches!(self, Self::Any | Self::Method),
40 },
41 SymbolDef::Function(..) => {
42 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
43 }
44 SymbolDef::Builtin(b) => match &b.kind {
45 crate::builtin::BuiltinKind::Function => {
46 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
47 }
48 crate::builtin::BuiltinKind::Workbench(bwk) => match bwk {
49 crate::builtin::BuiltinWorkbenchKind::Primitive2D
50 | crate::builtin::BuiltinWorkbenchKind::Primitive3D => {
51 matches!(self, Self::Any | Self::AnyButMethod | Self::Function)
52 }
53 crate::builtin::BuiltinWorkbenchKind::Transform
54 | crate::builtin::BuiltinWorkbenchKind::Operation => {
55 matches!(self, Self::Any | Self::Method)
56 }
57 },
58 },
59 SymbolDef::Constant(..) | SymbolDef::Assignment(..) | SymbolDef::Argument(..) => {
60 matches!(self, Self::Any | Self::AnyButMethod | Self::Value)
61 }
62 SymbolDef::Alias(..) | SymbolDef::UseAll(..) => {
63 matches!(self, Self::Any | Self::AnyButMethod | Self::Link)
64 }
65 #[cfg(test)]
66 SymbolDef::Tester(..) => todo!(),
67 }
68 })
69 }
70}
71
72impl std::fmt::Display for LookupTarget {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 LookupTarget::Any => write!(f, "any symbol"),
76 LookupTarget::AnyButMethod => write!(f, "any symbol but a method"),
77 LookupTarget::Method => write!(f, "method"),
78 LookupTarget::Function => write!(f, "function"),
79 LookupTarget::Module => write!(f, "module"),
80 LookupTarget::Value => write!(f, "value"),
81 LookupTarget::Link => write!(f, "link"),
82 }
83 }
84}
85
86pub trait Lookup<E: std::error::Error = ResolveError> {
88 fn lookup(&self, name: &QualifiedName, target: LookupTarget) -> Result<Symbol, E>;
93
94 fn ambiguity_error(ambiguous: QualifiedName, others: QualifiedNames) -> E;
96
97 fn lookup_within(
106 &self,
107 name: &QualifiedName,
108 within: &Symbol,
109 target: LookupTarget,
110 ) -> Result<Symbol, E> {
111 log::trace!(
112 "{lookup} for symbol '{name:?}' within '{within}'",
113 within = within.full_name(),
114 lookup = crate::mark!(LOOKUP)
115 );
116 match (self.lookup(name, target), within.search(name, true)) {
117 (Ok(global), Ok(relative)) => {
119 match (global.is_alias(), relative.is_alias()) {
121 (true, false) => Ok(relative),
122 (false, true) => Ok(global),
123 (true, true) => unreachable!("found two aliases"),
124 (false, false) => {
125 if relative == global {
126 Ok(global)
127 } else {
128 Err(Self::ambiguity_error(
129 relative.full_name(),
130 [global.full_name()].into_iter().collect(),
131 ))
132 }
133 }
134 }
135 }
136 (Ok(symbol), Err(_)) | (Err(_), Ok(symbol)) => {
138 log::trace!(
139 "{found} symbol '{name:?}' within '{within}'",
140 within = within.full_name(),
141 found = crate::mark!(FOUND)
142 );
143 Ok(symbol)
144 }
145 (Err(err), Err(_)) => {
147 log::trace!(
148 "{not_found} symbol '{name:?}' within '{within}'",
149 within = within.full_name(),
150 not_found = crate::mark!(NOT_FOUND)
151 );
152 Err(err)
153 }
154 }
155 }
156
157 fn lookup_within_opt(
166 &self,
167 name: &QualifiedName,
168 within: &Option<Symbol>,
169 target: LookupTarget,
170 ) -> Result<Symbol, E> {
171 if let Some(within) = within {
172 self.lookup_within(name, within, target)
173 } else {
174 self.lookup(name, target)
175 }
176 }
177
178 fn deny_super(&self, name: &QualifiedName) -> ResolveResult<()> {
180 if name.count_super() > 0 {
181 log::trace!(
182 "{not_found} '{name:?}' is not canonical",
183 not_found = crate::mark!(NOT_FOUND),
184 );
185 return Err(ResolveError::SymbolNotFound(name.clone()));
186 }
187 Ok(())
188 }
189}