1use alloc::{string::String, sync::Arc, vec::Vec};
2
3use vm_core::mast::MastForestError;
4
5use crate::{
6 ast::QualifiedProcedureName,
7 diagnostics::{Diagnostic, RelatedError, RelatedLabel, SourceFile},
8 LibraryNamespace, LibraryPath, SourceSpan,
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("two procedures found with same mast root, but conflicting definitions ('{first}' and '{second}')")]
32 #[diagnostic()]
33 ConflictingDefinitions {
34 first: QualifiedProcedureName,
35 second: QualifiedProcedureName,
36 },
37 #[error("duplicate definition found for module '{path}'")]
38 #[diagnostic()]
39 DuplicateModule { path: LibraryPath },
40 #[error("undefined module '{path}'")]
41 #[diagnostic()]
42 UndefinedModule {
43 #[label]
44 span: SourceSpan,
45 #[source_code]
46 source_file: Option<Arc<SourceFile>>,
47 path: LibraryPath,
48 },
49 #[error("module namespace is inconsistent with library ('{actual}' vs '{expected}')")]
50 #[diagnostic()]
51 InconsistentNamespace {
52 expected: LibraryNamespace,
53 actual: LibraryNamespace,
54 },
55 #[error("invalid syscall: '{callee}' is not an exported kernel procedure")]
56 #[diagnostic()]
57 InvalidSysCallTarget {
58 #[label("call occurs here")]
59 span: SourceSpan,
60 #[source_code]
61 source_file: Option<Arc<SourceFile>>,
62 callee: QualifiedProcedureName,
63 },
64 #[error("invalid local word index: {local_addr}")]
65 #[diagnostic(help("the index to a local word must be a multiple of 4"))]
66 InvalidLocalWordIndex {
67 #[label]
68 span: SourceSpan,
69 #[source_code]
70 source_file: Option<Arc<SourceFile>>,
71 local_addr: u16,
72 },
73 #[error("invalid use of 'caller' instruction outside of kernel")]
74 #[diagnostic(help(
75 "the 'caller' instruction is only allowed in procedures defined in a kernel"
76 ))]
77 CallerOutsideOfKernel {
78 #[label]
79 span: SourceSpan,
80 #[source_code]
81 source_file: Option<Arc<SourceFile>>,
82 },
83
84 #[error("invalid procedure: body must contain at least one instruction if it has decorators")]
85 #[diagnostic()]
86 EmptyProcedureBodyWithDecorators {
87 span: SourceSpan,
88 #[source_code]
89 source_file: Option<Arc<SourceFile>>,
90 },
91 #[error(transparent)]
92 #[diagnostic(transparent)]
93 Other(RelatedError),
94 #[error("{0}: {1}")]
98 Forest(&'static str, MastForestError),
99}
100
101impl AssemblyError {
102 pub(super) fn forest_error(message: &'static str, source: MastForestError) -> Self {
103 Self::Forest(message, source)
104 }
105}