miden_assembly_syntax/ast/item/resolver/
mod.rs1mod error;
2mod symbol_table;
3
4use alloc::sync::Arc;
5
6use miden_debug_types::{SourceManager, SourceSpan, Span, Spanned};
7
8use self::symbol_table::LocalSymbolTable;
9pub use self::{
10 error::SymbolResolutionError,
11 symbol_table::{LocalSymbol, SymbolTable},
12};
13use super::{GlobalItemIndex, ModuleIndex};
14use crate::{
15 Path, Word,
16 ast::{AliasTarget, Ident, ItemIndex},
17};
18
19#[derive(Debug, Clone)]
21pub enum SymbolResolution {
22 Local(Span<ItemIndex>),
24 External(Span<Arc<Path>>),
26 MastRoot(Span<Word>),
28 Exact {
30 gid: GlobalItemIndex,
31 path: Span<Arc<Path>>,
32 },
33 Module { id: ModuleIndex, path: Span<Arc<Path>> },
35}
36
37impl SymbolResolution {
38 pub fn into_global_id(&self) -> Option<GlobalItemIndex> {
39 match self {
40 Self::Exact { gid, .. } => Some(*gid),
41 Self::Local(_) | Self::External(_) | Self::MastRoot(_) | Self::Module { .. } => None,
42 }
43 }
44}
45
46impl Spanned for SymbolResolution {
47 fn span(&self) -> SourceSpan {
48 match self {
49 Self::Local(p) => p.span(),
50 Self::External(p) => p.span(),
51 Self::MastRoot(p) => p.span(),
52 Self::Exact { path, .. } => path.span(),
53 Self::Module { path, .. } => path.span(),
54 }
55 }
56}
57
58pub struct LocalSymbolResolver {
68 source_manager: Arc<dyn SourceManager>,
69 symbols: LocalSymbolTable,
70}
71
72impl LocalSymbolResolver {
73 pub fn new<S>(
75 symbols: S,
76 source_manager: Arc<dyn SourceManager>,
77 ) -> Result<Self, SymbolResolutionError>
78 where
79 S: SymbolTable,
80 {
81 let symbols = LocalSymbolTable::new(symbols, source_manager.clone())?;
82 Ok(Self { source_manager, symbols })
83 }
84
85 #[inline]
90 pub fn expand<F>(
91 get_import: F,
92 path: Span<&Path>,
93 source_manager: &dyn SourceManager,
94 ) -> Result<SymbolResolution, SymbolResolutionError>
95 where
96 F: Fn(&str) -> Option<AliasTarget>,
97 {
98 LocalSymbolTable::expand(get_import, path, source_manager)
99 }
100
101 #[inline]
102 pub fn source_manager(&self) -> Arc<dyn SourceManager> {
103 self.source_manager.clone()
104 }
105
106 #[inline]
110 pub fn resolve(&self, name: Span<&str>) -> Result<SymbolResolution, SymbolResolutionError> {
111 self.symbols.get(name)
112 }
113
114 pub fn resolve_path(
116 &self,
117 path: Span<&Path>,
118 ) -> Result<SymbolResolution, SymbolResolutionError> {
119 if path.is_absolute() {
120 return Ok(SymbolResolution::External(path.map(Into::into)));
121 }
122 log::debug!(target: "local-symbol-resolver", "resolving path '{path}'");
123 let (ns, subpath) = path.split_first().expect("invalid item path");
124 log::debug!(target: "local-symbol-resolver", "resolving symbol '{ns}'");
125 match self.resolve(Span::new(path.span(), ns))? {
126 SymbolResolution::External(target) => {
127 log::debug!(target: "local-symbol-resolver", "resolved '{ns}' to import of '{target}'");
128 if subpath.is_empty() {
129 log::debug!(target: "local-symbol-resolver", "resolved '{path}' '{target}'");
130 Ok(SymbolResolution::External(target))
131 } else {
132 let resolved = target.join(subpath).into();
133 log::debug!(target: "local-symbol-resolver", "resolved '{path}' '{resolved}'");
134 Ok(SymbolResolution::External(Span::new(target.span(), resolved)))
135 }
136 },
137 SymbolResolution::Local(item) => {
138 log::debug!(target: "local-symbol-resolver", "resolved '{ns}' to local item '{item}'");
139 if subpath.is_empty() {
140 return Ok(SymbolResolution::Local(item));
141 }
142
143 log::error!(target: "local-symbol-resolver", "cannot resolve '{subpath}' relative to non-module item");
145 Err(SymbolResolutionError::invalid_sub_path(
146 path.span(),
147 item.span(),
148 &*self.source_manager,
149 ))
150 },
151 SymbolResolution::MastRoot(digest) => {
152 log::debug!(target: "local-symbol-resolver", "resolved '{ns}' to procedure root '{digest}'");
153 if subpath.is_empty() {
154 return Ok(SymbolResolution::MastRoot(digest));
155 }
156
157 log::error!(target: "local-symbol-resolver", "cannot resolve '{subpath}' relative to procedure");
159 Err(SymbolResolutionError::invalid_sub_path(
160 path.span(),
161 digest.span(),
162 &*self.source_manager,
163 ))
164 },
165 SymbolResolution::Module { id, path, .. } => {
166 if subpath.is_empty() {
167 Ok(SymbolResolution::Module { id, path })
168 } else {
169 Ok(SymbolResolution::External(path.map(|p| p.join(subpath).into())))
170 }
171 },
172 SymbolResolution::Exact { .. } => unreachable!(),
173 }
174 }
175
176 pub fn get_item_name(&self, index: ItemIndex) -> Ident {
180 match &self.symbols[index] {
181 LocalSymbol::Item { name, .. } => name.clone(),
182 LocalSymbol::Import { name, .. } => Ident::from_raw_parts(name.clone()),
183 }
184 }
185}