1use alloc::{string::String, sync::Arc, vec::Vec};
2
3use vm_core::mast::MastForestError;
4
5use crate::{
6 LibraryNamespace, LibraryPath, SourceSpan,
7 ast::QualifiedProcedureName,
8 diagnostics::{Diagnostic, RelatedError, RelatedLabel, SourceFile},
9};
10
11#[derive(Debug, thiserror::Error, Diagnostic)]
16#[non_exhaustive]
17#[allow(clippy::large_enum_variant)]
18pub enum AssemblyError {
19 #[error("there are no modules to analyze")]
20 #[diagnostic()]
21 Empty,
22 #[error("assembly failed")]
23 #[diagnostic(help("see diagnostics for details"))]
24 Failed {
25 #[related]
26 labels: Vec<RelatedLabel>,
27 },
28 #[error("found a cycle in the call graph, involving these procedures: {}", nodes.as_slice().join(", "))]
29 #[diagnostic()]
30 Cycle { nodes: Vec<String> },
31 #[error(
32 "two procedures found with same mast root, but conflicting definitions ('{first}' and '{second}')"
33 )]
34 #[diagnostic()]
35 ConflictingDefinitions {
36 first: QualifiedProcedureName,
37 second: QualifiedProcedureName,
38 },
39 #[error("duplicate definition found for module '{path}'")]
40 #[diagnostic()]
41 DuplicateModule { path: LibraryPath },
42 #[error("undefined module '{path}'")]
43 #[diagnostic()]
44 UndefinedModule {
45 #[label]
46 span: SourceSpan,
47 #[source_code]
48 source_file: Option<Arc<SourceFile>>,
49 path: LibraryPath,
50 },
51 #[error("module namespace is inconsistent with library ('{actual}' vs '{expected}')")]
52 #[diagnostic()]
53 InconsistentNamespace {
54 expected: LibraryNamespace,
55 actual: LibraryNamespace,
56 },
57 #[error("invalid syscall: '{callee}' is not an exported kernel procedure")]
58 #[diagnostic()]
59 InvalidSysCallTarget {
60 #[label("call occurs here")]
61 span: SourceSpan,
62 #[source_code]
63 source_file: Option<Arc<SourceFile>>,
64 callee: QualifiedProcedureName,
65 },
66 #[error("invalid local word index: {local_addr}")]
67 #[diagnostic(help("the index to a local word must be a multiple of 4"))]
68 InvalidLocalWordIndex {
69 #[label]
70 span: SourceSpan,
71 #[source_code]
72 source_file: Option<Arc<SourceFile>>,
73 local_addr: u16,
74 },
75 #[error("invalid use of 'caller' instruction outside of kernel")]
76 #[diagnostic(help(
77 "the 'caller' instruction is only allowed in procedures defined in a kernel"
78 ))]
79 CallerOutsideOfKernel {
80 #[label]
81 span: SourceSpan,
82 #[source_code]
83 source_file: Option<Arc<SourceFile>>,
84 },
85
86 #[error("invalid procedure: body must contain at least one instruction if it has decorators")]
87 #[diagnostic()]
88 EmptyProcedureBodyWithDecorators {
89 span: SourceSpan,
90 #[source_code]
91 source_file: Option<Arc<SourceFile>>,
92 },
93 #[error(transparent)]
94 #[diagnostic(transparent)]
95 Other(RelatedError),
96 #[error("{0}: {1}")]
100 Forest(&'static str, MastForestError),
101}
102
103impl AssemblyError {
104 pub(super) fn forest_error(message: &'static str, source: MastForestError) -> Self {
105 Self::Forest(message, source)
106 }
107}