1#![allow(unused_assignments)]
3
4use alloc::{string::String, sync::Arc, vec::Vec};
5use core::{fmt, ops::Range};
6
7use miden_debug_types::SourceSpan;
8use miden_utils_diagnostics::{Diagnostic, miette};
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
14pub enum LiteralErrorKind {
15 Empty,
17 InvalidDigit,
19 U32Overflow,
21 FeltOverflow,
23 InvalidBitSize,
25}
26
27impl fmt::Display for LiteralErrorKind {
28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29 match self {
30 Self::Empty => f.write_str("input was empty"),
31 Self::InvalidDigit => f.write_str("invalid digit"),
32 Self::U32Overflow => f.write_str("value overflowed the u32 range"),
33 Self::FeltOverflow => f.write_str("value overflowed the field modulus"),
34 Self::InvalidBitSize => {
35 f.write_str("expected value to be a valid bit size, e.g. 0..63")
36 },
37 }
38 }
39}
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
45pub enum HexErrorKind {
46 MissingDigits,
48 Invalid,
51 Overflow,
53 TooLong,
55}
56
57impl fmt::Display for HexErrorKind {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 match self {
60 Self::MissingDigits => {
61 f.write_str("expected number of hex digits to be a multiple of 2")
62 },
63 Self::Invalid => f.write_str("expected 2, 4, 8, 16, or 64 hex digits"),
64 Self::Overflow => f.write_str("value overflowed the field modulus"),
65 Self::TooLong => f.write_str(
66 "value has too many digits, long hex strings must contain exactly 64 digits",
67 ),
68 }
69 }
70}
71
72#[derive(Debug, Copy, Clone, PartialEq, Eq)]
76pub enum BinErrorKind {
77 TooLong,
79}
80
81impl fmt::Display for BinErrorKind {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 match self {
84 Self::TooLong => f.write_str(
85 "value has too many digits, binary string can contain no more than 32 digits",
86 ),
87 }
88 }
89}
90
91#[non_exhaustive]
95#[derive(Debug, Default, thiserror::Error, Diagnostic)]
96#[repr(u8)]
97pub enum ParsingError {
98 #[default]
99 #[error("parsing failed due to unexpected input")]
100 #[diagnostic()]
101 Failed = 0,
102 #[error("expected input to be valid utf8, but invalid byte sequences were found")]
103 #[diagnostic()]
104 InvalidUtf8 {
105 #[label("invalid byte sequence starts here")]
106 span: SourceSpan,
107 },
108 #[error(
109 "expected input to be valid utf8, but end-of-file was reached before final codepoint was read"
110 )]
111 #[diagnostic()]
112 IncompleteUtf8 {
113 #[label("the codepoint starting here is incomplete")]
114 span: SourceSpan,
115 },
116 #[error("invalid syntax")]
117 #[diagnostic()]
118 InvalidToken {
119 #[label("occurs here")]
120 span: SourceSpan,
121 },
122 #[error("invalid syntax: {message}")]
123 #[diagnostic()]
124 InvalidSyntax {
125 #[label("{message}")]
126 span: SourceSpan,
127 message: String,
128 },
129 #[error("invalid syntax")]
130 #[diagnostic(help("expected {}", expected.as_slice().join(", or ")))]
131 UnrecognizedToken {
132 #[label("found a {token} here")]
133 span: SourceSpan,
134 token: String,
135 expected: Vec<String>,
136 },
137 #[error("unexpected trailing tokens")]
138 #[diagnostic()]
139 ExtraToken {
140 #[label("{token} was found here, but was not expected")]
141 span: SourceSpan,
142 token: String,
143 },
144 #[error("unexpected end of file")]
145 #[diagnostic(help("expected {}", expected.as_slice().join(", or ")))]
146 UnrecognizedEof {
147 #[label("reached end of file here")]
148 span: SourceSpan,
149 expected: Vec<String>,
150 },
151 #[error("{error}")]
152 #[diagnostic(help(
153 "bare identifiers must be lowercase alphanumeric with '_', quoted identifiers can include any graphical character"
154 ))]
155 InvalidIdentifier {
156 #[source]
157 #[diagnostic(source)]
158 error: crate::ast::IdentError,
159 #[label]
160 span: SourceSpan,
161 },
162 #[error("unclosed quoted identifier")]
163 #[diagnostic()]
164 UnclosedQuote {
165 #[label("no match for quotation mark starting here")]
166 start: SourceSpan,
167 },
168 #[error("too many instructions in a single code block")]
169 #[diagnostic()]
170 CodeBlockTooBig {
171 #[label]
172 span: SourceSpan,
173 },
174 #[error("control-flow nesting depth exceeded")]
175 #[diagnostic(help("control-flow nesting exceeded the maximum depth of {max_depth}"))]
176 ControlFlowNestingDepthExceeded {
177 #[label("control-flow nesting exceeded the configured depth limit here")]
178 span: SourceSpan,
179 max_depth: usize,
180 },
181 #[error("constant expression nesting depth exceeded")]
182 #[diagnostic(help("constant expression nesting exceeded the maximum depth of {max_depth}"))]
183 ConstantExpressionNestingDepthExceeded {
184 #[label("constant expression nesting exceeded the configured depth limit here")]
185 span: SourceSpan,
186 max_depth: usize,
187 },
188 #[error("type expression nesting depth exceeded")]
189 #[diagnostic(help("type expression nesting exceeded the maximum depth of {max_depth}"))]
190 TypeExpressionNestingDepthExceeded {
191 #[label("type expression nesting exceeded the configured depth limit here")]
192 span: SourceSpan,
193 max_depth: usize,
194 },
195 #[error("invalid constant expression: division by zero")]
196 DivisionByZero {
197 #[label]
198 span: SourceSpan,
199 },
200 #[error("doc comment is too large")]
201 #[diagnostic(help("make sure it is less than u16::MAX bytes in length"))]
202 DocsTooLarge {
203 #[label]
204 span: SourceSpan,
205 },
206 #[error("invalid literal: {}", kind)]
207 #[diagnostic()]
208 InvalidLiteral {
209 #[label]
210 span: SourceSpan,
211 kind: LiteralErrorKind,
212 },
213 #[error("invalid literal: {}", kind)]
214 #[diagnostic()]
215 InvalidHexLiteral {
216 #[label]
217 span: SourceSpan,
218 kind: HexErrorKind,
219 },
220 #[error("invalid literal: {}", kind)]
221 #[diagnostic()]
222 InvalidBinaryLiteral {
223 #[label]
224 span: SourceSpan,
225 kind: BinErrorKind,
226 },
227 #[error("invalid MAST root literal")]
228 InvalidMastRoot {
229 #[label]
230 span: SourceSpan,
231 },
232 #[error("invalid library path: {}", message)]
233 InvalidLibraryPath {
234 #[label]
235 span: SourceSpan,
236 message: String,
237 },
238 #[error("invalid immediate: value must be in the range {}..{} (exclusive)", range.start, range.end)]
239 ImmediateOutOfRange {
240 #[label]
241 span: SourceSpan,
242 range: Range<usize>,
243 },
244 #[error("too many procedures in this module")]
245 #[diagnostic()]
246 ModuleTooLarge {
247 #[label]
248 span: SourceSpan,
249 },
250 #[error("too many re-exported procedures in this module")]
251 #[diagnostic()]
252 ModuleTooManyReexports {
253 #[label]
254 span: SourceSpan,
255 },
256 #[error(
257 "too many operands for `push`: tried to push {} elements, but only 16 can be pushed at one time",
258 count
259 )]
260 #[diagnostic()]
261 PushOverflow {
262 #[label]
263 span: SourceSpan,
264 count: usize,
265 },
266 #[error("expected a fully-qualified module path, e.g. `std::u64`")]
267 UnqualifiedImport {
268 #[label]
269 span: SourceSpan,
270 },
271 #[error(
272 "source-level digest re-exports are not supported; re-export a named item with `pub use {{item}} from module`"
273 )]
274 UnnamedReexportOfMastRoot {
275 #[label]
276 span: SourceSpan,
277 },
278 #[error("conflicting attributes for procedure definition")]
279 #[diagnostic()]
280 AttributeConflict {
281 #[label(
282 "conflict occurs because an attribute with the same name has already been defined"
283 )]
284 span: SourceSpan,
285 #[label("previously defined here")]
286 prev: SourceSpan,
287 },
288 #[error("conflicting key-value attributes for procedure definition")]
289 #[diagnostic()]
290 AttributeKeyValueConflict {
291 #[label(
292 "conflict occurs because a key with the same name has already been set in a previous declaration"
293 )]
294 span: SourceSpan,
295 #[label("previously defined here")]
296 prev: SourceSpan,
297 },
298 #[error("invalid Advice Map key")]
299 #[diagnostic()]
300 InvalidAdvMapKey {
301 #[label(
302 "an Advice Map key must be a word, either in 64-character hex format or in array-like format `[f0,f1,f2,f3]`"
303 )]
304 span: SourceSpan,
305 },
306 #[error("invalid slice constant")]
307 #[diagnostic()]
308 InvalidSliceConstant {
309 #[label("slices are only supported over word-sized constants")]
310 span: SourceSpan,
311 },
312 #[error("invalid slice: expected valid range")]
313 #[diagnostic()]
314 InvalidRange {
315 #[label("range used for the word constant slice is malformed: `{range:?}`")]
316 span: SourceSpan,
317 range: Range<usize>,
318 },
319 #[error("invalid slice: expected non-empty range")]
320 #[diagnostic()]
321 EmptySlice {
322 #[label("range used for the word constant slice is empty: `{range:?}`")]
323 span: SourceSpan,
324 range: Range<usize>,
325 },
326 #[error("unrecognized calling convention")]
327 #[diagnostic(help("expected one of: 'fast', 'C', 'wasm', 'canon-lift', or 'canon-lower'"))]
328 UnrecognizedCallConv {
329 #[label]
330 span: SourceSpan,
331 },
332 #[error("invalid struct annotation")]
333 #[diagnostic(help("expected one of: '@packed', '@packed(N)', '@transparent', or '@align(N)'"))]
334 InvalidStructAnnotation {
335 #[label]
336 span: SourceSpan,
337 },
338 #[error("invalid struct representation")]
339 #[diagnostic()]
340 InvalidStructRepr {
341 #[label("{message}")]
342 span: SourceSpan,
343 message: String,
344 },
345 #[error("deprecated instruction: `{instruction}` has been removed")]
346 #[diagnostic(help("use `{}` instead", replacement))]
347 DeprecatedInstruction {
348 #[label("this instruction is no longer supported")]
349 span: SourceSpan,
350 instruction: String,
351 replacement: String,
352 },
353 #[error("invalid procedure @locals attribute")]
354 #[diagnostic()]
355 InvalidLocalsAttr {
356 #[label("{message}")]
357 span: SourceSpan,
358 message: String,
359 },
360 #[error("invalid padding value for the `adv.push_mapvaln` instruction: {padding}")]
361 #[diagnostic(help("valid padding values are 0, 4, and 8"))]
362 InvalidPadValue {
363 #[label]
364 span: SourceSpan,
365 padding: u8,
366 },
367 #[error(
368 "invalid submodule declaration '{name}': could not find module sources at '{directory}/{basename}.masm' or '{directory}/{basename}/mod.masm'"
369 )]
370 UndefinedSubmodule {
371 name: crate::ast::Ident,
372 basename: alloc::boxed::Box<str>,
373 directory: miden_debug_types::Uri,
374 #[label]
375 span: SourceSpan,
376 #[source_code]
377 source_file: Option<Arc<miden_debug_types::SourceFile>>,
378 },
379 #[error(
380 "invalid submodule declaration '{name}': submodules must not have the same name as their parent"
381 )]
382 #[diagnostic(help("occurred while parsing {parent_module_uri}"))]
383 SelfReferentialSubmodule {
384 name: crate::ast::Ident,
385 parent_module_uri: miden_debug_types::Uri,
386 #[label(
387 "module source resolution rules require this declaration to resolve to the current source file"
388 )]
389 span: SourceSpan,
390 #[source_code]
391 source_file: Option<Arc<miden_debug_types::SourceFile>>,
392 },
393 #[error(
394 "conflicting submodule paths detected: '{name}' can be parsed from either '{first}' and '{second}', but not both"
395 )]
396 AmbiguousSubmoduleLocation {
397 name: crate::ast::Ident,
398 first: miden_debug_types::Uri,
399 second: miden_debug_types::Uri,
400 #[label]
401 span: SourceSpan,
402 #[source_code]
403 source_file: Option<Arc<miden_debug_types::SourceFile>>,
404 },
405 #[error(
406 "invalid submodule declaration '{name}': module source '{module_uri}' is already reachable through another submodule declaration"
407 )]
408 #[diagnostic(help("each module source file can only be owned by one module in a module tree"))]
409 DuplicateSubmoduleSource {
410 name: crate::ast::Ident,
411 module_uri: miden_debug_types::Uri,
412 #[label("this declaration resolves to an already visited module source")]
413 span: SourceSpan,
414 #[source_code]
415 source_file: Option<Arc<miden_debug_types::SourceFile>>,
416 },
417 #[error("conflicting attributes for procedure definition")]
418 #[diagnostic()]
419 CallConvAttributeConflict {
420 #[label(
421 "conflict occurs because @callconv conflicts with convention implied by other attribute"
422 )]
423 cc_span: SourceSpan,
424 #[label("this attribute implies @callconv(\"component-model\")")]
425 attr_span: SourceSpan,
426 },
427 #[error("conflicting attributes for procedure definition")]
428 #[diagnostic()]
429 ConflictingProtocolAbiAttribute {
430 #[label(
431 "this attribute specifies the protocol ABI of this procedure, but a different ABI was previously specified"
432 )]
433 span: SourceSpan,
434 #[label("this attribute already specifies the protocol ABI for this procedure")]
435 prev: SourceSpan,
436 },
437}
438
439impl ParsingError {
440 fn tag(&self) -> u8 {
441 unsafe { *<*const _>::from(self).cast::<u8>() }
448 }
449}
450
451impl Eq for ParsingError {}
452
453impl PartialEq for ParsingError {
454 fn eq(&self, other: &Self) -> bool {
455 match (self, other) {
456 (Self::Failed, Self::Failed) => true,
457 (Self::InvalidSyntax { message: l, .. }, Self::InvalidSyntax { message: r, .. }) => {
458 l == r
459 },
460 (Self::InvalidLiteral { kind: l, .. }, Self::InvalidLiteral { kind: r, .. }) => l == r,
461 (Self::InvalidHexLiteral { kind: l, .. }, Self::InvalidHexLiteral { kind: r, .. }) => {
462 l == r
463 },
464 (
465 Self::InvalidLibraryPath { message: l, .. },
466 Self::InvalidLibraryPath { message: r, .. },
467 ) => l == r,
468 (
469 Self::ImmediateOutOfRange { range: l, .. },
470 Self::ImmediateOutOfRange { range: r, .. },
471 ) => l == r,
472 (Self::PushOverflow { count: l, .. }, Self::PushOverflow { count: r, .. }) => l == r,
473 (
474 Self::UnrecognizedToken { token: ltok, expected: lexpect, .. },
475 Self::UnrecognizedToken { token: rtok, expected: rexpect, .. },
476 ) => ltok == rtok && lexpect == rexpect,
477 (Self::ExtraToken { token: ltok, .. }, Self::ExtraToken { token: rtok, .. }) => {
478 ltok == rtok
479 },
480 (
481 Self::UnrecognizedEof { expected: lexpect, .. },
482 Self::UnrecognizedEof { expected: rexpect, .. },
483 ) => lexpect == rexpect,
484 (x, y) => x.tag() == y.tag(),
485 }
486 }
487}