microcad_lang/resolve/
resolve_error.rs1#![allow(unused_assignments)]
5use miette::Diagnostic;
8use thiserror::Error;
9
10use crate::src_ref::{SrcRef, SrcReferrer};
11use crate::{diag::*, parse::*, syntax::*};
12use crate::resolve::grant::Grant;
13use crate::resolve::Symbol;
14
15fn capitalize_first(s: &str) -> String {
16 let mut c = s.chars();
17 match c.next() {
18 None => String::new(),
19 Some(first) => first.to_uppercase().collect::<String>() + c.as_str(),
20 }
21}
22
23#[derive(Debug, Error, Diagnostic)]
25pub enum ResolveError {
26 #[error("Parse Error: {0}")]
28 #[diagnostic(transparent)]
29 ParseError(#[from] ParseErrorsWithSource),
30
31 #[error("Could not find a file with hash {0}")]
33 UnknownHash(u64),
34
35 #[error("Hash is zero")]
37 NulHash,
38
39 #[error("External symbol `{0}` not found")]
41 ExternalSymbolNotFound(QualifiedName),
42
43 #[error("External path `{0}` not found")]
45 ExternalPathNotFound(std::path::PathBuf),
46
47 #[error("Could not find a file with path {0}")]
49 FileNotFound(std::path::PathBuf),
50
51 #[error("Symbol {0} not found while resolving.")]
53 SymbolNotFound(QualifiedName),
54
55 #[error("Symbol {0} must be loaded from {1}")]
57 SymbolMustBeLoaded(QualifiedName, std::path::PathBuf),
58
59 #[error("Symbol {0} is not a value")]
61 NotAValue(QualifiedName),
62
63 #[error("Ambiguous external module files found {0:?}")]
65 AmbiguousExternals(Vec<std::path::PathBuf>),
66
67 #[error("Symbol {0} already defined")]
69 SymbolAlreadyDefined(QualifiedName),
70
71 #[error("Ambiguous symbol found: {0}")]
73 AmbiguousSymbol(QualifiedName, QualifiedNames),
74
75 #[error("{0}")]
77 ScanDirError(#[from] scan_dir::Error),
78
79 #[error("Invalid path: {0:?}")]
81 InvalidPath(std::path::PathBuf),
82
83 #[error("Diagnostic error: {0}")]
85 DiagError(#[from] DiagError),
86
87 #[error(transparent)]
89 #[diagnostic(transparent)]
90 StatementNotSupported(#[from] StatementNotSupportedError),
91
92 #[error("Resolve failed")]
94 ResolveCheckFailed(SrcRef),
95
96 #[error("Symbol {0} is private")]
98 SymbolIsPrivate(QualifiedName),
99
100 #[error("{0}")]
102 IoError(#[from] std::io::Error),
103
104 #[error(
106 "Source of module '{0}' could not be found in {1:?} (expecting a file '{0}.µcad' or '{0}/mod.µcad')"
107 )]
108 SourceFileNotFound(#[label("module not found")] Identifier, std::path::PathBuf),
109
110 #[error("Wrong lookup target")]
112 WrongTarget,
113
114 #[error("Statement not allowed within workbenches")]
116 IllegalWorkbenchStatement,
117
118 #[error("Code between initializers is not allowed")]
120 #[allow(missing_docs)]
121 CodeBetweenInitializers {
122 #[label("Between these initializers")]
123 initializers: SrcRef,
124 #[label(primary, "This statement is not allowed")]
125 statement: SrcRef,
126 #[label("Inside this {kind}")]
127 workbench: SrcRef,
128 kind: &'static str,
129 },
130
131 #[error("Statement not allowed prior initializers")]
133 #[allow(missing_docs)]
134 StatementNotAllowedPriorInitializers {
135 #[label("Before this initializer")]
136 initializer: SrcRef,
137 #[label(primary, "This statement is not allowed")]
138 statement: SrcRef,
139 #[label("Inside this {kind}")]
140 workbench: SrcRef,
141 kind: &'static str,
142 },
143}
144
145
146#[derive(Debug, Error, Diagnostic)]
148#[error("{} is not available within {outer}", capitalize_first(inner))]
149#[diagnostic(help("{inner} is only allowed within {}", self.allowed_parents()))]
150pub struct StatementNotSupportedError {
151 inner: &'static str,
152 #[label(primary, "This {inner} is not allowed")]
153 inner_span: SrcRef,
154 outer: &'static str,
155 #[label("Within this {outer}")]
156 outer_span: SrcRef,
157 allowed_parents: &'static[&'static str],
158}
159
160impl StatementNotSupportedError {
161 pub(super) fn new<T: Grant + SrcReferrer>(node: &T, parent: &Symbol) -> Self {
163 StatementNotSupportedError {
164 inner: node.kind(),
165 inner_span: node.src_ref(),
166 outer: parent.kind_str(),
167 outer_span: parent.src_ref(),
168 allowed_parents: node.allowed_parents(),
169 }
170 }
171
172 fn allowed_parents(&self) -> impl std::fmt::Display {
173 struct AllowedParents(&'static[&'static str]);
174
175 impl std::fmt::Display for AllowedParents {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 let mut items = self.0.iter();
178 if let Some(first) = items.next() {
179 write!(f, "{first}")?;
180 }
181 let last = items.next_back();
182 for item in items {
183 write!(f, ", {item}")?;
184 }
185 if let Some(last) = last {
186 write!(f, " or {last}")?;
187 }
188 Ok(())
189 }
190 }
191
192 AllowedParents(self.allowed_parents)
193 }
194}
195
196impl SrcReferrer for ResolveError {
197 fn src_ref(&self) -> SrcRef {
198 match self {
199 ResolveError::SourceFileNotFound(identifier, _) => identifier.src_ref(),
200 ResolveError::ParseError(parse_error) => parse_error.src_ref(),
201 ResolveError::ResolveCheckFailed(src_ref) => src_ref.clone(),
202 _ => SrcRef(None),
203 }
204 }
205}
206
207pub type ResolveResult<T> = std::result::Result<T, ResolveError>;