Skip to main content

miden_assembly/linker/
symbols.rs

1use alloc::{boxed::Box, sync::Arc};
2use core::cell::{Cell, RefCell};
3
4use miden_assembly_syntax::{
5    Path,
6    ast::{self, GlobalItemIndex, Ident, ImportKind, Visibility},
7    debuginfo::{SourceSpan, Span, Spanned},
8    module::ItemInfo,
9};
10
11use super::LinkStatus;
12
13/// A [Symbol] is a named, linkable item defined within a module.
14#[derive(Debug, Clone)]
15pub struct Symbol {
16    /// The name of the symbol in it's containing module.
17    name: Ident,
18    /// The external visibility of the symbol
19    visibility: Visibility,
20    /// The link status of the symbol, i.e. unlinked, partially, or fully linked.
21    status: Cell<LinkStatus>,
22    /// The type of item associated with this symbol.
23    item: SymbolItem,
24}
25
26/// An import declared by a module.
27#[derive(Debug, Clone)]
28pub struct Import {
29    /// The original import declaration.
30    decl: ast::Import,
31    /// Once this import has been resolved to a concrete item, cache the target id.
32    resolved: Cell<Option<GlobalItemIndex>>,
33}
34
35/// A [SymbolItem] represents the type of item associated with a [Symbol].
36#[derive(Debug, Clone)]
37pub enum SymbolItem {
38    /// A constant declaration in AST form
39    Constant(ast::Constant),
40    /// A type or enum declaration in AST form
41    Type(ast::TypeDecl),
42    /// Procedure symbols are wrapped in a `RefCell` to allow us to mutate the procedure body when
43    /// linking any externally-defined symbols it contains.
44    Procedure(RefCell<Box<ast::Procedure>>),
45    /// An already-assembled item
46    Compiled(ItemInfo),
47}
48
49impl Import {
50    /// Create a new [Import].
51    #[inline]
52    pub fn new(decl: ast::Import) -> Self {
53        Self { decl, resolved: Cell::new(None) }
54    }
55
56    /// Get the import declaration.
57    #[inline(always)]
58    pub fn decl(&self) -> &ast::Import {
59        &self.decl
60    }
61
62    /// Get the import kind.
63    #[inline(always)]
64    pub fn kind(&self) -> ImportKind {
65        self.decl.kind()
66    }
67
68    /// Get the local name bound by this import.
69    #[inline(always)]
70    pub fn local_name(&self) -> &Ident {
71        self.decl.local_name()
72    }
73
74    /// Get the import visibility.
75    #[inline(always)]
76    pub fn visibility(&self) -> Visibility {
77        self.decl.visibility()
78    }
79
80    /// Get the source span covering this import.
81    #[inline(always)]
82    pub fn span(&self) -> SourceSpan {
83        self.decl.span()
84    }
85
86    /// Get the target module path for this import.
87    #[inline(always)]
88    pub fn module_path(&self) -> Span<&Path> {
89        self.decl.module_path()
90    }
91
92    /// Get the full target path for this import.
93    pub fn target_path(&self) -> Span<Arc<Path>> {
94        match &self.decl {
95            ast::Import::Module(import) => {
96                let path = import.module_path();
97                Span::new(path.span(), Arc::from(*path))
98            },
99            ast::Import::Item(import) => import.target_path(),
100        }
101    }
102
103    /// Get the cached resolved concrete item, if known.
104    #[inline(always)]
105    pub fn resolved(&self) -> Option<GlobalItemIndex> {
106        self.resolved.get()
107    }
108
109    /// Set the cached resolved concrete item.
110    #[inline]
111    pub fn set_resolved(&self, resolved: GlobalItemIndex) {
112        self.resolved.set(Some(resolved));
113    }
114}
115
116impl Symbol {
117    /// Create a new [Symbol].
118    #[inline]
119    pub fn new(name: Ident, visibility: Visibility, status: LinkStatus, item: SymbolItem) -> Self {
120        Self {
121            name,
122            visibility,
123            status: Cell::new(status),
124            item,
125        }
126    }
127
128    /// Get the module-local name of this symbol
129    #[inline(always)]
130    pub fn name(&self) -> &Ident {
131        &self.name
132    }
133
134    /// Get the external visibility of this symbol
135    #[inline(always)]
136    pub fn visibility(&self) -> Visibility {
137        self.visibility
138    }
139
140    /// Get the item associated with this symbol
141    #[inline(always)]
142    pub fn item(&self) -> &SymbolItem {
143        &self.item
144    }
145
146    /// Get the current link status of this symbol
147    #[inline(always)]
148    pub fn status(&self) -> LinkStatus {
149        self.status.get()
150    }
151
152    /// Set the link status of this symbol
153    #[inline]
154    pub fn set_status(&self, status: LinkStatus) {
155        self.status.set(status);
156    }
157
158    /// Returns true if this symbol has not yet been visited by the linker.
159    #[inline]
160    pub fn is_unlinked(&self) -> bool {
161        matches!(self.status.get(), LinkStatus::Unlinked)
162    }
163
164    /// Returns true if this symbol is fully-linked.
165    #[inline]
166    pub fn is_linked(&self) -> bool {
167        matches!(self.status.get(), LinkStatus::Linked)
168    }
169
170    /// Returns true if this symbol represents a procedure definition.
171    pub fn is_procedure(&self) -> bool {
172        matches!(
173            &self.item,
174            SymbolItem::Compiled(ItemInfo::Procedure(_)) | SymbolItem::Procedure(_)
175        )
176    }
177}