1use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
2use core::fmt;
3
4use miden_core::{
5 AdviceMap,
6 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8use miden_debug_types::{SourceFile, SourceManager, SourceSpan, Span, Spanned};
9use miden_utils_diagnostics::Report;
10use smallvec::SmallVec;
11
12use super::{
13 Alias, Constant, DocString, EnumType, Export, FunctionType, GlobalItemIndex, ItemIndex,
14 LocalSymbolResolver, Path, Procedure, ProcedureName, QualifiedProcedureName, SymbolResolution,
15 SymbolResolutionError, TypeAlias, TypeDecl, TypeResolver, Variant,
16};
17use crate::{
18 PathBuf,
19 ast::{self, Ident, types},
20 parser::ModuleParser,
21 sema::SemanticAnalysisError,
22};
23
24#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
33#[repr(u8)]
34pub enum ModuleKind {
35 #[default]
42 Library = 0,
43 Executable = 1,
52 Kernel = 2,
63}
64
65impl ModuleKind {
66 pub fn is_executable(&self) -> bool {
67 matches!(self, Self::Executable)
68 }
69
70 pub fn is_kernel(&self) -> bool {
71 matches!(self, Self::Kernel)
72 }
73
74 pub fn is_library(&self) -> bool {
75 matches!(self, Self::Library)
76 }
77}
78
79impl fmt::Display for ModuleKind {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 match self {
82 Self::Library => f.write_str("library"),
83 Self::Executable => f.write_str("executable"),
84 Self::Kernel => f.write_str("kernel"),
85 }
86 }
87}
88
89impl Serializable for ModuleKind {
90 fn write_into<W: ByteWriter>(&self, target: &mut W) {
91 target.write_u8(*self as u8)
92 }
93}
94
95impl Deserializable for ModuleKind {
96 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
97 match source.read_u8()? {
98 0 => Ok(Self::Library),
99 1 => Ok(Self::Executable),
100 2 => Ok(Self::Kernel),
101 n => Err(DeserializationError::InvalidValue(format!("invalid module kind tag: {n}"))),
102 }
103 }
104}
105
106#[derive(Clone)]
114pub struct Module {
115 span: SourceSpan,
117 docs: Option<DocString>,
123 path: PathBuf,
125 kind: ModuleKind,
127 pub(crate) items: Vec<Export>,
129 pub(crate) advice_map: AdviceMap,
131}
132
133impl Module {
135 pub const FILE_EXTENSION: &'static str = "masm";
137
138 pub const ROOT: &'static str = "mod";
140
141 pub const ROOT_FILENAME: &'static str = "mod.masm";
143}
144
145impl Module {
147 pub fn new(kind: ModuleKind, path: impl AsRef<Path>) -> Self {
150 let path = path.as_ref().to_absolute().into_owned();
151 Self {
152 span: Default::default(),
153 docs: None,
154 path,
155 kind,
156 items: Default::default(),
157 advice_map: Default::default(),
158 }
159 }
160
161 pub fn new_kernel() -> Self {
163 Self::new(ModuleKind::Kernel, Path::kernel_path())
164 }
165
166 pub fn new_executable() -> Self {
168 Self::new(ModuleKind::Executable, Path::exec_path())
169 }
170
171 pub fn with_span(mut self, span: SourceSpan) -> Self {
174 self.span = span;
175 self
176 }
177
178 pub fn set_path(&mut self, path: impl AsRef<Path>) {
180 self.path = path.as_ref().to_path_buf();
181 }
182
183 pub fn set_parent(&mut self, ns: impl AsRef<Path>) {
188 self.path.set_parent(ns.as_ref());
189 }
190
191 pub fn set_docs(&mut self, docs: Option<Span<String>>) {
193 self.docs = docs.map(DocString::new);
194 }
195
196 pub fn set_span(&mut self, span: SourceSpan) {
198 self.span = span;
199 }
200
201 pub fn define_constant(&mut self, constant: Constant) -> Result<(), SemanticAnalysisError> {
203 for item in self.items.iter() {
204 if let Export::Constant(c) = item
205 && c.name == constant.name
206 {
207 return Err(SemanticAnalysisError::SymbolConflict {
208 span: constant.span,
209 prev_span: c.span,
210 });
211 }
212 }
213 self.items.push(Export::Constant(constant));
214 Ok(())
215 }
216
217 pub fn define_type(&mut self, ty: TypeAlias) -> Result<(), SemanticAnalysisError> {
219 for item in self.items.iter() {
220 if let Export::Type(t) = item
221 && t.name() == ty.name()
222 {
223 return Err(SemanticAnalysisError::SymbolConflict {
224 span: ty.span(),
225 prev_span: t.span(),
226 });
227 }
228 }
229 self.items.push(Export::Type(ty.into()));
230 Ok(())
231 }
232
233 pub fn define_enum(&mut self, ty: EnumType) -> Result<(), SemanticAnalysisError> {
243 let repr = ty.ty().clone();
244
245 if !repr.is_integer() {
246 return Err(SemanticAnalysisError::InvalidEnumRepr { span: ty.span() });
247 }
248
249 let (alias, variants) = ty.into_parts();
250
251 if let Some(prev) = self.items.iter().find(|t| t.name() == &alias.name) {
252 return Err(SemanticAnalysisError::SymbolConflict {
253 span: alias.span(),
254 prev_span: prev.span(),
255 });
256 }
257
258 let mut values = SmallVec::<[Span<u64>; 8]>::new_const();
259
260 for variant in variants {
261 let value = match &variant.discriminant {
263 ast::ConstantExpr::Int(value) => (*value).map(|v| v.as_int()),
264 expr => {
265 return Err(SemanticAnalysisError::InvalidEnumDiscriminant {
266 span: expr.span(),
267 repr,
268 });
269 },
270 };
271 if let Some(prev) = values.iter().find(|v| *v == &value) {
272 return Err(SemanticAnalysisError::EnumDiscriminantConflict {
273 span: value.span(),
274 prev: prev.span(),
275 });
276 } else {
277 values.push(value);
278 }
279
280 variant.assert_instance_of(&repr)?;
282
283 let Variant { span, docs, name, discriminant } = variant;
284
285 self.define_constant(Constant {
286 span,
287 docs,
288 visibility: alias.visibility(),
289 name,
290 value: discriminant,
291 })?;
292 }
293
294 self.items.push(Export::Type(alias.into()));
295
296 Ok(())
297 }
298
299 pub fn define_procedure(
302 &mut self,
303 procedure: Procedure,
304 source_manager: Arc<dyn SourceManager>,
305 ) -> Result<(), SemanticAnalysisError> {
306 let name = procedure.name();
307 let name = Span::new(name.span(), name.as_str());
308 if let Ok(prev) = self.resolve(name, source_manager) {
309 let prev_span = prev.span();
310 Err(SemanticAnalysisError::SymbolConflict { span: procedure.span(), prev_span })
311 } else {
312 self.items.push(Export::Procedure(procedure));
313 Ok(())
314 }
315 }
316
317 pub fn define_alias(
320 &mut self,
321 item: Alias,
322 source_manager: Arc<dyn SourceManager>,
323 ) -> Result<(), SemanticAnalysisError> {
324 if self.is_kernel() && item.visibility().is_public() {
325 return Err(SemanticAnalysisError::ReexportFromKernel { span: item.span() });
326 }
327 let name = item.name();
328 let name = Span::new(name.span(), name.as_str());
329 if let Ok(prev) = self.resolve(name, source_manager) {
330 let prev_span = prev.span();
331 Err(SemanticAnalysisError::SymbolConflict { span: item.span(), prev_span })
332 } else {
333 self.items.push(Export::Alias(item));
334 Ok(())
335 }
336 }
337}
338
339impl Module {
341 pub fn parse(
343 name: impl AsRef<Path>,
344 kind: ModuleKind,
345 source_file: Arc<SourceFile>,
346 source_manager: Arc<dyn SourceManager>,
347 ) -> Result<Box<Self>, Report> {
348 let name = name.as_ref();
349 let mut parser = Self::parser(kind);
350 parser.parse(name, source_file, source_manager)
351 }
352
353 pub fn parser(kind: ModuleKind) -> ModuleParser {
355 ModuleParser::new(kind)
356 }
357}
358
359impl Module {
361 pub fn name(&self) -> &str {
364 self.path.last().expect("non-empty module path")
365 }
366
367 pub fn path(&self) -> &Path {
369 &self.path
370 }
371
372 pub fn parent(&self) -> Option<&Path> {
374 self.path.parent()
375 }
376
377 pub fn is_in_namespace(&self, namespace: &Path) -> bool {
379 self.path.starts_with(namespace)
380 }
381
382 pub fn docs(&self) -> Option<Span<&str>> {
385 self.docs.as_ref().map(|spanned| spanned.as_spanned_str())
386 }
387
388 pub fn kind(&self) -> ModuleKind {
392 self.kind
393 }
394
395 pub fn set_kind(&mut self, kind: ModuleKind) {
399 self.kind = kind;
400 }
401
402 #[inline(always)]
404 pub fn is_executable(&self) -> bool {
405 self.kind.is_executable()
406 }
407
408 #[inline(always)]
410 pub fn is_kernel(&self) -> bool {
411 self.kind.is_kernel() && self.path.is_kernel_path()
412 }
413
414 #[inline(always)]
416 pub fn is_in_kernel(&self) -> bool {
417 self.kind.is_kernel()
418 }
419
420 pub fn has_entrypoint(&self) -> bool {
423 self.index_of(|p| p.is_main()).is_some()
424 }
425
426 pub fn advice_map(&self) -> &AdviceMap {
428 &self.advice_map
429 }
430
431 pub fn constants(&self) -> impl Iterator<Item = &Constant> + '_ {
433 self.items.iter().filter_map(|item| match item {
434 Export::Constant(item) => Some(item),
435 _ => None,
436 })
437 }
438
439 pub fn constants_mut(&mut self) -> impl Iterator<Item = &mut Constant> + '_ {
441 self.items.iter_mut().filter_map(|item| match item {
442 Export::Constant(item) => Some(item),
443 _ => None,
444 })
445 }
446
447 pub fn types(&self) -> impl Iterator<Item = &TypeDecl> + '_ {
449 self.items.iter().filter_map(|item| match item {
450 Export::Type(item) => Some(item),
451 _ => None,
452 })
453 }
454
455 pub fn types_mut(&mut self) -> impl Iterator<Item = &mut TypeDecl> + '_ {
457 self.items.iter_mut().filter_map(|item| match item {
458 Export::Type(item) => Some(item),
459 _ => None,
460 })
461 }
462
463 pub fn procedures(&self) -> impl Iterator<Item = &Procedure> + '_ {
465 self.items.iter().filter_map(|item| match item {
466 Export::Procedure(item) => Some(item),
467 _ => None,
468 })
469 }
470
471 pub fn procedures_mut(&mut self) -> impl Iterator<Item = &mut Procedure> + '_ {
473 self.items.iter_mut().filter_map(|item| match item {
474 Export::Procedure(item) => Some(item),
475 _ => None,
476 })
477 }
478
479 pub fn aliases(&self) -> impl Iterator<Item = &Alias> + '_ {
481 self.items.iter().filter_map(|item| match item {
482 Export::Alias(item) => Some(item),
483 _ => None,
484 })
485 }
486
487 pub fn aliases_mut(&mut self) -> impl Iterator<Item = &mut Alias> + '_ {
489 self.items.iter_mut().filter_map(|item| match item {
490 Export::Alias(item) => Some(item),
491 _ => None,
492 })
493 }
494
495 pub fn items(&self) -> &[Export] {
497 &self.items
498 }
499
500 pub fn items_mut(&mut self) -> &mut Vec<Export> {
502 &mut self.items
503 }
504
505 pub fn exported(&self) -> impl Iterator<Item = (ItemIndex, QualifiedProcedureName)> + '_ {
509 self.items.iter().enumerate().filter_map(|(idx, item)| {
510 if !item.visibility().is_public() {
512 return None;
513 }
514
515 let idx = ItemIndex::new(idx);
516 let name = ProcedureName::from_raw_parts(item.name().clone());
517 let fqn = QualifiedProcedureName::new(self.path.clone(), name);
518
519 Some((idx, fqn))
520 })
521 }
522
523 pub fn procedure_signature(&self, id: ItemIndex) -> Option<&FunctionType> {
525 self.items[id.as_usize()].signature()
526 }
527
528 pub fn get(&self, index: ItemIndex) -> Option<&Export> {
533 self.items.get(index.as_usize())
534 }
535
536 pub fn index_of<F>(&self, predicate: F) -> Option<ItemIndex>
539 where
540 F: FnMut(&Export) -> bool,
541 {
542 self.items.iter().position(predicate).map(ItemIndex::new)
543 }
544
545 pub fn index_of_name(&self, name: &Ident) -> Option<ItemIndex> {
550 self.index_of(|item| item.name() == name && item.visibility().is_public())
551 }
552
553 pub fn resolve(
555 &self,
556 name: Span<&str>,
557 source_manager: Arc<dyn SourceManager>,
558 ) -> Result<SymbolResolution, SymbolResolutionError> {
559 let resolver = self.resolver(source_manager);
560 resolver.resolve(name)
561 }
562
563 pub fn resolve_path(
565 &self,
566 path: Span<&Path>,
567 source_manager: Arc<dyn SourceManager>,
568 ) -> Result<SymbolResolution, SymbolResolutionError> {
569 let resolver = self.resolver(source_manager);
570 resolver.resolve_path(path)
571 }
572
573 #[inline]
575 pub fn resolver(&self, source_manager: Arc<dyn SourceManager>) -> LocalSymbolResolver {
576 LocalSymbolResolver::new(self, source_manager)
577 }
578
579 pub fn get_import(&self, module_name: &str) -> Option<&Alias> {
581 self.items.iter().find_map(|item| match item {
582 Export::Alias(item) if item.name().as_str() == module_name => Some(item),
583 _ => None,
584 })
585 }
586
587 pub fn get_import_mut(&mut self, module_name: &str) -> Option<&mut Alias> {
589 self.items.iter_mut().find_map(|item| match item {
590 Export::Alias(item) if item.name().as_str() == module_name => Some(item),
591 _ => None,
592 })
593 }
594
595 pub fn resolve_type(
597 &self,
598 ty: &ast::TypeExpr,
599 source_manager: Arc<dyn SourceManager>,
600 ) -> Result<Option<types::Type>, SymbolResolutionError> {
601 let type_resolver = ModuleTypeResolver::new(self, source_manager);
602 type_resolver.resolve(ty)
603 }
604
605 pub fn type_resolver(
607 &self,
608 source_manager: Arc<dyn SourceManager>,
609 ) -> impl TypeResolver<SymbolResolutionError> + '_ {
610 ModuleTypeResolver::new(self, source_manager)
611 }
612}
613
614impl core::ops::Index<ItemIndex> for Module {
615 type Output = Export;
616
617 #[inline]
618 fn index(&self, index: ItemIndex) -> &Self::Output {
619 &self.items[index.as_usize()]
620 }
621}
622
623impl core::ops::IndexMut<ItemIndex> for Module {
624 #[inline]
625 fn index_mut(&mut self, index: ItemIndex) -> &mut Self::Output {
626 &mut self.items[index.as_usize()]
627 }
628}
629
630impl Spanned for Module {
631 fn span(&self) -> SourceSpan {
632 self.span
633 }
634}
635
636impl Eq for Module {}
637
638impl PartialEq for Module {
639 fn eq(&self, other: &Self) -> bool {
640 self.kind == other.kind
641 && self.path == other.path
642 && self.docs == other.docs
643 && self.items == other.items
644 }
645}
646
647impl fmt::Debug for Module {
649 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
650 f.debug_struct("Module")
651 .field("docs", &self.docs)
652 .field("path", &self.path)
653 .field("kind", &self.kind)
654 .field("items", &self.items)
655 .finish()
656 }
657}
658
659impl fmt::Display for Module {
663 #[inline]
668 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
669 use crate::prettier::PrettyPrint;
670
671 self.pretty_print(f)
672 }
673}
674
675impl crate::prettier::PrettyPrint for Module {
677 fn render(&self) -> crate::prettier::Document {
678 use crate::prettier::*;
679
680 let mut doc = self
681 .docs
682 .as_ref()
683 .map(|docstring| docstring.render() + nl())
684 .unwrap_or(Document::Empty);
685
686 for (item_index, item) in self.items.iter().enumerate() {
687 if item_index > 0 {
688 doc += nl();
689 }
690 doc += item.render();
691 }
692
693 doc
694 }
695}
696
697struct ModuleTypeResolver<'a> {
698 module: &'a Module,
699 resolver: LocalSymbolResolver,
700}
701
702impl<'a> ModuleTypeResolver<'a> {
703 pub fn new(module: &'a Module, source_manager: Arc<dyn SourceManager>) -> Self {
704 let resolver = module.resolver(source_manager);
705 Self { module, resolver }
706 }
707}
708
709impl TypeResolver<SymbolResolutionError> for ModuleTypeResolver<'_> {
710 fn source_manager(&self) -> Arc<dyn SourceManager> {
711 self.resolver.source_manager()
712 }
713 fn get_type(
714 &self,
715 context: SourceSpan,
716 _gid: GlobalItemIndex,
717 ) -> Result<ast::types::Type, SymbolResolutionError> {
718 Err(SymbolResolutionError::undefined(context, &self.resolver.source_manager()))
719 }
720 fn get_local_type(
721 &self,
722 context: SourceSpan,
723 id: ItemIndex,
724 ) -> Result<Option<ast::types::Type>, SymbolResolutionError> {
725 match &self.module[id] {
726 super::Export::Type(ty) => match ty {
727 TypeDecl::Alias(ty) => self.resolve(&ty.ty),
728 TypeDecl::Enum(ty) => Ok(Some(ty.ty().clone())),
729 },
730 item => Err(self.resolve_local_failed(SymbolResolutionError::invalid_symbol_type(
731 context,
732 "type",
733 item.span(),
734 &self.resolver.source_manager(),
735 ))),
736 }
737 }
738 #[inline(always)]
739 fn resolve_local_failed(&self, err: SymbolResolutionError) -> SymbolResolutionError {
740 err
741 }
742 fn resolve_type_ref(
743 &self,
744 path: Span<&Path>,
745 ) -> Result<SymbolResolution, SymbolResolutionError> {
746 self.resolver.resolve_path(path)
747 }
748}